From 12f1dbd0dcebdaf9e6f9a140c4e1ec3fec7ccd8d Mon Sep 17 00:00:00 2001 From: The3D Date: Mon, 21 Sep 2020 22:08:44 +0200 Subject: [PATCH] Readded calculateAvailableBorrowsETH --- contracts/interfaces/ILendingPool.sol | 1 + contracts/lendingpool/LendingPool.sol | 25 +++++-- .../configuration/ReserveConfiguration.sol | 1 - contracts/libraries/logic/GenericLogic.sol | 24 +++++++ contracts/tokenization/StableDebtToken.sol | 1 - test/helpers/actions.ts | 5 -- .../scenarios/rebalance-stable-rate.json | 66 +++++++++++++++++-- test/scenario.spec.ts | 2 +- 8 files changed, 104 insertions(+), 21 deletions(-) diff --git a/contracts/interfaces/ILendingPool.sol b/contracts/interfaces/ILendingPool.sol index c98291c5..66d4542a 100644 --- a/contracts/interfaces/ILendingPool.sol +++ b/contracts/interfaces/ILendingPool.sol @@ -367,6 +367,7 @@ interface ILendingPool { returns ( uint256 totalCollateralETH, uint256 totalBorrowsETH, + uint256 availableBorrowsETH, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor diff --git a/contracts/lendingpool/LendingPool.sol b/contracts/lendingpool/LendingPool.sol index 4d5ef9e8..95af83b1 100644 --- a/contracts/lendingpool/LendingPool.sol +++ b/contracts/lendingpool/LendingPool.sol @@ -29,7 +29,6 @@ import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/SafeERC20.sol'; import {ILendingPool} from '../interfaces/ILendingPool.sol'; import {LendingPoolStorage} from './LendingPoolStorage.sol'; import {IReserveInterestRateStrategy} from '../interfaces/IReserveInterestRateStrategy.sol'; - /** * @title LendingPool contract * @notice Implements the actions of the LendingPool, and exposes accessory methods to fetch the users and reserve data @@ -161,6 +160,14 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage emit Withdraw(asset, msg.sender, amount); } + /** + * @dev returns the borrow allowance of the user + * @param asset The underlying asset of the debt token + * @param fromUser The user to giving allowance + * @param toUser The user to give allowance to + * @param interestRateMode Type of debt: 1 for stable, 2 for variable + * @return the current allowance of toUser + **/ function getBorrowAllowance( address fromUser, address toUser, @@ -363,15 +370,13 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage IERC20 stableDebtToken = IERC20(reserve.stableDebtTokenAddress); IERC20 variableDebtToken = IERC20(reserve.variableDebtTokenAddress); + address aTokenAddress = reserve.aTokenAddress; uint256 stableBorrowBalance = IERC20(stableDebtToken).balanceOf(user); - // user must be borrowing on asset at a stable rate - require(stableBorrowBalance > 0, Errors.NOT_ENOUGH_STABLE_BORROW_BALANCE); - //if the utilization rate is below 95%, no rebalances are needed uint256 totalBorrows = stableDebtToken.totalSupply().add(variableDebtToken.totalSupply()).wadToRay(); - uint256 availableLiquidity = IERC20(asset).balanceOf(reserve.aTokenAddress).wadToRay(); + uint256 availableLiquidity = IERC20(asset).balanceOf(aTokenAddress).wadToRay(); uint256 usageRatio = totalBorrows == 0 ? 0 : totalBorrows.rayDiv(availableLiquidity.add(totalBorrows)); @@ -398,11 +403,10 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage IStableDebtToken(address(stableDebtToken)).burn(user, stableBorrowBalance); IStableDebtToken(address(stableDebtToken)).mint(user, stableBorrowBalance, reserve.currentStableBorrowRate); - reserve.updateInterestRates(asset, reserve.aTokenAddress, 0, 0); + reserve.updateInterestRates(asset, aTokenAddress, 0, 0); emit RebalanceStableBorrowRate(asset, user); - return; } /** @@ -731,6 +735,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage returns ( uint256 totalCollateralETH, uint256 totalBorrowsETH, + uint256 availableBorrowsETH, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor @@ -749,6 +754,12 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage _reservesList, _addressesProvider.getPriceOracle() ); + + availableBorrowsETH = GenericLogic.calculateAvailableBorrowsETH( + totalCollateralETH, + totalBorrowsETH, + ltv + ); } function getUserReserveData(address asset, address user) diff --git a/contracts/libraries/configuration/ReserveConfiguration.sol b/contracts/libraries/configuration/ReserveConfiguration.sol index fb3d7972..66fa21f4 100644 --- a/contracts/libraries/configuration/ReserveConfiguration.sol +++ b/contracts/libraries/configuration/ReserveConfiguration.sol @@ -6,7 +6,6 @@ import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import {ReserveLogic} from '../logic/ReserveLogic.sol'; import {WadRayMath} from '../math/WadRayMath.sol'; import {IPriceOracleGetter} from '../../interfaces/IPriceOracleGetter.sol'; -import "@nomiclabs/buidler/console.sol"; /** * @title ReserveConfiguration library diff --git a/contracts/libraries/logic/GenericLogic.sol b/contracts/libraries/logic/GenericLogic.sol index 82993d28..4b64e85f 100644 --- a/contracts/libraries/logic/GenericLogic.sol +++ b/contracts/libraries/logic/GenericLogic.sol @@ -253,4 +253,28 @@ library GenericLogic { 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; + } } diff --git a/contracts/tokenization/StableDebtToken.sol b/contracts/tokenization/StableDebtToken.sol index 1974d51e..160d0f88 100644 --- a/contracts/tokenization/StableDebtToken.sol +++ b/contracts/tokenization/StableDebtToken.sol @@ -8,7 +8,6 @@ import {DebtTokenBase} from './base/DebtTokenBase.sol'; import {MathUtils} from '../libraries/math/MathUtils.sol'; import {WadRayMath} from '../libraries/math/WadRayMath.sol'; import {IStableDebtToken} from './interfaces/IStableDebtToken.sol'; -import "@nomiclabs/buidler/console.sol"; /** * @title contract StableDebtToken diff --git a/test/helpers/actions.ts b/test/helpers/actions.ts index d5bdfee8..69c9c6ce 100644 --- a/test/helpers/actions.ts +++ b/test/helpers/actions.ts @@ -636,11 +636,6 @@ export const rebalanceStableBorrowRate = async ( testEnv ); - console.log("avl liquidity ", reserveDataBefore.availableLiquidity.toFixed()); - console.log("Total borrows stable ", reserveDataBefore.totalStableDebt.toFixed()); - console.log("Total borrows variable ", reserveDataBefore.totalVariableDebt.toFixed()); - console.log("Usage ratio ", reserveDataBefore.utilizationRate.toFixed()); - if (expectedResult === 'success') { const txResult = await waitForTx( await pool.connect(user.signer).rebalanceStableBorrowRate(reserve, target.address) diff --git a/test/helpers/scenarios/rebalance-stable-rate.json b/test/helpers/scenarios/rebalance-stable-rate.json index 891de2b7..70ea820a 100644 --- a/test/helpers/scenarios/rebalance-stable-rate.json +++ b/test/helpers/scenarios/rebalance-stable-rate.json @@ -78,8 +78,8 @@ "name": "borrow", "args": { "reserve": "DAI", - "amount": "600", - "borrowRateMode": "variable", + "amount": "250", + "borrowRateMode": "stable", "user": "1", "timeTravel": "365" }, @@ -98,14 +98,68 @@ ] }, { - "description": "User 1 swaps to stable, user 0 tries to rebalance but the conditions are not met (revert expected)", + "description": "User 1 borrows another 200 at stable, user 0 tries to rebalance but the conditions are not met (revert expected)", "actions": [ { - "name": "swapBorrowRateMode", + "name": "borrow", "args": { "reserve": "DAI", + "amount": "200", + "borrowRateMode": "stable", "user": "1", - "borrowRateMode": "variable" + "timeTravel": "365" + }, + "expected": "success" + }, + { + "name": "rebalanceStableBorrowRate", + "args": { + "reserve": "DAI", + "user": "0", + "target": "1" + }, + "expected": "revert", + "revertMessage": "Interest rate rebalance conditions were not met" + } + ] + }, + { + "description": "User 1 borrows another 200 at stable, user 0 tries to rebalance but the conditions are not met (revert expected)", + "actions": [ + { + "name": "borrow", + "args": { + "reserve": "DAI", + "amount": "200", + "borrowRateMode": "stable", + "user": "1", + "timeTravel": "365" + }, + "expected": "success" + }, + { + "name": "rebalanceStableBorrowRate", + "args": { + "reserve": "DAI", + "user": "0", + "target": "1" + }, + "expected": "revert", + "revertMessage": "Interest rate rebalance conditions were not met" + } + ] + }, + { + "description": "User 1 borrows another 100 at stable, user 0 tries to rebalance but the conditions are not met (revert expected)", + "actions": [ + { + "name": "borrow", + "args": { + "reserve": "DAI", + "amount": "100", + "borrowRateMode": "stable", + "user": "1", + "timeTravel": "365" }, "expected": "success" }, @@ -155,7 +209,7 @@ "name": "borrow", "args": { "reserve": "DAI", - "amount": "340", + "amount": "190", "borrowRateMode": "variable", "user": "2" }, diff --git a/test/scenario.spec.ts b/test/scenario.spec.ts index 0a77c9e8..54fe7433 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[] = ['rebalance-stable-rate.json']; +const selectedScenarios: string[] = []; fs.readdirSync(scenarioFolder).forEach((file) => { if (selectedScenarios.length > 0 && !selectedScenarios.includes(file)) return;