Fixed errors

This commit is contained in:
The3D 2020-09-14 15:09:16 +02:00
parent 6e92575ac2
commit bb4e1b5c4b
16 changed files with 189 additions and 164 deletions

View File

@ -326,7 +326,6 @@ interface ILendingPool {
uint256 currentStableDebt, uint256 currentStableDebt,
uint256 currentVariableDebt, uint256 currentVariableDebt,
uint256 principalStableDebt, uint256 principalStableDebt,
uint256 principalVariableDebt,
uint256 scaledVariableDebt, uint256 scaledVariableDebt,
uint256 stableBorrowRate, uint256 stableBorrowRate,
uint256 liquidityRate, uint256 liquidityRate,

View File

@ -49,10 +49,9 @@ contract LendingPool is VersionedInitializable, ILendingPool {
uint256 public constant UINT_MAX_VALUE = uint256(-1); uint256 public constant UINT_MAX_VALUE = uint256(-1);
uint256 public constant LENDINGPOOL_REVISION = 0x2; uint256 public constant LENDINGPOOL_REVISION = 0x2;
ILendingPoolAddressesProvider public immutable ADDRESSES_PROVIDER;
mapping(address => ReserveLogic.ReserveData) internal _reserves; mapping(address => ReserveLogic.ReserveData) internal _reserves;
mapping(address => UserConfiguration.Map) internal _usersConfig; mapping(address => UserConfiguration.Map) internal _usersConfig;
ILendingPoolAddressesProvider internal _addressesProvider;
address[] internal _reservesList; address[] internal _reservesList;
@ -63,7 +62,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
**/ **/
modifier onlyLendingPoolConfigurator { modifier onlyLendingPoolConfigurator {
require( require(
ADDRESSES_PROVIDER.getLendingPoolConfigurator() == msg.sender, _addressesProvider.getLendingPoolConfigurator() == msg.sender,
Errors.CALLER_NOT_LENDING_POOL_CONFIGURATOR Errors.CALLER_NOT_LENDING_POOL_CONFIGURATOR
); );
_; _;
@ -79,7 +78,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
* @param provider the address of the LendingPoolAddressesProvider registry * @param provider the address of the LendingPoolAddressesProvider registry
**/ **/
function initialize(ILendingPoolAddressesProvider provider) public initializer { function initialize(ILendingPoolAddressesProvider provider) public initializer {
ADDRESSES_PROVIDER = provider; _addressesProvider = provider;
} }
/** /**
@ -144,7 +143,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
_reserves, _reserves,
_usersConfig[msg.sender], _usersConfig[msg.sender],
_reservesList, _reservesList,
ADDRESSES_PROVIDER.getPriceOracle() _addressesProvider.getPriceOracle()
); );
reserve.updateState(); reserve.updateState();
@ -271,10 +270,10 @@ contract LendingPool is VersionedInitializable, ILendingPool {
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,
@ -348,7 +347,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
_reserves, _reserves,
_usersConfig[msg.sender], _usersConfig[msg.sender],
_reservesList, _reservesList,
ADDRESSES_PROVIDER.getPriceOracle() _addressesProvider.getPriceOracle()
); );
_usersConfig[msg.sender].setUsingAsCollateral(reserve.id, useAsCollateral); _usersConfig[msg.sender].setUsingAsCollateral(reserve.id, useAsCollateral);
@ -376,7 +375,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
uint256 purchaseAmount, uint256 purchaseAmount,
bool receiveAToken bool receiveAToken
) external override { ) external override {
address liquidationManager = ADDRESSES_PROVIDER.getLendingPoolLiquidationManager(); address liquidationManager = _addressesProvider.getLendingPoolLiquidationManager();
//solium-disable-next-line //solium-disable-next-line
(bool success, bytes memory result) = liquidationManager.delegatecall( (bool success, bytes memory result) = liquidationManager.delegatecall(
@ -435,7 +434,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
require(!_flashLiquidationLocked, Errors.REENTRANCY_NOT_ALLOWED); require(!_flashLiquidationLocked, Errors.REENTRANCY_NOT_ALLOWED);
_flashLiquidationLocked = true; _flashLiquidationLocked = true;
address liquidationManager = ADDRESSES_PROVIDER.getLendingPoolLiquidationManager(); address liquidationManager = _addressesProvider.getLendingPoolLiquidationManager();
//solium-disable-next-line //solium-disable-next-line
(bool success, bytes memory result) = liquidationManager.delegatecall( (bool success, bytes memory result) = liquidationManager.delegatecall(
@ -638,7 +637,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
_reserves, _reserves,
_usersConfig[user], _usersConfig[user],
_reservesList, _reservesList,
ADDRESSES_PROVIDER.getPriceOracle() _addressesProvider.getPriceOracle()
); );
availableBorrowsETH = GenericLogic.calculateAvailableBorrowsETH( availableBorrowsETH = GenericLogic.calculateAvailableBorrowsETH(
@ -657,7 +656,6 @@ contract LendingPool is VersionedInitializable, ILendingPool {
uint256 currentStableDebt, uint256 currentStableDebt,
uint256 currentVariableDebt, uint256 currentVariableDebt,
uint256 principalStableDebt, uint256 principalStableDebt,
uint256 variableBorrowIndex,
uint256 scaledVariableDebt, uint256 scaledVariableDebt,
uint256 stableBorrowRate, uint256 stableBorrowRate,
uint256 liquidityRate, uint256 liquidityRate,
@ -669,7 +667,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
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); scaledVariableDebt = IVariableDebtToken(reserve.variableDebtTokenAddress).scaledBalanceOf(user);
liquidityRate = reserve.currentLiquidityRate; liquidityRate = reserve.currentLiquidityRate;
stableBorrowRate = IStableDebtToken(reserve.stableDebtTokenAddress).getUserStableRate(user); stableBorrowRate = IStableDebtToken(reserve.stableDebtTokenAddress).getUserStableRate(user);
@ -677,7 +675,6 @@ contract LendingPool is VersionedInitializable, ILendingPool {
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) {
@ -784,7 +781,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
_reserves, _reserves,
_usersConfig[user], _usersConfig[user],
_reservesList, _reservesList,
ADDRESSES_PROVIDER.getPriceOracle() _addressesProvider.getPriceOracle()
); );
} }
@ -799,7 +796,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
* @dev returns the addresses provider * @dev returns the addresses provider
**/ **/
function getAddressesProvider() external view returns (ILendingPoolAddressesProvider) { function getAddressesProvider() external view returns (ILendingPoolAddressesProvider) {
return ADDRESSES_PROVIDER; return _addressesProvider;
} }
// internal functions // internal functions
@ -822,7 +819,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
ReserveLogic.ReserveData storage reserve = _reserves[vars.asset]; ReserveLogic.ReserveData storage reserve = _reserves[vars.asset];
UserConfiguration.Map storage userConfig = _usersConfig[msg.sender]; UserConfiguration.Map storage userConfig = _usersConfig[msg.sender];
address oracle = ADDRESSES_PROVIDER.getPriceOracle(); address oracle = _addressesProvider.getPriceOracle();
uint256 amountInETH = IPriceOracleGetter(oracle).getAssetPrice(vars.asset).mul(vars.amount).div( uint256 amountInETH = IPriceOracleGetter(oracle).getAssetPrice(vars.asset).mul(vars.amount).div(
10**reserve.configuration.getDecimals() 10**reserve.configuration.getDecimals()

View File

@ -234,8 +234,6 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
//update the principal reserve //update the principal reserve
principalReserve.updateState(); principalReserve.updateState();
principalReserve.updateInterestRates( principalReserve.updateInterestRates(
principal, principal,
principalReserve.aTokenAddress, principalReserve.aTokenAddress,
@ -244,29 +242,19 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
); );
if (vars.userVariableDebt >= vars.actualAmountToLiquidate) { if (vars.userVariableDebt >= vars.actualAmountToLiquidate) {
IVariableDebtToken(principalReserve.variableDebtTokenAddress).burn(
address tokenAddress = principalReserve.variableDebtTokenAddress;
_mintToReserveTreasury(principalReserve, user, tokenAddress);
IVariableDebtToken(tokenAddress).burn(
user, user,
vars.actualAmountToLiquidate vars.actualAmountToLiquidate,
principalReserve.variableBorrowIndex
); );
} else { } else {
IVariableDebtToken(principalReserve.variableDebtTokenAddress).burn(
address tokenAddress = principalReserve.variableDebtTokenAddress;
_mintToReserveTreasury(principalReserve, user, tokenAddress);
IVariableDebtToken(tokenAddress).burn(
user, user,
vars.userVariableDebt vars.userVariableDebt,
principalReserve.variableBorrowIndex
); );
tokenAddress = principalReserve.stableDebtTokenAddress; IStableDebtToken(principalReserve.stableDebtTokenAddress).burn(
IStableDebtToken(tokenAddress).burn(
user, user,
vars.actualAmountToLiquidate.sub(vars.userVariableDebt) vars.actualAmountToLiquidate.sub(vars.userVariableDebt)
); );
@ -288,7 +276,12 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
); );
//burn the equivalent amount of atoken //burn the equivalent amount of atoken
vars.collateralAtoken.burn(user, msg.sender, vars.maxCollateralToLiquidate, collateralReserve.liquidityIndex); vars.collateralAtoken.burn(
user,
msg.sender,
vars.maxCollateralToLiquidate,
collateralReserve.liquidityIndex
);
} }
//transfers the principal currency to the aToken //transfers the principal currency to the aToken
@ -408,7 +401,12 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
//updating collateral reserve indexes //updating collateral reserve indexes
collateralReserve.updateState(); collateralReserve.updateState();
vars.collateralAtoken.burn(user, receiver, vars.maxCollateralToLiquidate, collateralReserve.liquidityIndex); vars.collateralAtoken.burn(
user,
receiver,
vars.maxCollateralToLiquidate,
collateralReserve.liquidityIndex
);
if (vars.userCollateralBalance == vars.maxCollateralToLiquidate) { if (vars.userCollateralBalance == vars.maxCollateralToLiquidate) {
usersConfig[user].setUsingAsCollateral(collateralReserve.id, false); usersConfig[user].setUsingAsCollateral(collateralReserve.id, false);
@ -433,10 +431,15 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
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)
@ -530,19 +533,4 @@ contract LendingPoolLiquidationManager is VersionedInitializable {
} }
return (collateralAmount, principalAmountNeeded); return (collateralAmount, principalAmountNeeded);
} }
function _mintToReserveTreasury(ReserveLogic.ReserveData storage reserve, address user, address debtTokenAddress) internal {
uint256 currentPrincipalBalance = DebtTokenBase(debtTokenAddress).principalBalanceOf(user);
//calculating the interest accrued since the last borrow and minting the equivalent amount to the reserve factor
if(currentPrincipalBalance > 0){
uint256 balanceIncrease = IERC20(debtTokenAddress).balanceOf(user).sub(currentPrincipalBalance);
uint256 amountForReserveFactor = balanceIncrease.percentMul(reserve.configuration.getReserveFactor());
IAToken(reserve.aTokenAddress).mintToReserve(amountForReserveFactor);
}
}
} }

