Merge branch 'fix/45' into 'master'

Resolve "Update rebalance conditions"

Closes #45

See merge request aave-tech/protocol-v2!54
This commit is contained in:
Ernesto Boado 2020-09-21 20:14:34 +00:00
commit f756f44a8d
9 changed files with 140 additions and 96 deletions

View File

@ -10,9 +10,13 @@ interface IReserveInterestRateStrategy {
/** /**
* @dev returns the base variable borrow rate, in rays * @dev returns the base variable borrow rate, in rays
*/ */
function baseVariableBorrowRate() external view returns (uint256); function baseVariableBorrowRate() external view returns (uint256);
/**
* @dev returns the maximum variable borrow rate
*/
function getMaxVariableBorrowRate() external view returns (uint256);
/** /**
* @dev calculates the liquidity, stable, and variable rates depending on the current utilization rate * @dev calculates the liquidity, stable, and variable rates depending on the current utilization rate
* and the base parameters * and the base parameters

View File

@ -91,6 +91,10 @@ contract DefaultReserveInterestRateStrategy is IReserveInterestRateStrategy {
return _baseVariableBorrowRate; return _baseVariableBorrowRate;
} }
function getMaxVariableBorrowRate() external override view returns (uint256) {
return _baseVariableBorrowRate.add(_variableRateSlope1).add(_variableRateSlope2);
}
struct CalcInterestRatesLocalVars { struct CalcInterestRatesLocalVars {
uint256 totalBorrows; uint256 totalBorrows;

View File

@ -28,21 +28,22 @@ 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 {ILendingPool} from '../interfaces/ILendingPool.sol'; import {ILendingPool} from '../interfaces/ILendingPool.sol';
import {LendingPoolStorage} from './LendingPoolStorage.sol'; import {LendingPoolStorage} from './LendingPoolStorage.sol';
import {IReserveInterestRateStrategy} from '../interfaces/IReserveInterestRateStrategy.sol';
/** /**
* @title LendingPool contract * @title LendingPool contract
* @notice Implements the actions of the LendingPool, and exposes accessory methods to fetch the users and reserve data * @notice Implements the actions of the LendingPool, and exposes accessory methods to fetch the users and reserve data
* @author Aave * @author Aave
**/ **/
contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage { contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage {
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;
//main configuration parameters //main configuration parameters
uint256 public constant REBALANCE_DOWN_RATE_DELTA = (1e27) / 5; uint256 public constant REBALANCE_UP_LIQUIDITY_RATE_THRESHOLD = 4000;
uint256 public constant MAX_STABLE_RATE_BORROW_SIZE_PERCENT = 25; uint256 public constant REBALANCE_UP_USAGE_RATIO_THRESHOLD = 0.95 * 1e27; //usage ratio of 95%
uint256 public constant MAX_STABLE_RATE_BORROW_SIZE_PERCENT = 2500;
uint256 public constant FLASHLOAN_PREMIUM_TOTAL = 9; uint256 public constant FLASHLOAN_PREMIUM_TOTAL = 9;
uint256 public constant MAX_NUMBER_RESERVES = 128; uint256 public constant MAX_NUMBER_RESERVES = 128;
uint256 public constant LENDINGPOOL_REVISION = 0x2; uint256 public constant LENDINGPOOL_REVISION = 0x2;
@ -50,13 +51,12 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
/** /**
* @dev only lending pools configurator can use functions affected by this modifier * @dev only lending pools configurator can use functions affected by this modifier
**/ **/
function onlyLendingPoolConfigurator() internal view { function _onlyLendingPoolConfigurator() internal view {
require( require(
_addressesProvider.getLendingPoolConfigurator() == msg.sender, _addressesProvider.getLendingPoolConfigurator() == msg.sender,
Errors.CALLER_NOT_LENDING_POOL_CONFIGURATOR Errors.CALLER_NOT_LENDING_POOL_CONFIGURATOR
); );
} }
/** /**
* @dev Function to make a function callable only when the contract is not paused. * @dev Function to make a function callable only when the contract is not paused.
* *
@ -64,7 +64,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
* *
* - The contract must not be paused. * - The contract must not be paused.
*/ */
function whenNotPaused() internal view { function _whenNotPaused() internal view {
require(!_paused, Errors.IS_PAUSED); require(!_paused, Errors.IS_PAUSED);
} }
@ -94,7 +94,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
address onBehalfOf, address onBehalfOf,
uint16 referralCode uint16 referralCode
) external override { ) external override {
whenNotPaused(); _whenNotPaused();
ReserveLogic.ReserveData storage reserve = _reserves[asset]; ReserveLogic.ReserveData storage reserve = _reserves[asset];
ValidationLogic.validateDeposit(reserve, amount); ValidationLogic.validateDeposit(reserve, amount);
@ -123,7 +123,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
* @param amount the underlying amount to be redeemed * @param amount the underlying amount to be redeemed
**/ **/
function withdraw(address asset, uint256 amount) external override { function withdraw(address asset, uint256 amount) external override {
whenNotPaused(); _whenNotPaused();
ReserveLogic.ReserveData storage reserve = _reserves[asset]; ReserveLogic.ReserveData storage reserve = _reserves[asset];
address aToken = reserve.aTokenAddress; address aToken = reserve.aTokenAddress;
@ -139,7 +139,6 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
ValidationLogic.validateWithdraw( ValidationLogic.validateWithdraw(
asset, asset,
aToken,
amountToWithdraw, amountToWithdraw,
userBalance, userBalance,
_reserves, _reserves,
@ -161,6 +160,14 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
emit Withdraw(asset, msg.sender, amount); 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( function getBorrowAllowance(
address fromUser, address fromUser,
address toUser, address toUser,
@ -184,7 +191,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
uint256 interestRateMode, uint256 interestRateMode,
uint256 amount uint256 amount
) external override { ) external override {
whenNotPaused(); _whenNotPaused();
address debtToken = _reserves[asset].getDebtTokenAddress(interestRateMode); address debtToken = _reserves[asset].getDebtTokenAddress(interestRateMode);
_borrowAllowance[debtToken][msg.sender][user] = amount; _borrowAllowance[debtToken][msg.sender][user] = amount;
@ -207,7 +214,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
uint16 referralCode, uint16 referralCode,
address onBehalfOf address onBehalfOf
) external override { ) external override {
whenNotPaused(); _whenNotPaused();
ReserveLogic.ReserveData storage reserve = _reserves[asset]; ReserveLogic.ReserveData storage reserve = _reserves[asset];
if (onBehalfOf != msg.sender) { if (onBehalfOf != msg.sender) {
@ -247,7 +254,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
uint256 rateMode, uint256 rateMode,
address onBehalfOf address onBehalfOf
) external override { ) external override {
whenNotPaused(); _whenNotPaused();
ReserveLogic.ReserveData storage reserve = _reserves[asset]; ReserveLogic.ReserveData storage reserve = _reserves[asset];
@ -304,7 +311,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
* @param rateMode the rate mode that the user wants to swap * @param rateMode the rate mode that the user wants to swap
**/ **/
function swapBorrowRateMode(address asset, uint256 rateMode) external override { function swapBorrowRateMode(address asset, uint256 rateMode) external override {
whenNotPaused(); _whenNotPaused();
ReserveLogic.ReserveData storage reserve = _reserves[asset]; ReserveLogic.ReserveData storage reserve = _reserves[asset];
(uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(msg.sender, reserve); (uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(msg.sender, reserve);
@ -356,43 +363,50 @@ 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];
IStableDebtToken stableDebtToken = IStableDebtToken(reserve.stableDebtTokenAddress); IERC20 stableDebtToken = IERC20(reserve.stableDebtTokenAddress);
IERC20 variableDebtToken = IERC20(reserve.variableDebtTokenAddress);
address aTokenAddress = reserve.aTokenAddress;
uint256 stableBorrowBalance = IERC20(address(stableDebtToken)).balanceOf(user); uint256 stableBorrowBalance = IERC20(stableDebtToken).balanceOf(user);
// user must be borrowing on asset at a stable rate //if the utilization rate is below 95%, no rebalances are needed
require(stableBorrowBalance > 0, Errors.NOT_ENOUGH_STABLE_BORROW_BALANCE); uint256 totalBorrows = stableDebtToken.totalSupply().add(variableDebtToken.totalSupply()).wadToRay();
uint256 availableLiquidity = IERC20(asset).balanceOf(aTokenAddress).wadToRay();
uint256 usageRatio = totalBorrows == 0
? 0
: totalBorrows.rayDiv(availableLiquidity.add(totalBorrows));
uint256 rebalanceDownRateThreshold = WadRayMath.ray().add(REBALANCE_DOWN_RATE_DELTA).rayMul( //if the liquidity rate is below REBALANCE_UP_THRESHOLD of the max variable APR at 95% usage,
reserve.currentStableBorrowRate //then we allow rebalancing of the stable rate positions.
);
//1. user stable borrow rate is below the current liquidity rate. The loan needs to be rebalanced, uint256 currentLiquidityRate = reserve.currentLiquidityRate;
//as this situation can be abused (user putting back the borrowed liquidity in the same reserve to earn on it) uint256 maxVariableBorrowRate = IReserveInterestRateStrategy(
//2. user stable rate is above the market avg borrow rate of a certain delta, and utilization rate is low. reserve
//In this case, the user is paying an interest that is too high, and needs to be rescaled down. .interestRateStrategyAddress
)
uint256 userStableRate = stableDebtToken.getUserStableRate(user); .getMaxVariableBorrowRate();
require( require(
userStableRate < reserve.currentLiquidityRate || userStableRate > rebalanceDownRateThreshold, usageRatio >= REBALANCE_UP_USAGE_RATIO_THRESHOLD &&
currentLiquidityRate <=
maxVariableBorrowRate.percentMul(REBALANCE_UP_LIQUIDITY_RATE_THRESHOLD),
Errors.INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET Errors.INTEREST_RATE_REBALANCE_CONDITIONS_NOT_MET
); );
reserve.updateState(); reserve.updateState();
//burn old debt tokens, mint new ones IStableDebtToken(address(stableDebtToken)).burn(user, stableBorrowBalance);
stableDebtToken.burn(user, stableBorrowBalance); IStableDebtToken(address(stableDebtToken)).mint(user, stableBorrowBalance, reserve.currentStableBorrowRate);
stableDebtToken.mint(user, stableBorrowBalance, reserve.currentStableBorrowRate);
reserve.updateInterestRates(asset, reserve.aTokenAddress, 0, 0); reserve.updateInterestRates(asset, aTokenAddress, 0, 0);
emit RebalanceStableBorrowRate(asset, user); emit RebalanceStableBorrowRate(asset, user);
return;
} }
/** /**
@ -401,7 +415,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
* @param useAsCollateral true if the user wants to user the deposit as collateral, false otherwise. * @param useAsCollateral true if the user wants to user the deposit as collateral, false otherwise.
**/ **/
function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external override { function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external override {
whenNotPaused(); _whenNotPaused();
ReserveLogic.ReserveData storage reserve = _reserves[asset]; ReserveLogic.ReserveData storage reserve = _reserves[asset];
ValidationLogic.validateSetUseReserveAsCollateral( ValidationLogic.validateSetUseReserveAsCollateral(
@ -438,7 +452,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
uint256 purchaseAmount, uint256 purchaseAmount,
bool receiveAToken bool receiveAToken
) external override { ) external override {
whenNotPaused(); _whenNotPaused();
address collateralManager = _addressesProvider.getLendingPoolCollateralManager(); address collateralManager = _addressesProvider.getLendingPoolCollateralManager();
//solium-disable-next-line //solium-disable-next-line
@ -482,7 +496,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
address receiver, address receiver,
bytes calldata params bytes calldata params
) external override { ) external override {
whenNotPaused(); _whenNotPaused();
require(!_flashLiquidationLocked, Errors.REENTRANCY_NOT_ALLOWED); require(!_flashLiquidationLocked, Errors.REENTRANCY_NOT_ALLOWED);
_flashLiquidationLocked = true; _flashLiquidationLocked = true;
@ -538,7 +552,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
bytes calldata params, bytes calldata params,
uint16 referralCode uint16 referralCode
) external override { ) external override {
whenNotPaused(); _whenNotPaused();
ReserveLogic.ReserveData storage reserve = _reserves[asset]; ReserveLogic.ReserveData storage reserve = _reserves[asset];
FlashLoanLocalVars memory vars; FlashLoanLocalVars memory vars;
@ -600,7 +614,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
uint256 amountToSwap, uint256 amountToSwap,
bytes calldata params bytes calldata params
) external override { ) external override {
whenNotPaused(); _whenNotPaused();
address collateralManager = _addressesProvider.getLendingPoolCollateralManager(); address collateralManager = _addressesProvider.getLendingPoolCollateralManager();
//solium-disable-next-line //solium-disable-next-line
@ -799,7 +813,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
address variableDebtAddress, address variableDebtAddress,
address interestRateStrategyAddress address interestRateStrategyAddress
) external override { ) external override {
onlyLendingPoolConfigurator(); _onlyLendingPoolConfigurator();
_reserves[asset].init( _reserves[asset].init(
aTokenAddress, aTokenAddress,
stableDebtAddress, stableDebtAddress,
@ -819,12 +833,12 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
external external
override override
{ {
onlyLendingPoolConfigurator(); _onlyLendingPoolConfigurator();
_reserves[asset].interestRateStrategyAddress = rateStrategyAddress; _reserves[asset].interestRateStrategyAddress = rateStrategyAddress;
} }
function setConfiguration(address asset, uint256 configuration) external override { function setConfiguration(address asset, uint256 configuration) external override {
onlyLendingPoolConfigurator(); _onlyLendingPoolConfigurator();
_reserves[asset].configuration.data = configuration; _reserves[asset].configuration.data = configuration;
} }
@ -980,7 +994,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
address user, address user,
uint256 amount uint256 amount
) external override view returns (bool) { ) external override view returns (bool) {
whenNotPaused(); _whenNotPaused();
return return
GenericLogic.balanceDecreaseAllowed( GenericLogic.balanceDecreaseAllowed(
asset, asset,
@ -998,7 +1012,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage
* @param val the boolean value to set the current pause state of LendingPool * @param val the boolean value to set the current pause state of LendingPool
*/ */
function setPause(bool val) external override { function setPause(bool val) external override {
onlyLendingPoolConfigurator(); _onlyLendingPoolConfigurator();
_paused = val; _paused = val;
if (_paused) { if (_paused) {

View File

@ -6,7 +6,6 @@ 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
@ -143,7 +142,7 @@ library ReserveConfiguration {
* @param self the reserve configuration * @param self the reserve configuration
* @param active the active state * @param active the active state
**/ **/
function setActive(ReserveConfiguration.Map memory self, bool active) internal { function setActive(ReserveConfiguration.Map memory self, bool active) internal pure {
self.data = (self.data & ACTIVE_MASK) | (uint256(active ? 1 : 0) << 56); self.data = (self.data & ACTIVE_MASK) | (uint256(active ? 1 : 0) << 56);
} }

View File

@ -127,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)
{ {
@ -371,7 +371,6 @@ library ReserveLogic {
uint256 liquidityIndex, uint256 liquidityIndex,
uint256 variableBorrowIndex uint256 variableBorrowIndex
) internal returns (uint256, uint256) { ) internal returns (uint256, uint256) {
uint40 timestamp = reserve.lastUpdateTimestamp; uint40 timestamp = reserve.lastUpdateTimestamp;
uint256 currentLiquidityRate = reserve.currentLiquidityRate; uint256 currentLiquidityRate = reserve.currentLiquidityRate;

View File

@ -34,7 +34,7 @@ library ValidationLogic {
* @param reserve the reserve state on which the user is depositing * @param reserve the reserve state on which the user is depositing
* @param amount the amount to be deposited * @param amount the amount to be deposited
*/ */
function validateDeposit(ReserveLogic.ReserveData storage reserve, uint256 amount) internal view { function validateDeposit(ReserveLogic.ReserveData storage reserve, uint256 amount) external view {
(bool isActive, bool isFreezed, , ) = reserve.configuration.getFlags(); (bool isActive, bool isFreezed, , ) = reserve.configuration.getFlags();
require(amount > 0, Errors.AMOUNT_NOT_GREATER_THAN_0); require(amount > 0, Errors.AMOUNT_NOT_GREATER_THAN_0);
@ -45,13 +45,11 @@ library ValidationLogic {
/** /**
* @dev validates a withdraw action. * @dev validates a withdraw action.
* @param reserveAddress the address of the reserve * @param reserveAddress the address of the reserve
* @param aTokenAddress the address of the aToken for the reserve
* @param amount the amount to be withdrawn * @param amount the amount to be withdrawn
* @param userBalance the balance of the user * @param userBalance the balance of the user
*/ */
function validateWithdraw( function validateWithdraw(
address reserveAddress, address reserveAddress,
address aTokenAddress,
uint256 amount, uint256 amount,
uint256 userBalance, uint256 userBalance,
mapping(address => ReserveLogic.ReserveData) storage reservesData, mapping(address => ReserveLogic.ReserveData) storage reservesData,

View File

@ -8,7 +8,6 @@ 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

View File

@ -19,7 +19,7 @@
] ]
}, },
{ {
"description": "User 0 deposits 1000 DAI, user 1 deposits 1 ETH, borrows 100 DAI at a variable rate, user 0 rebalances user 1 (revert expected)", "description": "User 0 deposits 1000 DAI, user 1 deposits 5 ETH, borrows 600 DAI at a variable rate, user 0 rebalances user 1 (revert expected)",
"actions": [ "actions": [
{ {
"name": "mint", "name": "mint",
@ -51,7 +51,7 @@
"name": "mint", "name": "mint",
"args": { "args": {
"reserve": "WETH", "reserve": "WETH",
"amount": "1", "amount": "5",
"user": "1" "user": "1"
}, },
"expected": "success" "expected": "success"
@ -69,7 +69,7 @@
"args": { "args": {
"reserve": "WETH", "reserve": "WETH",
"amount": "1", "amount": "5",
"user": "1" "user": "1"
}, },
"expected": "success" "expected": "success"
@ -78,8 +78,8 @@
"name": "borrow", "name": "borrow",
"args": { "args": {
"reserve": "DAI", "reserve": "DAI",
"amount": "100", "amount": "250",
"borrowRateMode": "variable", "borrowRateMode": "stable",
"user": "1", "user": "1",
"timeTravel": "365" "timeTravel": "365"
}, },
@ -98,14 +98,16 @@
] ]
}, },
{ {
"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": [ "actions": [
{ {
"name": "swapBorrowRateMode", "name": "borrow",
"args": { "args": {
"reserve": "DAI", "reserve": "DAI",
"amount": "200",
"borrowRateMode": "stable",
"user": "1", "user": "1",
"borrowRateMode": "variable" "timeTravel": "365"
}, },
"expected": "success" "expected": "success"
}, },
@ -122,40 +124,92 @@
] ]
}, },
{ {
"description": "User 2 deposits ETH and borrows the remaining DAI, causing the stable rates to rise (liquidity rate < user 1 borrow rate). User 0 tries to rebalance user 1 (revert expected)", "description": "User 1 borrows another 200 at stable, user 0 tries to rebalance but the conditions are not met (revert expected)",
"actions": [ "actions": [
{ {
"name": "mint", "name": "borrow",
"args": { "args": {
"reserve": "WETH", "reserve": "DAI",
"amount": "5", "amount": "200",
"user": "2" "borrowRateMode": "stable",
"user": "1",
"timeTravel": "365"
}, },
"expected": "success" "expected": "success"
}, },
{ {
"name": "approve", "name": "rebalanceStableBorrowRate",
"args": { "args": {
"reserve": "WETH", "reserve": "DAI",
"user": "2" "user": "0",
"target": "1"
}, },
"expected": "success" "expected": "revert",
"revertMessage": "Interest rate rebalance conditions were not met"
}
]
}, },
{ {
"name": "deposit", "description": "User 1 borrows another 100 at stable, user 0 tries to rebalance but the conditions are not met (revert expected)",
"args": { "actions": [
"reserve": "WETH",
"amount": "5",
"user": "2"
},
"expected": "success"
},
{ {
"name": "borrow", "name": "borrow",
"args": { "args": {
"reserve": "DAI", "reserve": "DAI",
"amount": "100", "amount": "100",
"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 2 deposits ETH and borrows the remaining DAI, causing the stable rates to rise (usage ratio = 94%). User 0 tries to rebalance user 1 (revert expected)",
"actions": [
{
"name": "mint",
"args": {
"reserve": "WETH",
"amount": "5",
"user": "2"
},
"expected": "success"
},
{
"name": "approve",
"args": {
"reserve": "WETH",
"user": "2"
},
"expected": "success"
},
{
"name": "deposit",
"args": {
"reserve": "WETH",
"amount": "5",
"user": "2"
},
"expected": "success"
},
{
"name": "borrow",
"args": {
"reserve": "DAI",
"amount": "190",
"borrowRateMode": "variable", "borrowRateMode": "variable",
"user": "2" "user": "2"
}, },
@ -174,40 +228,13 @@
] ]
}, },
{ {
"description": "User 2 borrows more DAI, causing the liquidity rate to rise above user 1 stable borrow rate User 0 rebalances user 1", "description": "User 2 borrows the remaining DAI (usage ratio = 100%). User 0 rebalances user 1",
"actions": [ "actions": [
{
"name": "mint",
"args": {
"reserve": "WETH",
"amount": "3",
"user": "2"
},
"expected": "success"
},
{
"name": "approve",
"args": {
"reserve": "WETH",
"user": "2"
},
"expected": "success"
},
{
"name": "deposit",
"args": {
"reserve": "WETH",
"amount": "3",
"user": "2"
},
"expected": "success"
},
{ {
"name": "borrow", "name": "borrow",
"args": { "args": {
"reserve": "DAI", "reserve": "DAI",
"amount": "700", "amount": "60",
"borrowRateMode": "variable", "borrowRateMode": "variable",
"user": "2" "user": "2"
}, },