diff --git a/contracts/interfaces/ILendingPool.sol b/contracts/interfaces/ILendingPool.sol index c13fe2e5..4b3c8385 100644 --- a/contracts/interfaces/ILendingPool.sol +++ b/contracts/interfaces/ILendingPool.sol @@ -326,7 +326,6 @@ interface ILendingPool { uint256 currentStableDebt, uint256 currentVariableDebt, uint256 principalStableDebt, - uint256 principalVariableDebt, uint256 scaledVariableDebt, uint256 stableBorrowRate, uint256 liquidityRate, diff --git a/contracts/lendingpool/LendingPool.sol b/contracts/lendingpool/LendingPool.sol index 79940ef2..93716948 100644 --- a/contracts/lendingpool/LendingPool.sol +++ b/contracts/lendingpool/LendingPool.sol @@ -49,10 +49,9 @@ contract LendingPool is VersionedInitializable, ILendingPool { uint256 public constant UINT_MAX_VALUE = uint256(-1); uint256 public constant LENDINGPOOL_REVISION = 0x2; - ILendingPoolAddressesProvider public immutable ADDRESSES_PROVIDER; - mapping(address => ReserveLogic.ReserveData) internal _reserves; mapping(address => UserConfiguration.Map) internal _usersConfig; + ILendingPoolAddressesProvider internal _addressesProvider; address[] internal _reservesList; @@ -63,7 +62,7 @@ contract LendingPool is VersionedInitializable, ILendingPool { **/ modifier onlyLendingPoolConfigurator { require( - ADDRESSES_PROVIDER.getLendingPoolConfigurator() == msg.sender, + _addressesProvider.getLendingPoolConfigurator() == msg.sender, Errors.CALLER_NOT_LENDING_POOL_CONFIGURATOR ); _; @@ -79,7 +78,7 @@ contract LendingPool is VersionedInitializable, ILendingPool { * @param provider the address of the LendingPoolAddressesProvider registry **/ function initialize(ILendingPoolAddressesProvider provider) public initializer { - ADDRESSES_PROVIDER = provider; + _addressesProvider = provider; } /** @@ -144,7 +143,7 @@ contract LendingPool is VersionedInitializable, ILendingPool { _reserves, _usersConfig[msg.sender], _reservesList, - ADDRESSES_PROVIDER.getPriceOracle() + _addressesProvider.getPriceOracle() ); reserve.updateState(); @@ -271,10 +270,10 @@ contract LendingPool is VersionedInitializable, ILendingPool { if (interestRateMode == ReserveLogic.InterestRateMode.STABLE) { //burn stable rate tokens, mint variable rate tokens IStableDebtToken(reserve.stableDebtTokenAddress).burn(msg.sender, stableDebt); - IVariableDebtToken(reserve.variableDebtTokenAddress).mint(msg.sender, stableDebt); + IVariableDebtToken(reserve.variableDebtTokenAddress).mint(msg.sender, stableDebt, reserve.variableBorrowIndex); } else { //do the opposite - IVariableDebtToken(reserve.variableDebtTokenAddress).burn(msg.sender, variableDebt); + IVariableDebtToken(reserve.variableDebtTokenAddress).burn(msg.sender, variableDebt, reserve.variableBorrowIndex); IStableDebtToken(reserve.stableDebtTokenAddress).mint( msg.sender, variableDebt, @@ -348,7 +347,7 @@ contract LendingPool is VersionedInitializable, ILendingPool { _reserves, _usersConfig[msg.sender], _reservesList, - ADDRESSES_PROVIDER.getPriceOracle() + _addressesProvider.getPriceOracle() ); _usersConfig[msg.sender].setUsingAsCollateral(reserve.id, useAsCollateral); @@ -376,7 +375,7 @@ contract LendingPool is VersionedInitializable, ILendingPool { uint256 purchaseAmount, bool receiveAToken ) external override { - address liquidationManager = ADDRESSES_PROVIDER.getLendingPoolLiquidationManager(); + address liquidationManager = _addressesProvider.getLendingPoolLiquidationManager(); //solium-disable-next-line (bool success, bytes memory result) = liquidationManager.delegatecall( @@ -435,7 +434,7 @@ contract LendingPool is VersionedInitializable, ILendingPool { require(!_flashLiquidationLocked, Errors.REENTRANCY_NOT_ALLOWED); _flashLiquidationLocked = true; - address liquidationManager = ADDRESSES_PROVIDER.getLendingPoolLiquidationManager(); + address liquidationManager = _addressesProvider.getLendingPoolLiquidationManager(); //solium-disable-next-line (bool success, bytes memory result) = liquidationManager.delegatecall( @@ -638,7 +637,7 @@ contract LendingPool is VersionedInitializable, ILendingPool { _reserves, _usersConfig[user], _reservesList, - ADDRESSES_PROVIDER.getPriceOracle() + _addressesProvider.getPriceOracle() ); availableBorrowsETH = GenericLogic.calculateAvailableBorrowsETH( @@ -657,7 +656,6 @@ contract LendingPool is VersionedInitializable, ILendingPool { uint256 currentStableDebt, uint256 currentVariableDebt, uint256 principalStableDebt, - uint256 variableBorrowIndex, uint256 scaledVariableDebt, uint256 stableBorrowRate, uint256 liquidityRate, @@ -669,7 +667,7 @@ contract LendingPool is VersionedInitializable, ILendingPool { currentATokenBalance = IERC20(reserve.aTokenAddress).balanceOf(user); (currentStableDebt, currentVariableDebt) = Helpers.getUserCurrentDebt(user, reserve); - (principalStableDebt, principalVariableDebt) = Helpers.getUserPrincipalDebt(user, reserve); + principalStableDebt = IStableDebtToken(reserve.stableDebtTokenAddress).principalBalanceOf(user); scaledVariableDebt = IVariableDebtToken(reserve.variableDebtTokenAddress).scaledBalanceOf(user); liquidityRate = reserve.currentLiquidityRate; stableBorrowRate = IStableDebtToken(reserve.stableDebtTokenAddress).getUserStableRate(user); @@ -677,7 +675,6 @@ contract LendingPool is VersionedInitializable, ILendingPool { user ); usageAsCollateralEnabled = _usersConfig[user].isUsingAsCollateral(reserve.id); - variableBorrowIndex = IVariableDebtToken(reserve.variableDebtTokenAddress).getUserIndex(user); } function getReserves() external override view returns (address[] memory) { @@ -784,7 +781,7 @@ contract LendingPool is VersionedInitializable, ILendingPool { _reserves, _usersConfig[user], _reservesList, - ADDRESSES_PROVIDER.getPriceOracle() + _addressesProvider.getPriceOracle() ); } @@ -799,7 +796,7 @@ contract LendingPool is VersionedInitializable, ILendingPool { * @dev returns the addresses provider **/ function getAddressesProvider() external view returns (ILendingPoolAddressesProvider) { - return ADDRESSES_PROVIDER; + return _addressesProvider; } // internal functions @@ -822,7 +819,7 @@ contract LendingPool is VersionedInitializable, ILendingPool { ReserveLogic.ReserveData storage reserve = _reserves[vars.asset]; 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( 10**reserve.configuration.getDecimals() diff --git a/contracts/lendingpool/LendingPoolLiquidationManager.sol b/contracts/lendingpool/LendingPoolLiquidationManager.sol index 848aaffb..8a018489 100644 --- a/contracts/lendingpool/LendingPoolLiquidationManager.sol +++ b/contracts/lendingpool/LendingPoolLiquidationManager.sol @@ -234,8 +234,6 @@ contract LendingPoolLiquidationManager is VersionedInitializable { //update the principal reserve principalReserve.updateState(); - - principalReserve.updateInterestRates( principal, principalReserve.aTokenAddress, @@ -244,29 +242,19 @@ contract LendingPoolLiquidationManager is VersionedInitializable { ); if (vars.userVariableDebt >= vars.actualAmountToLiquidate) { - - address tokenAddress = principalReserve.variableDebtTokenAddress; - - _mintToReserveTreasury(principalReserve, user, tokenAddress); - - IVariableDebtToken(tokenAddress).burn( + IVariableDebtToken(principalReserve.variableDebtTokenAddress).burn( user, - vars.actualAmountToLiquidate + vars.actualAmountToLiquidate, + principalReserve.variableBorrowIndex ); } else { - - address tokenAddress = principalReserve.variableDebtTokenAddress; - - _mintToReserveTreasury(principalReserve, user, tokenAddress); - - IVariableDebtToken(tokenAddress).burn( + IVariableDebtToken(principalReserve.variableDebtTokenAddress).burn( user, - vars.userVariableDebt + vars.userVariableDebt, + principalReserve.variableBorrowIndex ); - tokenAddress = principalReserve.stableDebtTokenAddress; - - IStableDebtToken(tokenAddress).burn( + IStableDebtToken(principalReserve.stableDebtTokenAddress).burn( user, vars.actualAmountToLiquidate.sub(vars.userVariableDebt) ); @@ -288,7 +276,12 @@ contract LendingPoolLiquidationManager is VersionedInitializable { ); //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 @@ -408,7 +401,12 @@ contract LendingPoolLiquidationManager is VersionedInitializable { //updating collateral reserve indexes 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) { usersConfig[user].setUsingAsCollateral(collateralReserve.id, false); @@ -433,10 +431,15 @@ contract LendingPoolLiquidationManager is VersionedInitializable { if (vars.userVariableDebt >= vars.actualAmountToLiquidate) { IVariableDebtToken(debtReserve.variableDebtTokenAddress).burn( user, - vars.actualAmountToLiquidate + vars.actualAmountToLiquidate, + debtReserve.variableBorrowIndex ); } else { - IVariableDebtToken(debtReserve.variableDebtTokenAddress).burn(user, vars.userVariableDebt); + IVariableDebtToken(debtReserve.variableDebtTokenAddress).burn( + user, + vars.userVariableDebt, + debtReserve.variableBorrowIndex + ); IStableDebtToken(debtReserve.stableDebtTokenAddress).burn( user, vars.actualAmountToLiquidate.sub(vars.userVariableDebt) @@ -530,19 +533,4 @@ contract LendingPoolLiquidationManager is VersionedInitializable { } return (collateralAmount, principalAmountNeeded); } - - function _mintToReserveTreasury(ReserveLogic.ReserveData storage reserve, address user, address debtTokenAddress) internal { - - uint256 currentPrincipalBalance = DebtTokenBase(debtTokenAddress).principalBalanceOf(user); - //calculating the interest accrued since the last borrow and minting the equivalent amount to the reserve factor - if(currentPrincipalBalance > 0){ - - uint256 balanceIncrease = IERC20(debtTokenAddress).balanceOf(user).sub(currentPrincipalBalance); - - uint256 amountForReserveFactor = balanceIncrease.percentMul(reserve.configuration.getReserveFactor()); - - IAToken(reserve.aTokenAddress).mintToReserve(amountForReserveFactor); - } - - } } diff --git a/contracts/libraries/helpers/Helpers.sol b/contracts/libraries/helpers/Helpers.sol index dda22eb4..e1d65502 100644 --- a/contracts/libraries/helpers/Helpers.sol +++ b/contracts/libraries/helpers/Helpers.sol @@ -26,21 +26,4 @@ library Helpers { DebtTokenBase(reserve.variableDebtTokenAddress).balanceOf(user) ); } - - /** - * @dev fetches the user principal stable and variable debt balances - * @param user the user - * @param reserve the reserve object - * @return the stable and variable debt balance - **/ - function getUserPrincipalDebt(address user, ReserveLogic.ReserveData storage reserve) - internal - view - returns (uint256, uint256) - { - return ( - DebtTokenBase(reserve.stableDebtTokenAddress).principalBalanceOf(user), - DebtTokenBase(reserve.variableDebtTokenAddress).principalBalanceOf(user) - ); - } } diff --git a/contracts/libraries/logic/ReserveLogic.sol b/contracts/libraries/logic/ReserveLogic.sol index 0530e650..b287094a 100644 --- a/contracts/libraries/logic/ReserveLogic.sol +++ b/contracts/libraries/logic/ReserveLogic.sol @@ -6,11 +6,13 @@ import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import {MathUtils} from '../math/MathUtils.sol'; import {IPriceOracleGetter} from '../../interfaces/IPriceOracleGetter.sol'; import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/SafeERC20.sol'; +import {IAToken} from '../../tokenization/interfaces/IAToken.sol'; import {IStableDebtToken} from '../../tokenization/interfaces/IStableDebtToken.sol'; import {IVariableDebtToken} from '../../tokenization/interfaces/IVariableDebtToken.sol'; import {ReserveConfiguration} from '../configuration/ReserveConfiguration.sol'; import {IReserveInterestRateStrategy} from '../../interfaces/IReserveInterestRateStrategy.sol'; import {WadRayMath} from '../math/WadRayMath.sol'; +import {PercentageMath} from '../math/PercentageMath.sol'; import {Errors} from '../helpers/Errors.sol'; /** @@ -21,6 +23,7 @@ import {Errors} from '../helpers/Errors.sol'; library ReserveLogic { using SafeMath for uint256; using WadRayMath for uint256; + using PercentageMath for uint256; using SafeERC20 for IERC20; /** @@ -63,14 +66,12 @@ library ReserveLogic { //the current stable borrow rate. Expressed in ray uint128 currentStableBorrowRate; uint40 lastUpdateTimestamp; - //tokens addresses address aTokenAddress; address stableDebtTokenAddress; address variableDebtTokenAddress; //address of the interest rate strategy address interestRateStrategyAddress; - //the id of the reserve. Represents the position in the list of the active reserves uint8 id; } @@ -127,8 +128,14 @@ library ReserveLogic { * @param reserve the reserve object **/ function updateState(ReserveData storage reserve) internal { - _mintToTreasury(reserve); - _updateIndexes(reserve); + address stableDebtToken = reserve.stableDebtTokenAddress; + 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 { - - address stableDebtToken = reserve.stableDebtTokenAddress; - address variableDebtToken = reserve.variableDebtTokenAddress; + struct MintToTreasuryLocalVars { + uint256 currentTotalDebt; + uint256 principalStableDebt; + uint256 avgStableRate; + uint256 scaledVariableDebt; + uint256 cumulatedStableInterest; + uint256 variableDebtOnLastUpdate; + uint256 stableDebtOnLastUpdate; + uint256 totalInterestAccrued; + uint256 amountToMint; + uint256 reserveFactor; + } - uint256 currentVariableDebt = IERC20(variableDebtToken).totalSupply(); - uint256 currentStableDebt = IERC20(stableDebtToken).totalSupply(); + function _mintToTreasury( + ReserveData storage reserve, + address stableDebtToken, + address variableDebtToken, + uint256 liquidityIndex, + uint256 variableBorrowIndex, + uint40 lastUpdateTimestamp + ) internal { + + MintToTreasuryLocalVars memory vars; - uint256 principalStableDebt = IStableDebtToken(stableDebtToken).principalTotalSupply(); - uint256 scaledVariableDebt = IVariableDebtToken(variableDebtToken).scaledTotalSupply(); - - - + vars.reserveFactor = reserve.configuration.getReserveFactor(); + + 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; //only cumulating if there is any income being produced if (currentLiquidityRate > 0) { - uint40 lastUpdateTimestamp = reserve.lastUpdateTimestamp; uint256 cumulatedLiquidityInterest = MathUtils.calculateLinearInterest( currentLiquidityRate, lastUpdateTimestamp @@ -276,12 +325,12 @@ library ReserveLogic { //as the liquidity rate might come only from stable rate loans, we need to ensure //that there is actual variable debt before accumulating - if (IERC20(reserve.variableDebtTokenAddress).totalSupply() > 0) { + if (IERC20(variableDebtToken).totalSupply() > 0) { uint256 cumulatedVariableBorrowInterest = MathUtils.calculateCompoundedInterest( reserve.currentVariableBorrowRate, lastUpdateTimestamp ); - index = cumulatedVariableBorrowInterest.rayMul(reserve.variableBorrowIndex); + index = cumulatedVariableBorrowInterest.rayMul(variableBorrowIndex); require(index < (1 << 128), Errors.VARIABLE_BORROW_INDEX_OVERFLOW); reserve.variableBorrowIndex = uint128(index); } diff --git a/contracts/tokenization/AToken.sol b/contracts/tokenization/AToken.sol index 9df145ba..cd270ccb 100644 --- a/contracts/tokenization/AToken.sol +++ b/contracts/tokenization/AToken.sol @@ -105,8 +105,7 @@ contract AToken is VersionedInitializable, ERC20, IAToken { emit Mint(user, amount, index); } - function mintToReserve(uint256 amount) external override onlyLendingPool { - uint256 index = _pool.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS); + function mintToTreasury(uint256 amount, uint256 index) external override onlyLendingPool { _mint(RESERVE_TREASURY_ADDRESS, amount.div(index)); } diff --git a/contracts/tokenization/StableDebtToken.sol b/contracts/tokenization/StableDebtToken.sol index cf50fb18..1d166c8f 100644 --- a/contracts/tokenization/StableDebtToken.sol +++ b/contracts/tokenization/StableDebtToken.sol @@ -68,7 +68,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { * @return the accumulated debt of the user **/ function balanceOf(address account) public virtual override view returns (uint256) { - uint256 accountBalance = principalBalanceOf(account); + uint256 accountBalance = super.balanceOf(account); uint256 stableRate = _usersData[account]; if (accountBalance == 0) { return 0; @@ -125,7 +125,6 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { //solium-disable-next-line _totalSupplyTimestamp = _timestamps[user] = uint40(block.timestamp); - //calculates the updated average stable rate _avgStableRate = _avgStableRate .rayMul(vars.supplyBeforeMint.wadToRay()) @@ -185,15 +184,22 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { emit BurnDebt(user, amount, previousBalance, currentBalance, balanceIncrease); } - /** * @dev Calculates the increase in balance since the last user interaction * @param user The address of the user for which the interest is being accumulated * @return The previous principal balance, the new principal balance, the balance increase * and the new user index **/ - function _calculateBalanceIncrease(address user) internal view returns (uint256, uint256, uint256) { - uint256 previousPrincipalBalance = principalBalanceOf(user); + function _calculateBalanceIncrease(address user) + internal + view + returns ( + uint256, + uint256, + uint256 + ) + { + uint256 previousPrincipalBalance = super.balanceOf(user); if (previousPrincipalBalance == 0) { return (0, 0, 0); @@ -209,11 +215,11 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { ); } - function principalTotalSupply() public override view returns(uint256) { - return super.totalSupply(); + function getPrincipalSupplyAndAvgRate() public override view returns (uint256, uint256) { + return (super.totalSupply(), _avgStableRate); } - - function totalSupply() public override view returns(uint256) { + + function totalSupply() public override view returns (uint256) { uint256 principalSupply = super.totalSupply(); if (principalSupply == 0) { return 0; @@ -225,4 +231,11 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { 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); + } } diff --git a/contracts/tokenization/VariableDebtToken.sol b/contracts/tokenization/VariableDebtToken.sol index d9a423eb..8a70f31c 100644 --- a/contracts/tokenization/VariableDebtToken.sol +++ b/contracts/tokenization/VariableDebtToken.sol @@ -39,7 +39,7 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken { * @return the debt balance of the user **/ function balanceOf(address user) public virtual override view returns (uint256) { - uint256 scaledBalance = super.principalBalanceOf(user); + uint256 scaledBalance = super.balanceOf(user); if (scaledBalance == 0) { return 0; diff --git a/contracts/tokenization/base/DebtTokenBase.sol b/contracts/tokenization/base/DebtTokenBase.sol index d8798906..ff0070b8 100644 --- a/contracts/tokenization/base/DebtTokenBase.sol +++ b/contracts/tokenization/base/DebtTokenBase.sol @@ -64,14 +64,6 @@ abstract contract DebtTokenBase is ERC20, VersionedInitializable { return UNDERLYING_ASSET; } - /** - * @dev Returns the principal debt balance of the user from - * @return The debt balance of the user since the last burn/mint action - **/ - function principalBalanceOf(address user) public virtual view returns (uint256) { - return super.balanceOf(user); - } - /** * @dev Being non transferrable, the debt token does not implement any of the * standard ERC20 functions for transfer and allowance. diff --git a/contracts/tokenization/interfaces/IAToken.sol b/contracts/tokenization/interfaces/IAToken.sol index c188162e..de8b0d3c 100644 --- a/contracts/tokenization/interfaces/IAToken.sol +++ b/contracts/tokenization/interfaces/IAToken.sol @@ -62,12 +62,11 @@ interface IAToken is IERC20 { function mint(address user, uint256 amount, uint256 index) external; /** - * @dev mints aTokens to reserve, based on the reserveFactor value - * only lending pools can call this function - * @param amount the amount of tokens to mint - */ - function mintToReserve(uint256 amount) external; - + * @dev mints aTokens to the reserve treasury + * @param amount the amount to mint + * @param index the liquidity index of the reserve + **/ + function mintToTreasury(uint256 amount, uint256 index) external; /** * @dev transfers tokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken @@ -104,6 +103,7 @@ interface IAToken is IERC20 { * @param amount the amount to transfer * @return the amount transferred **/ - function transferUnderlyingTo(address user, uint256 amount) external returns (uint256); + + } diff --git a/contracts/tokenization/interfaces/IStableDebtToken.sol b/contracts/tokenization/interfaces/IStableDebtToken.sol index 4c3800e0..c1e97388 100644 --- a/contracts/tokenization/interfaces/IStableDebtToken.sol +++ b/contracts/tokenization/interfaces/IStableDebtToken.sol @@ -86,7 +86,14 @@ interface IStableDebtToken { 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); + } diff --git a/test/helpers/utils/calculations.ts b/test/helpers/utils/calculations.ts index 861f5a94..b9f9ebe2 100644 --- a/test/helpers/utils/calculations.ts +++ b/test/helpers/utils/calculations.ts @@ -273,19 +273,16 @@ export const calcExpectedReserveDataAfterBorrow = ( const amountBorrowedBN = new BigNumber(amountBorrowed); - const userStableBorrowBalance = calcExpectedStableDebtTokenBalance( - userDataBeforeAction, - txTimestamp - ); + const userStableDebt = calcExpectedStableDebtTokenBalance(userDataBeforeAction, txTimestamp); - const userVariableBorrowBalance = calcExpectedVariableDebtTokenBalance( + const userVariableDebt = calcExpectedVariableDebtTokenBalance( reserveDataBeforeAction, userDataBeforeAction, txTimestamp ); if (borrowRateMode == RateMode.Stable) { - const debtAccrued = userStableBorrowBalance.minus(userDataBeforeAction.principalStableDebt); + const debtAccrued = userStableDebt.minus(userDataBeforeAction.principalStableDebt); expectedReserveData.totalLiquidity = reserveDataBeforeAction.totalLiquidity.plus(debtAccrued); @@ -301,7 +298,11 @@ export const calcExpectedReserveDataAfterBorrow = ( ); expectedReserveData.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable; } 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.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable .plus(amountBorrowedBN) @@ -362,12 +363,9 @@ export const calcExpectedReserveDataAfterRepay = ( let amountRepaidBN = new BigNumber(amountRepaid); - const userStableBorrowBalance = calcExpectedStableDebtTokenBalance( - userDataBeforeAction, - txTimestamp - ); + const userStableDebt = calcExpectedStableDebtTokenBalance(userDataBeforeAction, txTimestamp); - const userVariableBorrowBalance = calcExpectedVariableDebtTokenBalance( + const userVariableDebt = calcExpectedVariableDebtTokenBalance( reserveDataBeforeAction, userDataBeforeAction, txTimestamp @@ -376,14 +374,14 @@ export const calcExpectedReserveDataAfterRepay = ( //if amount repaid = MAX_UINT_AMOUNT, user is repaying everything if (amountRepaidBN.abs().eq(MAX_UINT_AMOUNT)) { if (borrowRateMode == RateMode.Stable) { - amountRepaidBN = userStableBorrowBalance; + amountRepaidBN = userStableDebt; } else { - amountRepaidBN = userVariableBorrowBalance; + amountRepaidBN = userVariableDebt; } } if (borrowRateMode == RateMode.Stable) { - const debtAccrued = userStableBorrowBalance.minus(userDataBeforeAction.principalStableDebt); + const debtAccrued = userStableDebt.minus(userDataBeforeAction.principalStableDebt); expectedReserveData.totalLiquidity = reserveDataBeforeAction.totalLiquidity.plus(debtAccrued); @@ -399,7 +397,11 @@ export const calcExpectedReserveDataAfterRepay = ( ); expectedReserveData.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable; } 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); @@ -477,7 +479,7 @@ export const calcExpectedUserDataAfterBorrow = ( const debtAccrued = currentStableDebt.minus(userDataBeforeAction.principalStableDebt); expectedUserData.principalStableDebt = currentStableDebt.plus(amountBorrowed); - expectedUserData.principalVariableDebt = userDataBeforeAction.principalVariableDebt; + expectedUserData.scaledVariableDebt = userDataBeforeAction.scaledVariableDebt; expectedUserData.stableBorrowRate = calcExpectedUserStableRate( userDataBeforeAction.principalStableDebt.plus(debtAccrued), @@ -510,8 +512,8 @@ export const calcExpectedUserDataAfterBorrow = ( expectedDataAfterAction, { ...userDataBeforeAction, - currentVariableDebt: expectedUserData.principalVariableDebt, - principalVariableDebt: expectedUserData.principalVariableDebt, + currentVariableDebt: expectedUserData.scaledVariableDebt.rayMul(reserveDataBeforeAction.variableBorrowIndex), + scaledVariableDebt: expectedUserData.scaledVariableDebt, variableBorrowIndex: interestRateMode == RateMode.Variable ? expectedDataAfterAction.variableBorrowIndex @@ -520,7 +522,7 @@ export const calcExpectedUserDataAfterBorrow = ( currentTimestamp ); - if (expectedUserData.principalVariableDebt.eq(0)) { + if (expectedUserData.scaledVariableDebt.eq(0)) { expectedUserData.variableBorrowIndex = new BigNumber(0); } else { expectedUserData.variableBorrowIndex = @@ -539,7 +541,7 @@ export const calcExpectedUserDataAfterBorrow = ( currentTimestamp ); expectedUserData.scaledATokenBalance = userDataBeforeAction.scaledATokenBalance; - + expectedUserData.walletBalance = userDataBeforeAction.walletBalance.plus(amountBorrowed); return expectedUserData; @@ -623,7 +625,7 @@ export const calcExpectedUserDataAfterRepay = ( txTimestamp ); expectedUserData.scaledATokenBalance = userDataBeforeAction.scaledATokenBalance; - + if (user === onBehalfOf) { expectedUserData.walletBalance = userDataBeforeAction.walletBalance.minus(totalRepaid); } else { @@ -657,51 +659,52 @@ export const calcExpectedReserveDataAfterSwapRateMode = ( expectedReserveData.address = reserveDataBeforeAction.address; - const variableBorrowBalance = calcExpectedVariableDebtTokenBalance( + const variableDebt = calcExpectedVariableDebtTokenBalance( reserveDataBeforeAction, userDataBeforeAction, txTimestamp ); - const stableBorrowBalance = calcExpectedStableDebtTokenBalance(userDataBeforeAction, txTimestamp); + const stableDebt = calcExpectedStableDebtTokenBalance(userDataBeforeAction, txTimestamp); expectedReserveData.availableLiquidity = reserveDataBeforeAction.availableLiquidity; if (rateMode === RateMode.Stable) { //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.averageStableBorrowRate = calcExpectedAverageStableBorrowRate( reserveDataBeforeAction.averageStableBorrowRate, reserveDataBeforeAction.totalBorrowsStable.plus(debtAccrued), - stableBorrowBalance.negated(), + stableDebt.negated(), userDataBeforeAction.stableBorrowRate ); expectedReserveData.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable.plus( - stableBorrowBalance + stableDebt ); expectedReserveData.totalBorrowsStable = reserveDataBeforeAction.totalBorrowsStable.minus( userDataBeforeAction.principalStableDebt ); } 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.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable.minus( - userDataBeforeAction.principalVariableDebt - ); + + expectedReserveData.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable; + expectedReserveData.totalBorrowsStable = reserveDataBeforeAction.totalBorrowsStable.plus( - variableBorrowBalance + variableDebt ); expectedReserveData.averageStableBorrowRate = calcExpectedAverageStableBorrowRate( reserveDataBeforeAction.averageStableBorrowRate, reserveDataBeforeAction.totalBorrowsStable, - variableBorrowBalance, + variableDebt, reserveDataBeforeAction.stableBorrowRate ); } @@ -926,9 +929,7 @@ const calcExpectedATokenBalance = ( ) => { const index = calcExpectedReserveNormalizedIncome(reserveDataBeforeAction, currentTimestamp); - const { - scaledATokenBalance: scaledBalanceBeforeAction, - } = userDataBeforeAction; + const {scaledATokenBalance: scaledBalanceBeforeAction} = userDataBeforeAction; return scaledBalanceBeforeAction.rayMul(index); }; @@ -969,8 +970,7 @@ export const calcExpectedVariableDebtTokenBalance = ( ) => { const debt = calcExpectedReserveNormalizedDebt(reserveDataBeforeAction, currentTimestamp); - const { scaledVariableDebt } = userDataBeforeAction; - + const {scaledVariableDebt} = userDataBeforeAction; return scaledVariableDebt.rayMul(debt); }; diff --git a/test/helpers/utils/helpers.ts b/test/helpers/utils/helpers.ts index 59eb600a..1d2516ad 100644 --- a/test/helpers/utils/helpers.ts +++ b/test/helpers/utils/helpers.ts @@ -79,7 +79,6 @@ export const getUserData = async ( currentStableDebt: new BigNumber(userData.currentStableDebt.toString()), currentVariableDebt: new BigNumber(userData.currentVariableDebt.toString()), principalStableDebt: new BigNumber(userData.principalStableDebt.toString()), - principalVariableDebt: new BigNumber(userData.principalVariableDebt.toString()), scaledVariableDebt: new BigNumber(userData.scaledVariableDebt.toString()), stableBorrowRate: new BigNumber(userData.stableBorrowRate.toString()), liquidityRate: new BigNumber(userData.liquidityRate.toString()), diff --git a/test/helpers/utils/interfaces/index.ts b/test/helpers/utils/interfaces/index.ts index 646e6b10..2acbfa31 100644 --- a/test/helpers/utils/interfaces/index.ts +++ b/test/helpers/utils/interfaces/index.ts @@ -6,7 +6,6 @@ export interface UserReserveData { currentStableDebt: BigNumber; currentVariableDebt: BigNumber; principalStableDebt: BigNumber; - principalVariableDebt: BigNumber; scaledVariableDebt: BigNumber; liquidityRate: BigNumber; stableBorrowRate: BigNumber; diff --git a/test/scenario.spec.ts b/test/scenario.spec.ts index 1d8da5e9..17830d1c 100644 --- a/test/scenario.spec.ts +++ b/test/scenario.spec.ts @@ -10,7 +10,7 @@ import {executeStory} from './helpers/scenario-engine'; const scenarioFolder = './test/helpers/scenarios/'; -const selectedScenarios: string[] = ['']; +const selectedScenarios: string[] = ['deposit.json']; fs.readdirSync(scenarioFolder).forEach((file) => { if (selectedScenarios.length > 0 && !selectedScenarios.includes(file)) return; diff --git a/test/variable-debt-token.spec.ts b/test/variable-debt-token.spec.ts index 89bb1acc..a79bdde2 100644 --- a/test/variable-debt-token.spec.ts +++ b/test/variable-debt-token.spec.ts @@ -18,7 +18,7 @@ makeSuite('Variable debt token tests', (testEnv: TestEnv) => { daiVariableDebtTokenAddress ); - await expect(variableDebtContract.mint(deployer.address, '1')).to.be.revertedWith( + await expect(variableDebtContract.mint(deployer.address, '1', '1')).to.be.revertedWith( CALLER_MUST_BE_LENDING_POOL ); }); @@ -34,7 +34,7 @@ makeSuite('Variable debt token tests', (testEnv: TestEnv) => { daiVariableDebtTokenAddress ); - await expect(variableDebtContract.burn(deployer.address, '1')).to.be.revertedWith( + await expect(variableDebtContract.burn(deployer.address, '1', '1')).to.be.revertedWith( CALLER_MUST_BE_LENDING_POOL ); });