View File

@ -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

@ -6,11 +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 {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';
/** /**
@ -21,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;
/** /**
@ -63,14 +66,12 @@ library ReserveLogic {
//the current stable borrow rate. Expressed in ray //the current stable borrow rate. Expressed in ray
uint128 currentStableBorrowRate; uint128 currentStableBorrowRate;
uint40 lastUpdateTimestamp; uint40 lastUpdateTimestamp;
//tokens addresses //tokens addresses
address aTokenAddress; address aTokenAddress;
address stableDebtTokenAddress; address stableDebtTokenAddress;
address variableDebtTokenAddress; address variableDebtTokenAddress;
//address of the interest rate strategy //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;
} }
@ -127,8 +128,14 @@ library ReserveLogic {
* @param reserve the reserve object * @param reserve the reserve object
**/ **/
function updateState(ReserveData storage reserve) internal { function updateState(ReserveData storage reserve) internal {
_mintToTreasury(reserve); address stableDebtToken = reserve.stableDebtTokenAddress;
_updateIndexes(reserve); address variableDebtToken = reserve.variableDebtTokenAddress;
uint256 variableBorrowIndex = reserve.variableBorrowIndex;
uint256 liquidityIndex = reserve.liquidityIndex;
uint40 timestamp = reserve.lastUpdateTimestamp;
_mintToTreasury(reserve, stableDebtToken, variableDebtToken, liquidityIndex, variableBorrowIndex, timestamp);
_updateIndexes(reserve, variableDebtToken, liquidityIndex, variableBorrowIndex, timestamp);
} }
/** /**
@ -243,28 +250,70 @@ library ReserveLogic {
); );
} }
function _mintToTreasury(ReserveData storage reserve) internal { struct MintToTreasuryLocalVars {
uint256 currentTotalDebt;
address stableDebtToken = reserve.stableDebtTokenAddress; uint256 principalStableDebt;
address variableDebtToken = reserve.variableDebtTokenAddress; uint256 avgStableRate;
uint256 scaledVariableDebt;
uint256 cumulatedStableInterest;
uint256 variableDebtOnLastUpdate;
uint256 stableDebtOnLastUpdate;
uint256 totalInterestAccrued;
uint256 amountToMint;
uint256 reserveFactor;
}
uint256 currentVariableDebt = IERC20(variableDebtToken).totalSupply(); function _mintToTreasury(
uint256 currentStableDebt = IERC20(stableDebtToken).totalSupply(); ReserveData storage reserve,
address stableDebtToken,
address variableDebtToken,
uint256 liquidityIndex,
uint256 variableBorrowIndex,
uint40 lastUpdateTimestamp
) internal {
MintToTreasuryLocalVars memory vars;
uint256 principalStableDebt = IStableDebtToken(stableDebtToken).principalTotalSupply(); vars.reserveFactor = reserve.configuration.getReserveFactor();
uint256 scaledVariableDebt = IVariableDebtToken(variableDebtToken).scaledTotalSupply();
if(vars.reserveFactor == 0){
return;
}
vars.currentTotalDebt = IERC20(variableDebtToken).totalSupply().add(IERC20(stableDebtToken).totalSupply());
(vars.principalStableDebt, vars.avgStableRate) = IStableDebtToken(stableDebtToken)
.getPrincipalSupplyAndAvgRate();
vars.scaledVariableDebt = IVariableDebtToken(variableDebtToken).scaledTotalSupply();
vars.cumulatedStableInterest = MathUtils.calculateCompoundedInterest(
vars.avgStableRate,
lastUpdateTimestamp
);
vars.variableDebtOnLastUpdate = vars.scaledVariableDebt.rayMul(variableBorrowIndex);
vars.stableDebtOnLastUpdate = vars.principalStableDebt.rayMul(vars.cumulatedStableInterest);
vars.totalInterestAccrued =vars.currentTotalDebt.sub(vars.variableDebtOnLastUpdate.add(vars.stableDebtOnLastUpdate));
vars.amountToMint = vars.totalInterestAccrued.percentMul(vars.reserveFactor);
IAToken(reserve.aTokenAddress).mintToTreasury(vars.amountToMint, liquidityIndex);
} }
function _updateIndexes(ReserveData storage reserve) internal { function _updateIndexes(
ReserveData storage reserve,
address variableDebtToken,
uint256 liquidityIndex,
uint256 variableBorrowIndex,
uint40 lastUpdateTimestamp
) internal {
uint256 currentLiquidityRate = reserve.currentLiquidityRate; uint256 currentLiquidityRate = reserve.currentLiquidityRate;
//only cumulating if there is any income being produced //only cumulating if there is any income being produced
if (currentLiquidityRate > 0) { if (currentLiquidityRate > 0) {
uint40 lastUpdateTimestamp = reserve.lastUpdateTimestamp;
uint256 cumulatedLiquidityInterest = MathUtils.calculateLinearInterest( uint256 cumulatedLiquidityInterest = MathUtils.calculateLinearInterest(
currentLiquidityRate, currentLiquidityRate,
lastUpdateTimestamp lastUpdateTimestamp
@ -276,12 +325,12 @@ library ReserveLogic {
//as the liquidity rate might come only from stable rate loans, we need to ensure //as the liquidity rate might come only from stable rate loans, we need to ensure
//that there is actual variable debt before accumulating //that there is actual variable debt before accumulating
if (IERC20(reserve.variableDebtTokenAddress).totalSupply() > 0) { if (IERC20(variableDebtToken).totalSupply() > 0) {
uint256 cumulatedVariableBorrowInterest = MathUtils.calculateCompoundedInterest( uint256 cumulatedVariableBorrowInterest = MathUtils.calculateCompoundedInterest(
reserve.currentVariableBorrowRate, reserve.currentVariableBorrowRate,
lastUpdateTimestamp lastUpdateTimestamp
); );
index = cumulatedVariableBorrowInterest.rayMul(reserve.variableBorrowIndex); index = cumulatedVariableBorrowInterest.rayMul(variableBorrowIndex);
require(index < (1 << 128), Errors.VARIABLE_BORROW_INDEX_OVERFLOW); require(index < (1 << 128), Errors.VARIABLE_BORROW_INDEX_OVERFLOW);
reserve.variableBorrowIndex = uint128(index); reserve.variableBorrowIndex = uint128(index);
} }

View File

@ -105,8 +105,7 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
emit Mint(user, amount, index); emit Mint(user, amount, index);
} }
function mintToReserve(uint256 amount) external override onlyLendingPool { function mintToTreasury(uint256 amount, uint256 index) external override onlyLendingPool {
uint256 index = _pool.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS);
_mint(RESERVE_TREASURY_ADDRESS, amount.div(index)); _mint(RESERVE_TREASURY_ADDRESS, amount.div(index));
} }

View File

@ -68,7 +68,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;
@ -125,7 +125,6 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
//solium-disable-next-line //solium-disable-next-line
_totalSupplyTimestamp = _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 = _avgStableRate
.rayMul(vars.supplyBeforeMint.wadToRay()) .rayMul(vars.supplyBeforeMint.wadToRay())
@ -185,15 +184,22 @@ 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 * @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 * @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 * @return The previous principal balance, the new principal balance, the balance increase
* and the new user index * and the new user index
**/ **/
function _calculateBalanceIncrease(address user) internal view returns (uint256, uint256, uint256) { function _calculateBalanceIncrease(address user)
uint256 previousPrincipalBalance = principalBalanceOf(user); internal
view
returns (
uint256,
uint256,
uint256
)
{
uint256 previousPrincipalBalance = super.balanceOf(user);
if (previousPrincipalBalance == 0) { if (previousPrincipalBalance == 0) {
return (0, 0, 0); return (0, 0, 0);
@ -209,11 +215,11 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
); );
} }
function principalTotalSupply() public override view returns(uint256) { function getPrincipalSupplyAndAvgRate() public override view returns (uint256, uint256) {
return super.totalSupply(); return (super.totalSupply(), _avgStableRate);
} }
function totalSupply() public override view returns(uint256) { function totalSupply() public override view returns (uint256) {
uint256 principalSupply = super.totalSupply(); uint256 principalSupply = super.totalSupply();
if (principalSupply == 0) { if (principalSupply == 0) {
return 0; return 0;
@ -225,4 +231,11 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase {
return principalSupply.rayMul(cumulatedInterest); return principalSupply.rayMul(cumulatedInterest);
} }
/**
* @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) external virtual override view returns (uint256) {
return super.balanceOf(user);
}
} }

View File

@ -39,7 +39,7 @@ 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 scaledBalance = super.principalBalanceOf(user); uint256 scaledBalance = super.balanceOf(user);
if (scaledBalance == 0) { if (scaledBalance == 0) {
return 0; return 0;

View File

@ -64,14 +64,6 @@ abstract contract DebtTokenBase is ERC20, 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 virtual 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.

View File

@ -62,12 +62,11 @@ interface IAToken is IERC20 {
function mint(address user, uint256 amount, uint256 index) external; function mint(address user, uint256 amount, uint256 index) external;
/** /**
* @dev mints aTokens to reserve, based on the reserveFactor value * @dev mints aTokens to the reserve treasury
* only lending pools can call this function * @param amount the amount to mint
* @param amount the amount of tokens to mint * @param index the liquidity index of the reserve
*/ **/
function mintToReserve(uint256 amount) external; function mintToTreasury(uint256 amount, uint256 index) external;
/** /**
* @dev transfers tokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken * @dev transfers tokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken
@ -104,6 +103,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

@ -86,7 +86,14 @@ interface IStableDebtToken {
function getUserLastUpdated(address user) external view returns (uint40); function getUserLastUpdated(address user) external view returns (uint40);
/** /**
* @dev returns the principal total supply * @dev returns the principal total supply and the average stable rate
**/ **/
function principalTotalSupply() external view returns (uint40); function getPrincipalSupplyAndAvgRate() 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

@ -273,19 +273,16 @@ export const calcExpectedReserveDataAfterBorrow = (
const amountBorrowedBN = new BigNumber(amountBorrowed); const amountBorrowedBN = new BigNumber(amountBorrowed);
const userStableBorrowBalance = calcExpectedStableDebtTokenBalance( const userStableDebt = calcExpectedStableDebtTokenBalance(userDataBeforeAction, txTimestamp);
userDataBeforeAction,
txTimestamp
);
const userVariableBorrowBalance = calcExpectedVariableDebtTokenBalance( const userVariableDebt = calcExpectedVariableDebtTokenBalance(
reserveDataBeforeAction, reserveDataBeforeAction,
userDataBeforeAction, userDataBeforeAction,
txTimestamp txTimestamp
); );
if (borrowRateMode == RateMode.Stable) { if (borrowRateMode == RateMode.Stable) {
const debtAccrued = userStableBorrowBalance.minus(userDataBeforeAction.principalStableDebt); const debtAccrued = userStableDebt.minus(userDataBeforeAction.principalStableDebt);
expectedReserveData.totalLiquidity = reserveDataBeforeAction.totalLiquidity.plus(debtAccrued); expectedReserveData.totalLiquidity = reserveDataBeforeAction.totalLiquidity.plus(debtAccrued);
@ -301,7 +298,11 @@ export const calcExpectedReserveDataAfterBorrow = (
); );
expectedReserveData.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable; expectedReserveData.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable;
} else { } else {
const debtAccrued = userVariableBorrowBalance.minus(userDataBeforeAction.principalVariableDebt); const variableDebtBefore = userDataBeforeAction.scaledVariableDebt.rayMul(
reserveDataBeforeAction.variableBorrowIndex
);
const debtAccrued = userVariableDebt.minus(variableDebtBefore);
expectedReserveData.totalLiquidity = reserveDataBeforeAction.totalLiquidity.plus(debtAccrued); expectedReserveData.totalLiquidity = reserveDataBeforeAction.totalLiquidity.plus(debtAccrued);
expectedReserveData.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable expectedReserveData.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable
.plus(amountBorrowedBN) .plus(amountBorrowedBN)
@ -362,12 +363,9 @@ export const calcExpectedReserveDataAfterRepay = (
let amountRepaidBN = new BigNumber(amountRepaid); let amountRepaidBN = new BigNumber(amountRepaid);
const userStableBorrowBalance = calcExpectedStableDebtTokenBalance( const userStableDebt = calcExpectedStableDebtTokenBalance(userDataBeforeAction, txTimestamp);
userDataBeforeAction,
txTimestamp
);
const userVariableBorrowBalance = calcExpectedVariableDebtTokenBalance( const userVariableDebt = calcExpectedVariableDebtTokenBalance(
reserveDataBeforeAction, reserveDataBeforeAction,
userDataBeforeAction, userDataBeforeAction,
txTimestamp txTimestamp
@ -376,14 +374,14 @@ export const calcExpectedReserveDataAfterRepay = (
//if amount repaid = MAX_UINT_AMOUNT, user is repaying everything //if amount repaid = MAX_UINT_AMOUNT, user is repaying everything
if (amountRepaidBN.abs().eq(MAX_UINT_AMOUNT)) { if (amountRepaidBN.abs().eq(MAX_UINT_AMOUNT)) {
if (borrowRateMode == RateMode.Stable) { if (borrowRateMode == RateMode.Stable) {
amountRepaidBN = userStableBorrowBalance; amountRepaidBN = userStableDebt;
} else { } else {
amountRepaidBN = userVariableBorrowBalance; amountRepaidBN = userVariableDebt;
} }
} }
if (borrowRateMode == RateMode.Stable) { if (borrowRateMode == RateMode.Stable) {
const debtAccrued = userStableBorrowBalance.minus(userDataBeforeAction.principalStableDebt); const debtAccrued = userStableDebt.minus(userDataBeforeAction.principalStableDebt);
expectedReserveData.totalLiquidity = reserveDataBeforeAction.totalLiquidity.plus(debtAccrued); expectedReserveData.totalLiquidity = reserveDataBeforeAction.totalLiquidity.plus(debtAccrued);
@ -399,7 +397,11 @@ export const calcExpectedReserveDataAfterRepay = (
); );
expectedReserveData.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable; expectedReserveData.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable;
} else { } else {
const debtAccrued = userVariableBorrowBalance.minus(userDataBeforeAction.principalVariableDebt); const variableDebtBefore = userDataBeforeAction.scaledVariableDebt.rayMul(
reserveDataBeforeAction.variableBorrowIndex
);
const debtAccrued = userVariableDebt.minus(variableDebtBefore);
expectedReserveData.totalLiquidity = reserveDataBeforeAction.totalLiquidity.plus(debtAccrued); expectedReserveData.totalLiquidity = reserveDataBeforeAction.totalLiquidity.plus(debtAccrued);
@ -477,7 +479,7 @@ export const calcExpectedUserDataAfterBorrow = (
const debtAccrued = currentStableDebt.minus(userDataBeforeAction.principalStableDebt); const debtAccrued = currentStableDebt.minus(userDataBeforeAction.principalStableDebt);
expectedUserData.principalStableDebt = currentStableDebt.plus(amountBorrowed); expectedUserData.principalStableDebt = currentStableDebt.plus(amountBorrowed);
expectedUserData.principalVariableDebt = userDataBeforeAction.principalVariableDebt; expectedUserData.scaledVariableDebt = userDataBeforeAction.scaledVariableDebt;
expectedUserData.stableBorrowRate = calcExpectedUserStableRate( expectedUserData.stableBorrowRate = calcExpectedUserStableRate(
userDataBeforeAction.principalStableDebt.plus(debtAccrued), userDataBeforeAction.principalStableDebt.plus(debtAccrued),
@ -510,8 +512,8 @@ export const calcExpectedUserDataAfterBorrow = (
expectedDataAfterAction, expectedDataAfterAction,
{ {
...userDataBeforeAction, ...userDataBeforeAction,
currentVariableDebt: expectedUserData.principalVariableDebt, currentVariableDebt: expectedUserData.scaledVariableDebt.rayMul(reserveDataBeforeAction.variableBorrowIndex),
principalVariableDebt: expectedUserData.principalVariableDebt, scaledVariableDebt: expectedUserData.scaledVariableDebt,
variableBorrowIndex: variableBorrowIndex:
interestRateMode == RateMode.Variable interestRateMode == RateMode.Variable
? expectedDataAfterAction.variableBorrowIndex ? expectedDataAfterAction.variableBorrowIndex
@ -520,7 +522,7 @@ export const calcExpectedUserDataAfterBorrow = (
currentTimestamp currentTimestamp
); );
if (expectedUserData.principalVariableDebt.eq(0)) { if (expectedUserData.scaledVariableDebt.eq(0)) {
expectedUserData.variableBorrowIndex = new BigNumber(0); expectedUserData.variableBorrowIndex = new BigNumber(0);
} else { } else {
expectedUserData.variableBorrowIndex = expectedUserData.variableBorrowIndex =
@ -539,7 +541,7 @@ export const calcExpectedUserDataAfterBorrow = (
currentTimestamp currentTimestamp
); );
expectedUserData.scaledATokenBalance = userDataBeforeAction.scaledATokenBalance; expectedUserData.scaledATokenBalance = userDataBeforeAction.scaledATokenBalance;
expectedUserData.walletBalance = userDataBeforeAction.walletBalance.plus(amountBorrowed); expectedUserData.walletBalance = userDataBeforeAction.walletBalance.plus(amountBorrowed);
return expectedUserData; return expectedUserData;
@ -623,7 +625,7 @@ export const calcExpectedUserDataAfterRepay = (
txTimestamp txTimestamp
); );
expectedUserData.scaledATokenBalance = userDataBeforeAction.scaledATokenBalance; expectedUserData.scaledATokenBalance = userDataBeforeAction.scaledATokenBalance;
if (user === onBehalfOf) { if (user === onBehalfOf) {
expectedUserData.walletBalance = userDataBeforeAction.walletBalance.minus(totalRepaid); expectedUserData.walletBalance = userDataBeforeAction.walletBalance.minus(totalRepaid);
} else { } else {
@ -657,51 +659,52 @@ export const calcExpectedReserveDataAfterSwapRateMode = (
expectedReserveData.address = reserveDataBeforeAction.address; expectedReserveData.address = reserveDataBeforeAction.address;
const variableBorrowBalance = calcExpectedVariableDebtTokenBalance( const variableDebt = calcExpectedVariableDebtTokenBalance(
reserveDataBeforeAction, reserveDataBeforeAction,
userDataBeforeAction, userDataBeforeAction,
txTimestamp txTimestamp
); );
const stableBorrowBalance = calcExpectedStableDebtTokenBalance(userDataBeforeAction, txTimestamp); const stableDebt = calcExpectedStableDebtTokenBalance(userDataBeforeAction, txTimestamp);
expectedReserveData.availableLiquidity = reserveDataBeforeAction.availableLiquidity; expectedReserveData.availableLiquidity = reserveDataBeforeAction.availableLiquidity;
if (rateMode === RateMode.Stable) { if (rateMode === RateMode.Stable) {
//swap user stable debt to variable //swap user stable debt to variable
const debtAccrued = stableBorrowBalance.minus(userDataBeforeAction.principalStableDebt); const debtAccrued = stableDebt.minus(userDataBeforeAction.principalStableDebt);
expectedReserveData.totalLiquidity = reserveDataBeforeAction.totalLiquidity.plus(debtAccrued); expectedReserveData.totalLiquidity = reserveDataBeforeAction.totalLiquidity.plus(debtAccrued);
expectedReserveData.averageStableBorrowRate = calcExpectedAverageStableBorrowRate( expectedReserveData.averageStableBorrowRate = calcExpectedAverageStableBorrowRate(
reserveDataBeforeAction.averageStableBorrowRate, reserveDataBeforeAction.averageStableBorrowRate,
reserveDataBeforeAction.totalBorrowsStable.plus(debtAccrued), reserveDataBeforeAction.totalBorrowsStable.plus(debtAccrued),
stableBorrowBalance.negated(), stableDebt.negated(),
userDataBeforeAction.stableBorrowRate userDataBeforeAction.stableBorrowRate
); );
expectedReserveData.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable.plus( expectedReserveData.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable.plus(
stableBorrowBalance stableDebt
); );
expectedReserveData.totalBorrowsStable = reserveDataBeforeAction.totalBorrowsStable.minus( expectedReserveData.totalBorrowsStable = reserveDataBeforeAction.totalBorrowsStable.minus(
userDataBeforeAction.principalStableDebt userDataBeforeAction.principalStableDebt
); );
} else { } else {
const debtAccrued = variableBorrowBalance.minus(userDataBeforeAction.principalVariableDebt); const totalDebtBefore = userDataBeforeAction.scaledVariableDebt.rayMul(reserveDataBeforeAction.variableBorrowIndex);
const debtAccrued = variableDebt.minus(totalDebtBefore);
expectedReserveData.totalLiquidity = reserveDataBeforeAction.totalLiquidity.plus(debtAccrued); expectedReserveData.totalLiquidity = reserveDataBeforeAction.totalLiquidity.plus(debtAccrued);
expectedReserveData.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable.minus(
userDataBeforeAction.principalVariableDebt expectedReserveData.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable;
);
expectedReserveData.totalBorrowsStable = reserveDataBeforeAction.totalBorrowsStable.plus( expectedReserveData.totalBorrowsStable = reserveDataBeforeAction.totalBorrowsStable.plus(
variableBorrowBalance variableDebt
); );
expectedReserveData.averageStableBorrowRate = calcExpectedAverageStableBorrowRate( expectedReserveData.averageStableBorrowRate = calcExpectedAverageStableBorrowRate(
reserveDataBeforeAction.averageStableBorrowRate, reserveDataBeforeAction.averageStableBorrowRate,
reserveDataBeforeAction.totalBorrowsStable, reserveDataBeforeAction.totalBorrowsStable,
variableBorrowBalance, variableDebt,
reserveDataBeforeAction.stableBorrowRate reserveDataBeforeAction.stableBorrowRate
); );
} }
@ -926,9 +929,7 @@ const calcExpectedATokenBalance = (
) => { ) => {
const index = calcExpectedReserveNormalizedIncome(reserveDataBeforeAction, currentTimestamp); const index = calcExpectedReserveNormalizedIncome(reserveDataBeforeAction, currentTimestamp);
const { const {scaledATokenBalance: scaledBalanceBeforeAction} = userDataBeforeAction;
scaledATokenBalance: scaledBalanceBeforeAction,
} = userDataBeforeAction;
return scaledBalanceBeforeAction.rayMul(index); return scaledBalanceBeforeAction.rayMul(index);
}; };
@ -969,8 +970,7 @@ export const calcExpectedVariableDebtTokenBalance = (
) => { ) => {
const debt = calcExpectedReserveNormalizedDebt(reserveDataBeforeAction, currentTimestamp); const debt = calcExpectedReserveNormalizedDebt(reserveDataBeforeAction, currentTimestamp);
const { scaledVariableDebt } = userDataBeforeAction; const {scaledVariableDebt} = userDataBeforeAction;
return scaledVariableDebt.rayMul(debt); return scaledVariableDebt.rayMul(debt);
}; };

View File

@ -79,7 +79,6 @@ 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()), scaledVariableDebt: new BigNumber(userData.scaledVariableDebt.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()),

View File

@ -6,7 +6,6 @@ export interface UserReserveData {
currentStableDebt: BigNumber; currentStableDebt: BigNumber;
currentVariableDebt: BigNumber; currentVariableDebt: BigNumber;
principalStableDebt: BigNumber; principalStableDebt: BigNumber;
principalVariableDebt: BigNumber;
scaledVariableDebt: BigNumber; scaledVariableDebt: BigNumber;
liquidityRate: BigNumber; liquidityRate: BigNumber;
stableBorrowRate: BigNumber; stableBorrowRate: BigNumber;

View File

@ -10,7 +10,7 @@ import {executeStory} from './helpers/scenario-engine';
const scenarioFolder = './test/helpers/scenarios/'; const scenarioFolder = './test/helpers/scenarios/';
const selectedScenarios: string[] = ['']; const selectedScenarios: string[] = ['deposit.json'];
fs.readdirSync(scenarioFolder).forEach((file) => { fs.readdirSync(scenarioFolder).forEach((file) => {
if (selectedScenarios.length > 0 && !selectedScenarios.includes(file)) return; if (selectedScenarios.length > 0 && !selectedScenarios.includes(file)) return;

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