From 4e4fbe65395540304251e9d81232c9921abc4453 Mon Sep 17 00:00:00 2001 From: The3D Date: Tue, 3 Nov 2020 19:47:57 +0100 Subject: [PATCH 1/4] Refactoring of credit delegation --- contracts/interfaces/ILendingPool.sol | 28 --------- contracts/lendingpool/LendingPool.sol | 60 ++----------------- contracts/lendingpool/LendingPoolStorage.sol | 2 - contracts/libraries/helpers/Errors.sol | 2 +- contracts/libraries/logic/ReserveLogic.sol | 22 ------- contracts/tokenization/StableDebtToken.sol | 38 ++++++------ contracts/tokenization/VariableDebtToken.sol | 13 ++-- contracts/tokenization/base/DebtTokenBase.sol | 47 ++++++++++++++- contracts/tokenization/interfaces/IAToken.sol | 21 +++++++ .../interfaces/IScaledBalanceToken.sol | 21 ------- .../interfaces/IStableDebtToken.sol | 5 +- .../interfaces/IVariableDebtToken.sol | 23 +++++++ deployed-contracts.json | 11 ++-- test/flashloan.spec.ts | 8 ++- test/helpers/actions.ts | 52 +++++++++------- test/helpers/scenario-engine.ts | 6 +- test/pausable-functions.spec.ts | 17 ------ test/scenario.spec.ts | 2 +- test/stable-token.spec.ts | 6 +- test/variable-debt-token.spec.ts | 6 +- 20 files changed, 178 insertions(+), 212 deletions(-) diff --git a/contracts/interfaces/ILendingPool.sol b/contracts/interfaces/ILendingPool.sol index 83e40cd9..17be5799 100644 --- a/contracts/interfaces/ILendingPool.sol +++ b/contracts/interfaces/ILendingPool.sol @@ -33,13 +33,6 @@ interface ILendingPool { **/ event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount); - event BorrowAllowanceDelegated( - address indexed fromUser, - address indexed toUser, - address[] assets, - uint256[] interestRateModes, - uint256[] amounts - ); /** * @dev emitted on borrow * @param reserve the address of the reserve @@ -196,27 +189,6 @@ interface ILendingPool { address to ) external; - /** - * @dev Sets allowance to borrow on a certain type of debt assets for a certain user address - * @param assets The underlying asset of each debt token - * @param user The user to give allowance to - * @param interestRateModes Types of debt: 1 for stable, 2 for variable - * @param amounts Allowance amounts to borrow - **/ - function delegateBorrowAllowance( - address[] calldata assets, - address user, - uint256[] calldata interestRateModes, - uint256[] calldata amounts - ) external; - - function getBorrowAllowance( - address fromUser, - address toUser, - address asset, - uint256 interestRateMode - ) external view returns (uint256); - /** * @dev Allows users to borrow a specific amount of the reserve currency, provided that the borrower * already deposited enough collateral. diff --git a/contracts/lendingpool/LendingPool.sol b/contracts/lendingpool/LendingPool.sol index 4c70ca88..b2afa781 100644 --- a/contracts/lendingpool/LendingPool.sol +++ b/contracts/lendingpool/LendingPool.sol @@ -166,53 +166,6 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage emit Withdraw(asset, msg.sender, to, amountToWithdraw); } - /** - * @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, - address asset, - uint256 interestRateMode - ) external override view returns (uint256) { - return - _borrowAllowance[_reserves[asset].getDebtTokenAddress(interestRateMode)][fromUser][toUser]; - } - - /** - * @dev Sets allowance to borrow on a certain type of debt assets for a certain user address - * @param assets The underlying asset of each debt token - * @param user The user to give allowance to - * @param interestRateModes Types of debt: 1 for stable, 2 for variable - * @param amounts Allowance amounts to borrow - **/ - function delegateBorrowAllowance( - address[] calldata assets, - address user, - uint256[] calldata interestRateModes, - uint256[] calldata amounts - ) external override { - _whenNotPaused(); - - uint256 countAssets = assets.length; - require( - countAssets == interestRateModes.length && countAssets == amounts.length, - Errors.LP_INCONSISTENT_PARAMS_LENGTH - ); - - for (uint256 i = 0; i < countAssets; i++) { - address debtToken = _reserves[assets[i]].getDebtTokenAddress(interestRateModes[i]); - _borrowAllowance[debtToken][msg.sender][user] = amounts[i]; - } - - emit BorrowAllowanceDelegated(msg.sender, user, assets, interestRateModes, amounts); - } - /** * @dev Allows users to borrow a specific amount of the reserve currency, provided that the borrower * already deposited enough collateral. @@ -338,6 +291,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage //burn stable rate tokens, mint variable rate tokens IStableDebtToken(reserve.stableDebtTokenAddress).burn(msg.sender, stableDebt); IVariableDebtToken(reserve.variableDebtTokenAddress).mint( + msg.sender, msg.sender, stableDebt, reserve.variableBorrowIndex @@ -350,6 +304,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage reserve.variableBorrowIndex ); IStableDebtToken(reserve.stableDebtTokenAddress).mint( + msg.sender, msg.sender, variableDebt, reserve.currentStableBorrowRate @@ -411,6 +366,7 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage IStableDebtToken(address(stableDebtToken)).burn(user, stableBorrowBalance); IStableDebtToken(address(stableDebtToken)).mint( + user, user, stableBorrowBalance, reserve.currentStableBorrowRate @@ -898,14 +854,6 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage oracle ); - if (vars.onBehalfOf != msg.sender) { - address debtToken = reserve.getDebtTokenAddress(vars.interestRateMode); - - _borrowAllowance[debtToken][vars.onBehalfOf][msg.sender] = _borrowAllowance[debtToken][vars - .onBehalfOf][msg.sender] - .sub(vars.amount, Errors.LP_BORROW_ALLOWANCE_NOT_ENOUGH); - } - reserve.updateState(); //caching the current stable borrow rate @@ -918,12 +866,14 @@ contract LendingPool is VersionedInitializable, ILendingPool, LendingPoolStorage currentStableRate = reserve.currentStableBorrowRate; isFirstBorrowing = IStableDebtToken(reserve.stableDebtTokenAddress).mint( + vars.user, vars.onBehalfOf, vars.amount, currentStableRate ); } else { isFirstBorrowing = IVariableDebtToken(reserve.variableDebtTokenAddress).mint( + vars.user, vars.onBehalfOf, vars.amount, reserve.variableBorrowIndex diff --git a/contracts/lendingpool/LendingPoolStorage.sol b/contracts/lendingpool/LendingPoolStorage.sol index ceeadd39..5ea45c6e 100644 --- a/contracts/lendingpool/LendingPoolStorage.sol +++ b/contracts/lendingpool/LendingPoolStorage.sol @@ -15,8 +15,6 @@ contract LendingPoolStorage { mapping(address => ReserveLogic.ReserveData) internal _reserves; mapping(address => UserConfiguration.Map) internal _usersConfig; - // debt token address => user who gives allowance => user who receives allowance => amount - mapping(address => mapping(address => mapping(address => uint256))) internal _borrowAllowance; // the list of the available reserves, structured as a mapping for gas savings reasons mapping(uint256 => address) internal _reservesList; diff --git a/contracts/libraries/helpers/Errors.sol b/contracts/libraries/helpers/Errors.sol index 2b173fff..76d1b043 100644 --- a/contracts/libraries/helpers/Errors.sol +++ b/contracts/libraries/helpers/Errors.sol @@ -19,6 +19,7 @@ pragma solidity ^0.6.8; library Errors { //common errors string public constant CALLER_NOT_AAVE_ADMIN = '33'; // 'The caller must be the aave admin' + string public constant BORROW_ALLOWANCE_NOT_ENOUGH = '59'; // User borrows on behalf, but allowance are too small //contract specific errors string public constant VL_AMOUNT_NOT_GREATER_THAN_0 = '1'; // 'Amount must be greater than 0' @@ -79,7 +80,6 @@ library Errors { string public constant AT_INVALID_MINT_AMOUNT = '56'; //invalid amount to mint string public constant LP_FAILED_REPAY_WITH_COLLATERAL = '57'; string public constant AT_INVALID_BURN_AMOUNT = '58'; //invalid amount to burn - string public constant LP_BORROW_ALLOWANCE_NOT_ENOUGH = '59'; // User borrows on behalf, but allowance are too small string public constant LP_FAILED_COLLATERAL_SWAP = '60'; string public constant LP_INVALID_EQUAL_ASSETS_TO_SWAP = '61'; string public constant LP_REENTRANCY_NOT_ALLOWED = '62'; diff --git a/contracts/libraries/logic/ReserveLogic.sol b/contracts/libraries/logic/ReserveLogic.sol index f3d13628..63cc0dd6 100644 --- a/contracts/libraries/logic/ReserveLogic.sol +++ b/contracts/libraries/logic/ReserveLogic.sol @@ -119,28 +119,6 @@ library ReserveLogic { return cumulated; } - /** - * @dev returns an address of the debt token used for particular interest rate mode on asset. - * @param reserve the reserve object - * @param interestRateMode - STABLE or VARIABLE from ReserveLogic.InterestRateMode enum - * @return an address of the corresponding debt token from reserve configuration - **/ - function getDebtTokenAddress(ReserveLogic.ReserveData storage reserve, uint256 interestRateMode) - external - view - returns (address) - { - require( - ReserveLogic.InterestRateMode.STABLE == ReserveLogic.InterestRateMode(interestRateMode) || - ReserveLogic.InterestRateMode.VARIABLE == ReserveLogic.InterestRateMode(interestRateMode), - Errors.VL_INVALID_INTEREST_RATE_MODE_SELECTED - ); - return - ReserveLogic.InterestRateMode.STABLE == ReserveLogic.InterestRateMode(interestRateMode) - ? reserve.stableDebtTokenAddress - : reserve.variableDebtTokenAddress; - } - /** * @dev Updates the liquidity cumulative index Ci and variable borrow cumulative index Bvc. Refer to the whitepaper for * a formal specification. diff --git a/contracts/tokenization/StableDebtToken.sol b/contracts/tokenization/StableDebtToken.sol index e6105dbb..dfb73e0f 100644 --- a/contracts/tokenization/StableDebtToken.sol +++ b/contracts/tokenization/StableDebtToken.sol @@ -5,6 +5,7 @@ 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 @@ -16,9 +17,10 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { uint256 public constant DEBT_TOKEN_REVISION = 0x1; - uint256 private _avgStableRate; - mapping(address => uint40) _timestamps; - uint40 _totalSupplyTimestamp; + uint256 internal _avgStableRate; + mapping(address => uint40) internal _timestamps; + mapping(address => uint256) internal _usersData; + uint40 internal _totalSupplyTimestamp; constructor( address pool, @@ -95,17 +97,20 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { **/ function mint( address user, + address onBehalfOf, uint256 amount, uint256 rate ) external override onlyLendingPool returns (bool) { MintLocalVars memory vars; + if (user != onBehalfOf) { + _decreaseBorrowAllowance(onBehalfOf, user, amount); + } + + console.log('Invoked mint for %s and %s', user, onBehalfOf); + //cumulates the user debt - ( - uint256 previousBalance, - uint256 currentBalance, - uint256 balanceIncrease - ) = _calculateBalanceIncrease(user); + (, uint256 currentBalance, uint256 balanceIncrease) = _calculateBalanceIncrease(onBehalfOf); //accrueing the interest accumulation to the stored total supply and caching it vars.previousSupply = totalSupply(); @@ -115,17 +120,17 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { vars.amountInRay = amount.wadToRay(); //calculates the new stable rate for the user - vars.newStableRate = _usersData[user] + vars.newStableRate = _usersData[onBehalfOf] .rayMul(currentBalance.wadToRay()) .add(vars.amountInRay.rayMul(rate)) .rayDiv(currentBalance.add(amount).wadToRay()); require(vars.newStableRate < (1 << 128), 'Debt token: stable rate overflow'); - _usersData[user] = vars.newStableRate; + _usersData[onBehalfOf] = vars.newStableRate; //updating the user and supply timestamp //solium-disable-next-line - _totalSupplyTimestamp = _timestamps[user] = uint40(block.timestamp); + _totalSupplyTimestamp = _timestamps[onBehalfOf] = uint40(block.timestamp); //calculates the updated average stable rate vars.currentAvgStableRate = _avgStableRate = vars @@ -134,13 +139,14 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { .add(rate.rayMul(vars.amountInRay)) .rayDiv(vars.nextSupply.wadToRay()); - _mint(user, amount.add(balanceIncrease), vars.previousSupply); + _mint(onBehalfOf, amount.add(balanceIncrease), vars.previousSupply); // transfer event to track balances - emit Transfer(address(0), user, amount); + emit Transfer(address(0), onBehalfOf, amount); emit Mint( user, + onBehalfOf, amount, currentBalance, balanceIncrease, @@ -158,11 +164,7 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { * @param amount the amount of debt tokens to mint **/ function burn(address user, uint256 amount) external override onlyLendingPool { - ( - uint256 previousBalance, - uint256 currentBalance, - uint256 balanceIncrease - ) = _calculateBalanceIncrease(user); + (, uint256 currentBalance, uint256 balanceIncrease) = _calculateBalanceIncrease(user); uint256 previousSupply = totalSupply(); uint256 newStableRate = 0; diff --git a/contracts/tokenization/VariableDebtToken.sol b/contracts/tokenization/VariableDebtToken.sol index 6f16082b..ef429b53 100644 --- a/contracts/tokenization/VariableDebtToken.sol +++ b/contracts/tokenization/VariableDebtToken.sol @@ -55,17 +55,22 @@ contract VariableDebtToken is DebtTokenBase, IVariableDebtToken { **/ function mint( address user, + address onBehalfOf, uint256 amount, uint256 index ) external override onlyLendingPool returns (bool) { - uint256 previousBalance = super.balanceOf(user); + if (user != onBehalfOf) { + _decreaseBorrowAllowance(onBehalfOf, user, amount); + } + + uint256 previousBalance = super.balanceOf(onBehalfOf); uint256 amountScaled = amount.rayDiv(index); require(amountScaled != 0, Errors.AT_INVALID_MINT_AMOUNT); - _mint(user, amountScaled); + _mint(onBehalfOf, amountScaled); - emit Transfer(address(0), user, amount); - emit Mint(user, amount, index); + emit Transfer(address(0), onBehalfOf, amount); + emit Mint(user, onBehalfOf, amount, index); return previousBalance == 0; } diff --git a/contracts/tokenization/base/DebtTokenBase.sol b/contracts/tokenization/base/DebtTokenBase.sol index 723bb5d2..b1b9963c 100644 --- a/contracts/tokenization/base/DebtTokenBase.sol +++ b/contracts/tokenization/base/DebtTokenBase.sol @@ -15,9 +15,17 @@ import {Errors} from '../../libraries/helpers/Errors.sol'; */ abstract contract DebtTokenBase is IncentivizedERC20, VersionedInitializable { + event BorrowAllowanceDelegated( + address indexed fromUser, + address indexed toUser, + address asset, + uint256 amount + ); + address public immutable UNDERLYING_ASSET_ADDRESS; ILendingPool public immutable POOL; - mapping(address => uint256) internal _usersData; + + mapping(address => mapping(address => uint256)) internal _borrowAllowances; /** * @dev Only lending pool can call functions marked by this modifier @@ -58,6 +66,28 @@ abstract contract DebtTokenBase is IncentivizedERC20, VersionedInitializable { _setDecimals(decimals); } + /** + * @dev delegates borrowing power to a user on the specific debt token + * @param delegatee the address receiving the delegated borrowing power + * @param amount the maximum amount being delegated. Delegation will still + * respect the liquidation constraints (even if delegated, a delegatee cannot + * force a delegator HF to go below 1) + **/ + function approveDelegation(address delegatee, uint256 amount) external { + _borrowAllowances[_msgSender()][delegatee] = amount; + emit BorrowAllowanceDelegated(_msgSender(), delegatee, UNDERLYING_ASSET_ADDRESS, amount); + } + + /** + * @dev returns the borrow allowance of the user + * @param fromUser The user to giving allowance + * @param toUser The user to give allowance to + * @return the current allowance of toUser + **/ + function borrowAllowance(address fromUser, address toUser) external view returns (uint256) { + return _borrowAllowances[fromUser][toUser]; + } + /** * @dev Being non transferrable, the debt token does not implement any of the * standard ERC20 functions for transfer and allowance. @@ -118,4 +148,19 @@ abstract contract DebtTokenBase is IncentivizedERC20, VersionedInitializable { subtractedValue; revert('ALLOWANCE_NOT_SUPPORTED'); } + + function _decreaseBorrowAllowance( + address delegator, + address delegatee, + uint256 amount + ) internal { + uint256 newAllowance = _borrowAllowances[delegator][delegatee].sub( + amount, + Errors.BORROW_ALLOWANCE_NOT_ENOUGH + ); + + _borrowAllowances[delegator][delegatee] = newAllowance; + + emit BorrowAllowanceDelegated(delegator, delegatee, UNDERLYING_ASSET_ADDRESS, newAllowance); + } } diff --git a/contracts/tokenization/interfaces/IAToken.sol b/contracts/tokenization/interfaces/IAToken.sol index 055e3f5d..13cf6cb7 100644 --- a/contracts/tokenization/interfaces/IAToken.sol +++ b/contracts/tokenization/interfaces/IAToken.sol @@ -5,6 +5,27 @@ import {IERC20} from '../../dependencies/openzeppelin/contracts/IERC20.sol'; import {IScaledBalanceToken} from './IScaledBalanceToken.sol'; interface IAToken is IERC20, IScaledBalanceToken { + /** + * @dev emitted after the mint action + * @param from the address performing the mint + * @param value the amount to be minted + * @param index the last index of the reserve + **/ + event Mint(address indexed from, uint256 value, uint256 index); + + /** + * @dev mints aTokens to user + * only lending pools can call this function + * @param user the address receiving the minted tokens + * @param amount the amount of tokens to mint + * @param index the liquidity index + */ + function mint( + address user, + uint256 amount, + uint256 index + ) external returns (bool); + /** * @dev emitted after aTokens are burned * @param from the address performing the redeem diff --git a/contracts/tokenization/interfaces/IScaledBalanceToken.sol b/contracts/tokenization/interfaces/IScaledBalanceToken.sol index 604706c2..ee1a132c 100644 --- a/contracts/tokenization/interfaces/IScaledBalanceToken.sol +++ b/contracts/tokenization/interfaces/IScaledBalanceToken.sol @@ -2,27 +2,6 @@ pragma solidity ^0.6.8; interface IScaledBalanceToken { - /** - * @dev emitted after the mint action - * @param from the address performing the mint - * @param value the amount to be minted - * @param index the last index of the reserve - **/ - event Mint(address indexed from, uint256 value, uint256 index); - - /** - * @dev mints aTokens to user - * only lending pools can call this function - * @param user the address receiving the minted tokens - * @param amount the amount of tokens to mint - * @param index the liquidity index - */ - function mint( - address user, - uint256 amount, - uint256 index - ) external returns (bool); - /** * @dev returns the principal balance of the user. The principal balance is the last * updated stored balance, which does not consider the perpetually accruing interest. diff --git a/contracts/tokenization/interfaces/IStableDebtToken.sol b/contracts/tokenization/interfaces/IStableDebtToken.sol index 81c1b586..af71aab2 100644 --- a/contracts/tokenization/interfaces/IStableDebtToken.sol +++ b/contracts/tokenization/interfaces/IStableDebtToken.sol @@ -15,7 +15,8 @@ pragma solidity ^0.6.8; interface IStableDebtToken { /** * @dev emitted when new stable debt is minted - * @param user the address of the user + * @param user the address of the user who triggered the minting + * @param onBehalfOf the address of the user * @param amount the amount minted * @param currentBalance the current balance of the user * @param balanceIncrease the the increase in balance since the last action of the user @@ -25,6 +26,7 @@ interface IStableDebtToken { **/ event Mint( address indexed user, + address indexed onBehalfOf, uint256 amount, uint256 currentBalance, uint256 balanceIncrease, @@ -60,6 +62,7 @@ interface IStableDebtToken { **/ function mint( address user, + address onBehalfOf, uint256 amount, uint256 rate ) external returns (bool); diff --git a/contracts/tokenization/interfaces/IVariableDebtToken.sol b/contracts/tokenization/interfaces/IVariableDebtToken.sol index f1988be8..c01b50ce 100644 --- a/contracts/tokenization/interfaces/IVariableDebtToken.sol +++ b/contracts/tokenization/interfaces/IVariableDebtToken.sol @@ -9,6 +9,29 @@ import {IScaledBalanceToken} from './IScaledBalanceToken.sol'; * @notice defines the basic interface for a variable debt token. **/ interface IVariableDebtToken is IScaledBalanceToken { + /** + * @dev emitted after the mint action + * @param from the address performing the mint + * @param onBehalfOf the address of the user on which behalf minting has been performed + * @param value the amount to be minted + * @param index the last index of the reserve + **/ + event Mint(address indexed from, address indexed onBehalfOf, uint256 value, uint256 index); + + /** + * @dev mints aTokens to user + * only lending pools can call this function + * @param user the address receiving the minted tokens + * @param amount the amount of tokens to mint + * @param index the liquidity index + */ + function mint( + address user, + address onBehalfOf, + uint256 amount, + uint256 index + ) external returns (bool); + /** * @dev emitted when variable debt is burnt * @param user the user which debt has been burned diff --git a/deployed-contracts.json b/deployed-contracts.json index d1b2f772..c2cbd017 100644 --- a/deployed-contracts.json +++ b/deployed-contracts.json @@ -163,26 +163,25 @@ }, "ReserveLogic": { "buidlerevm": { - "address": "0x78Ee8Fb9fE5abD5e347Fc94c2fb85596d1f60e3c", + "address": "0xFAe0fd738dAbc8a0426F47437322b6d026A9FD95", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "GenericLogic": { "buidlerevm": { - "address": "0x920d847fE49E54C19047ba8bc236C45A8068Bca7", + "address": "0x6082731fdAba4761277Fb31299ebC782AD3bCf24", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "ValidationLogic": { "buidlerevm": { - "address": "0xA4765Ff72A9F3CfE73089bb2c3a41B838DF71574", + "address": "0x8456161947DFc1fC159A0B26c025cD2b4bba0c3e", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "LendingPool": { "buidlerevm": { - "address": "0x35c1419Da7cf0Ff885B8Ef8EA9242FEF6800c99b", - "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" + "address": "0xD9273d497eDBC967F39d419461CfcF382a0A822e" } }, "LendingPoolConfigurator": { @@ -198,7 +197,7 @@ }, "ATokensAndRatesHelper": { "buidlerevm": { - "address": "0x920d847fE49E54C19047ba8bc236C45A8068Bca7", + "address": "0x06bA8d8af0dF898D0712DffFb0f862cC51AF45c2", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, diff --git a/test/flashloan.spec.ts b/test/flashloan.spec.ts index 887479a8..b5978d1a 100644 --- a/test/flashloan.spec.ts +++ b/test/flashloan.spec.ts @@ -454,10 +454,12 @@ makeSuite('LendingPool FlashLoan function', (testEnv: TestEnv) => { const flashAmount = ethers.utils.parseEther('0.8'); + const reserveData = await pool.getReserveData(weth.address); + + const stableDebtToken = await getVariableDebtToken(reserveData.stableDebtTokenAddress); + // Deposited for onBehalfOf user already, delegate borrow allowance - await pool - .connect(onBehalfOf.signer) - .delegateBorrowAllowance([weth.address], caller.address, [1], [flashAmount]); + await stableDebtToken.connect(onBehalfOf.signer).approveDelegation(caller.address, flashAmount); await _mockFlashLoanReceiver.setFailExecutionTransfer(true); diff --git a/test/helpers/actions.ts b/test/helpers/actions.ts index d998962b..6d48e2b1 100644 --- a/test/helpers/actions.ts +++ b/test/helpers/actions.ts @@ -18,7 +18,12 @@ import { import {getReserveAddressFromSymbol, getReserveData, getUserData} from './utils/helpers'; import {convertToCurrencyDecimals} from '../../helpers/contracts-helpers'; -import {getAToken, getMintableErc20} from '../../helpers/contracts-getters'; +import { + getAToken, + getMintableErc20, + getStableDebtToken, + getVariableDebtToken, +} from '../../helpers/contracts-getters'; import {MAX_UINT_AMOUNT, ONE_YEAR} from '../../helpers/constants'; import {SignerWithAddress, TestEnv} from './make-suite'; import {BRE, increaseTime, timeLatest, waitForTx} from '../../helpers/misc-utils'; @@ -277,9 +282,9 @@ export const withdraw = async ( }; export const delegateBorrowAllowance = async ( - reserveSymbols: string[], - amounts: string[], - interestRateModes: string[], + reserve: string, + amount: string, + interestRateMode: string, user: SignerWithAddress, receiver: tEthereumAddress, expectedResult: string, @@ -288,32 +293,33 @@ export const delegateBorrowAllowance = async ( ) => { const {pool} = testEnv; - const reserves: tEthereumAddress[] = []; - const amountsToDelegate: tEthereumAddress[] = []; - for (const reserveSymbol of reserveSymbols) { - const newLength = reserves.push(await getReserveAddressFromSymbol(reserveSymbol)); - amountsToDelegate.push( - await ( - await convertToCurrencyDecimals(reserves[newLength - 1], amounts[newLength - 1]) - ).toString() - ); - } + const reserveAddress: tEthereumAddress = await getReserveAddressFromSymbol(reserve); - const delegateAllowancePromise = pool + const amountToDelegate: string = await ( + await convertToCurrencyDecimals(reserveAddress, amount) + ).toString(); + + const reserveData = await pool.getReserveData(reserveAddress); + + const debtToken = + interestRateMode === 'stable' + ? await getStableDebtToken(reserveData.stableDebtTokenAddress) + : await getVariableDebtToken(reserveData.variableDebtTokenAddress); + + const delegateAllowancePromise = debtToken .connect(user.signer) - .delegateBorrowAllowance(reserves, receiver, interestRateModes, amountsToDelegate); + .approveDelegation(receiver, amountToDelegate); + if (expectedResult === 'revert') { await expect(delegateAllowancePromise, revertMessage).to.be.reverted; return; } else { await delegateAllowancePromise; - for (const [i, reserve] of reserves.entries()) { - expect( - ( - await pool.getBorrowAllowance(user.address, receiver, reserve, interestRateModes[i]) - ).toString() - ).to.be.equal(amountsToDelegate[i], 'borrowAllowance are set incorrectly'); - } + const allowance = await debtToken.borrowAllowance(user.address, receiver); + expect(allowance.toString()).to.be.equal( + amountToDelegate, + 'borrowAllowance are set incorrectly' + ); } }; diff --git a/test/helpers/scenario-engine.ts b/test/helpers/scenario-engine.ts index fe2e302a..bb4f82f8 100644 --- a/test/helpers/scenario-engine.ts +++ b/test/helpers/scenario-engine.ts @@ -121,9 +121,9 @@ const executeAction = async (action: Action, users: SignerWithAddress[], testEnv } await delegateBorrowAllowance( - [reserve], - [amount], - [rateMode], + reserve, + amount, + rateMode, user, toUser, expected, diff --git a/test/pausable-functions.spec.ts b/test/pausable-functions.spec.ts index 9c7f6473..01383c90 100644 --- a/test/pausable-functions.spec.ts +++ b/test/pausable-functions.spec.ts @@ -122,23 +122,6 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { await configurator.setPoolPause(false); }); - it('DelegateBorrowAllowance', async () => { - const {pool, dai, users, configurator} = testEnv; - - const user = users[1]; - const toUser = users[2]; - // Pause the pool - await configurator.setPoolPause(true); - - // Try to execute liquidation - await expect( - pool.connect(user.signer).delegateBorrowAllowance([dai.address], toUser.address, ['1'], ['1']) - ).revertedWith(LP_IS_PAUSED); - - // Unpause the pool - await configurator.setPoolPause(false); - }); - it('Borrow', async () => { const {pool, dai, users, configurator} = testEnv; diff --git a/test/scenario.spec.ts b/test/scenario.spec.ts index 50793c0c..82631141 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[] = [`credit-delegation.json`]; fs.readdirSync(scenarioFolder).forEach((file) => { if (selectedScenarios.length > 0 && !selectedScenarios.includes(file)) return; diff --git a/test/stable-token.spec.ts b/test/stable-token.spec.ts index 02348d8b..fecc3e78 100644 --- a/test/stable-token.spec.ts +++ b/test/stable-token.spec.ts @@ -16,9 +16,9 @@ makeSuite('Stable debt token tests', (testEnv: TestEnv) => { const stableDebtContract = await getStableDebtToken(daiStableDebtTokenAddress); - await expect(stableDebtContract.mint(deployer.address, '1', '1')).to.be.revertedWith( - AT_CALLER_MUST_BE_LENDING_POOL - ); + await expect( + stableDebtContract.mint(deployer.address, deployer.address, '1', '1') + ).to.be.revertedWith(AT_CALLER_MUST_BE_LENDING_POOL); }); it('Tries to invoke burn not being the LendingPool', async () => { diff --git a/test/variable-debt-token.spec.ts b/test/variable-debt-token.spec.ts index 5e21f939..6c177096 100644 --- a/test/variable-debt-token.spec.ts +++ b/test/variable-debt-token.spec.ts @@ -15,9 +15,9 @@ makeSuite('Variable debt token tests', (testEnv: TestEnv) => { const variableDebtContract = await getVariableDebtToken(daiVariableDebtTokenAddress); - await expect(variableDebtContract.mint(deployer.address, '1', '1')).to.be.revertedWith( - AT_CALLER_MUST_BE_LENDING_POOL - ); + await expect( + variableDebtContract.mint(deployer.address, deployer.address, '1', '1') + ).to.be.revertedWith(AT_CALLER_MUST_BE_LENDING_POOL); }); it('Tries to invoke burn not being the LendingPool', async () => { From add6cad5c33a9e83514070fe08f06b564a99fea0 Mon Sep 17 00:00:00 2001 From: emilio Date: Wed, 4 Nov 2020 11:12:26 +0100 Subject: [PATCH 2/4] Fixed scenarios, tests, removed console.log --- contracts/tokenization/StableDebtToken.sol | 3 --- test/helpers/actions.ts | 8 +++---- test/helpers/scenarios/credit-delegation.json | 21 ++----------------- test/scenario.spec.ts | 2 +- 4 files changed, 7 insertions(+), 27 deletions(-) diff --git a/contracts/tokenization/StableDebtToken.sol b/contracts/tokenization/StableDebtToken.sol index dfb73e0f..89430392 100644 --- a/contracts/tokenization/StableDebtToken.sol +++ b/contracts/tokenization/StableDebtToken.sol @@ -5,7 +5,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 @@ -107,8 +106,6 @@ contract StableDebtToken is IStableDebtToken, DebtTokenBase { _decreaseBorrowAllowance(onBehalfOf, user, amount); } - console.log('Invoked mint for %s and %s', user, onBehalfOf); - //cumulates the user debt (, uint256 currentBalance, uint256 balanceIncrease) = _calculateBalanceIncrease(onBehalfOf); diff --git a/test/helpers/actions.ts b/test/helpers/actions.ts index 6d48e2b1..e44fc07f 100644 --- a/test/helpers/actions.ts +++ b/test/helpers/actions.ts @@ -302,7 +302,7 @@ export const delegateBorrowAllowance = async ( const reserveData = await pool.getReserveData(reserveAddress); const debtToken = - interestRateMode === 'stable' + interestRateMode === '1' ? await getStableDebtToken(reserveData.stableDebtTokenAddress) : await getVariableDebtToken(reserveData.variableDebtTokenAddress); @@ -310,15 +310,15 @@ export const delegateBorrowAllowance = async ( .connect(user.signer) .approveDelegation(receiver, amountToDelegate); - if (expectedResult === 'revert') { - await expect(delegateAllowancePromise, revertMessage).to.be.reverted; + if (expectedResult === 'revert' && revertMessage) { + await expect(delegateAllowancePromise, revertMessage).to.be.revertedWith(revertMessage); return; } else { await delegateAllowancePromise; const allowance = await debtToken.borrowAllowance(user.address, receiver); expect(allowance.toString()).to.be.equal( amountToDelegate, - 'borrowAllowance are set incorrectly' + 'borrowAllowance is set incorrectly' ); } }; diff --git a/test/helpers/scenarios/credit-delegation.json b/test/helpers/scenarios/credit-delegation.json index a67924ee..a0aecf1b 100644 --- a/test/helpers/scenarios/credit-delegation.json +++ b/test/helpers/scenarios/credit-delegation.json @@ -68,7 +68,7 @@ "borrowRateMode": "stable" }, "expected": "revert", - "revertMessage": "54" + "revertMessage": "59" } ] }, @@ -96,7 +96,7 @@ "borrowRateMode": "variable" }, "expected": "revert", - "revertMessage": "54" + "revertMessage": "59" } ] }, @@ -126,23 +126,6 @@ "expected": "success" } ] - }, - { - "description": "User 0 delegates borrowing of 1 WETH to user 2 with wrong borrowRateMode, revert expected", - "actions": [ - { - "name": "delegateBorrowAllowance", - "args": { - "reserve": "WETH", - "amount": "1", - "user": "0", - "borrowRateMode": "random", - "toUser": "2" - }, - "expected": "revert", - "revertMessage": "8" - } - ] } ] } diff --git a/test/scenario.spec.ts b/test/scenario.spec.ts index 82631141..50793c0c 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[] = [`credit-delegation.json`]; +const selectedScenarios: string[] = []; fs.readdirSync(scenarioFolder).forEach((file) => { if (selectedScenarios.length > 0 && !selectedScenarios.includes(file)) return; From 69c3d5b9b77e4459e09627b611945d1889004d61 Mon Sep 17 00:00:00 2001 From: emilio Date: Thu, 5 Nov 2020 12:35:50 +0100 Subject: [PATCH 3/4] Adds Emergency admin --- config/commons.ts | 14 ++++- .../LendingPoolAddressesProvider.sol | 22 +++++-- .../ILendingPoolAddressesProvider.sol | 11 +++- .../lendingpool/LendingPoolConfigurator.sol | 57 ++++++++++------- contracts/libraries/helpers/Errors.sol | 5 +- .../tokenization/DelegationAwareAToken.sol | 8 +-- deployed-contracts.json | 34 +++++----- helpers/configuration.ts | 19 +++++- helpers/init-helpers.ts | 12 ++-- helpers/types.ts | 11 ++-- tasks/dev/2_address_provider_registry.ts | 2 +- tasks/full/1_address_provider_registry.ts | 13 +++- test/__setup.spec.ts | 13 +++- test/configurator.spec.ts | 62 +++++++++---------- test/delegation-aware-atoken.spec.ts | 2 +- test/lending-pool-addresses-provider.spec.ts | 2 +- test/pausable-functions.spec.ts | 44 ++++++------- test/upgradeability.spec.ts | 8 +-- 18 files changed, 203 insertions(+), 136 deletions(-) diff --git a/config/commons.ts b/config/commons.ts index 71c60c66..7dfd7fe0 100644 --- a/config/commons.ts +++ b/config/commons.ts @@ -118,15 +118,23 @@ export const CommonsConfig: ICommonConfiguration = { // COMMON PROTOCOL ADDRESSES ACROSS POOLS // ---------------- - // If lendingPoolManagerAddress is set, will take priority over lendingPoolManagerAddressIndex - AaveAdmin: { + // If PoolAdmin/emergencyAdmin is set, will take priority over PoolAdminIndex/emergencyAdminIndex + PoolAdmin: { [eEthereumNetwork.coverage]: undefined, [eEthereumNetwork.buidlerevm]: undefined, [eEthereumNetwork.kovan]: undefined, [eEthereumNetwork.ropsten]: undefined, [eEthereumNetwork.main]: undefined, }, - AaveAdminIndex: 0, + PoolAdminIndex: 0, + EmergencyAdmin: { + [eEthereumNetwork.coverage]: undefined, + [eEthereumNetwork.buidlerevm]: undefined, + [eEthereumNetwork.kovan]: undefined, + [eEthereumNetwork.ropsten]: undefined, + [eEthereumNetwork.main]: undefined, + }, + EmergencyAdminIndex: 1, ProviderRegistry: { [eEthereumNetwork.kovan]: '', [eEthereumNetwork.ropsten]: '', diff --git a/contracts/configuration/LendingPoolAddressesProvider.sol b/contracts/configuration/LendingPoolAddressesProvider.sol index 38aa1280..b392d970 100644 --- a/contracts/configuration/LendingPoolAddressesProvider.sol +++ b/contracts/configuration/LendingPoolAddressesProvider.sol @@ -20,7 +20,8 @@ contract LendingPoolAddressesProvider is Ownable, ILendingPoolAddressesProvider bytes32 private constant LENDING_POOL = 'LENDING_POOL'; bytes32 private constant LENDING_POOL_CONFIGURATOR = 'LENDING_POOL_CONFIGURATOR'; - bytes32 private constant AAVE_ADMIN = 'AAVE_ADMIN'; + bytes32 private constant POOL_ADMIN = 'POOL_ADMIN'; + bytes32 private constant EMERGENCY_ADMIN = 'EMERGENCY_ADMIN'; bytes32 private constant LENDING_POOL_COLLATERAL_MANAGER = 'COLLATERAL_MANAGER'; bytes32 private constant PRICE_ORACLE = 'PRICE_ORACLE'; bytes32 private constant LENDING_RATE_ORACLE = 'LENDING_RATE_ORACLE'; @@ -113,13 +114,22 @@ contract LendingPoolAddressesProvider is Ownable, ILendingPoolAddressesProvider * hence the upgradable proxy pattern is not used **/ - function getAaveAdmin() external override view returns (address) { - return getAddress(AAVE_ADMIN); + function getPoolAdmin() external override view returns (address) { + return getAddress(POOL_ADMIN); } - function setAaveAdmin(address aaveAdmin) external override onlyOwner { - _addresses[AAVE_ADMIN] = aaveAdmin; - emit AaveAdminUpdated(aaveAdmin); + function setPoolAdmin(address admin) external override onlyOwner { + _addresses[POOL_ADMIN] = admin; + emit ConfigurationAdminUpdated(admin); + } + + function getEmergencyAdmin() external override view returns (address) { + return getAddress(EMERGENCY_ADMIN); + } + + function setEmergencyAdmin(address emergencyAdmin) external override onlyOwner { + _addresses[EMERGENCY_ADMIN] = emergencyAdmin; + emit EmergencyAdminUpdated(emergencyAdmin); } function getPriceOracle() external override view returns (address) { diff --git a/contracts/interfaces/ILendingPoolAddressesProvider.sol b/contracts/interfaces/ILendingPoolAddressesProvider.sol index 53ed9873..c0d180e3 100644 --- a/contracts/interfaces/ILendingPoolAddressesProvider.sol +++ b/contracts/interfaces/ILendingPoolAddressesProvider.sol @@ -8,7 +8,8 @@ pragma solidity ^0.6.8; interface ILendingPoolAddressesProvider { event LendingPoolUpdated(address indexed newAddress); - event AaveAdminUpdated(address indexed newAddress); + event ConfigurationAdminUpdated(address indexed newAddress); + event EmergencyAdminUpdated(address indexed newAddress); event LendingPoolConfiguratorUpdated(address indexed newAddress); event LendingPoolCollateralManagerUpdated(address indexed newAddress); event EthereumAddressUpdated(address indexed newAddress); @@ -37,9 +38,13 @@ interface ILendingPoolAddressesProvider { function setLendingPoolCollateralManager(address manager) external; - function getAaveAdmin() external view returns (address); + function getPoolAdmin() external view returns (address); - function setAaveAdmin(address aaveAdmin) external; + function setPoolAdmin(address admin) external; + + function getEmergencyAdmin() external view returns (address); + + function setEmergencyAdmin(address admin) external; function getPriceOracle() external view returns (address); diff --git a/contracts/lendingpool/LendingPoolConfigurator.sol b/contracts/lendingpool/LendingPoolConfigurator.sol index b336ed51..e8f79502 100644 --- a/contracts/lendingpool/LendingPoolConfigurator.sol +++ b/contracts/lendingpool/LendingPoolConfigurator.sol @@ -188,10 +188,21 @@ contract LendingPoolConfigurator is VersionedInitializable { ILendingPool internal pool; /** - * @dev only the aave admin can call functions affected by this modifier + * @dev only the pool admin can call functions affected by this modifier **/ - modifier onlyAaveAdmin { - require(addressesProvider.getAaveAdmin() == msg.sender, Errors.CALLER_NOT_AAVE_ADMIN); + modifier onlyPoolAdmin { + require(addressesProvider.getPoolAdmin() == msg.sender, Errors.CALLER_NOT_POOL_ADMIN); + _; + } + + /** + * @dev only the emergency admin can call functions affected by this modifier + **/ + modifier onlyEmergencyAdmin { + require( + addressesProvider.getEmergencyAdmin() == msg.sender, + Errors.LPC_CALLER_NOT_EMERGENCY_ADMIN + ); _; } @@ -220,7 +231,7 @@ contract LendingPoolConfigurator is VersionedInitializable { address variableDebtTokenImpl, uint8 underlyingAssetDecimals, address interestRateStrategyAddress - ) public onlyAaveAdmin { + ) public onlyPoolAdmin { address asset = ITokenConfiguration(aTokenImpl).UNDERLYING_ASSET_ADDRESS(); require( @@ -287,7 +298,7 @@ contract LendingPoolConfigurator is VersionedInitializable { * @param asset the address of the reserve to be updated * @param implementation the address of the new aToken implementation **/ - function updateAToken(address asset, address implementation) external onlyAaveAdmin { + function updateAToken(address asset, address implementation) external onlyPoolAdmin { ReserveLogic.ReserveData memory reserveData = pool.getReserveData(asset); _upgradeTokenImplementation(asset, reserveData.aTokenAddress, implementation); @@ -300,7 +311,7 @@ contract LendingPoolConfigurator is VersionedInitializable { * @param asset the address of the reserve to be updated * @param implementation the address of the new aToken implementation **/ - function updateStableDebtToken(address asset, address implementation) external onlyAaveAdmin { + function updateStableDebtToken(address asset, address implementation) external onlyPoolAdmin { ReserveLogic.ReserveData memory reserveData = pool.getReserveData(asset); _upgradeTokenImplementation(asset, reserveData.stableDebtTokenAddress, implementation); @@ -313,7 +324,7 @@ contract LendingPoolConfigurator is VersionedInitializable { * @param asset the address of the reserve to be updated * @param implementation the address of the new aToken implementation **/ - function updateVariableDebtToken(address asset, address implementation) external onlyAaveAdmin { + function updateVariableDebtToken(address asset, address implementation) external onlyPoolAdmin { ReserveLogic.ReserveData memory reserveData = pool.getReserveData(asset); _upgradeTokenImplementation(asset, reserveData.variableDebtTokenAddress, implementation); @@ -328,7 +339,7 @@ contract LendingPoolConfigurator is VersionedInitializable { **/ function enableBorrowingOnReserve(address asset, bool stableBorrowRateEnabled) external - onlyAaveAdmin + onlyPoolAdmin { ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset); @@ -344,7 +355,7 @@ contract LendingPoolConfigurator is VersionedInitializable { * @dev disables borrowing on a reserve * @param asset the address of the reserve **/ - function disableBorrowingOnReserve(address asset) external onlyAaveAdmin { + function disableBorrowingOnReserve(address asset) external onlyPoolAdmin { ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset); currentConfig.setBorrowingEnabled(false); @@ -365,7 +376,7 @@ contract LendingPoolConfigurator is VersionedInitializable { uint256 ltv, uint256 liquidationThreshold, uint256 liquidationBonus - ) external onlyAaveAdmin { + ) external onlyPoolAdmin { ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset); //validation of the parameters: the LTV can @@ -401,7 +412,7 @@ contract LendingPoolConfigurator is VersionedInitializable { * @dev enable stable rate borrowing on a reserve * @param asset the address of the reserve **/ - function enableReserveStableRate(address asset) external onlyAaveAdmin { + function enableReserveStableRate(address asset) external onlyPoolAdmin { ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset); currentConfig.setStableRateBorrowingEnabled(true); @@ -415,7 +426,7 @@ contract LendingPoolConfigurator is VersionedInitializable { * @dev disable stable rate borrowing on a reserve * @param asset the address of the reserve **/ - function disableReserveStableRate(address asset) external onlyAaveAdmin { + function disableReserveStableRate(address asset) external onlyPoolAdmin { ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset); currentConfig.setStableRateBorrowingEnabled(false); @@ -429,7 +440,7 @@ contract LendingPoolConfigurator is VersionedInitializable { * @dev activates a reserve * @param asset the address of the reserve **/ - function activateReserve(address asset) external onlyAaveAdmin { + function activateReserve(address asset) external onlyPoolAdmin { ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset); currentConfig.setActive(true); @@ -443,7 +454,7 @@ contract LendingPoolConfigurator is VersionedInitializable { * @dev deactivates a reserve * @param asset the address of the reserve **/ - function deactivateReserve(address asset) external onlyAaveAdmin { + function deactivateReserve(address asset) external onlyPoolAdmin { _checkNoLiquidity(asset); ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset); @@ -459,7 +470,7 @@ contract LendingPoolConfigurator is VersionedInitializable { * @dev freezes a reserve. A frozen reserve doesn't accept any new deposit, borrow or rate swap, but can accept repayments, liquidations, rate rebalances and redeems * @param asset the address of the reserve **/ - function freezeReserve(address asset) external onlyAaveAdmin { + function freezeReserve(address asset) external onlyPoolAdmin { ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset); currentConfig.setFrozen(true); @@ -473,7 +484,7 @@ contract LendingPoolConfigurator is VersionedInitializable { * @dev unfreezes a reserve * @param asset the address of the reserve **/ - function unfreezeReserve(address asset) external onlyAaveAdmin { + function unfreezeReserve(address asset) external onlyPoolAdmin { ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset); currentConfig.setFrozen(false); @@ -488,7 +499,7 @@ contract LendingPoolConfigurator is VersionedInitializable { * @param asset the address of the reserve * @param ltv the new value for the loan to value **/ - function setLtv(address asset, uint256 ltv) external onlyAaveAdmin { + function setLtv(address asset, uint256 ltv) external onlyPoolAdmin { ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset); currentConfig.setLtv(ltv); @@ -503,7 +514,7 @@ contract LendingPoolConfigurator is VersionedInitializable { * @param asset the address of the reserve * @param reserveFactor the new reserve factor of the reserve **/ - function setReserveFactor(address asset, uint256 reserveFactor) external onlyAaveAdmin { + function setReserveFactor(address asset, uint256 reserveFactor) external onlyPoolAdmin { ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset); currentConfig.setReserveFactor(reserveFactor); @@ -518,7 +529,7 @@ contract LendingPoolConfigurator is VersionedInitializable { * @param asset the address of the reserve * @param threshold the new value for the liquidation threshold **/ - function setLiquidationThreshold(address asset, uint256 threshold) external onlyAaveAdmin { + function setLiquidationThreshold(address asset, uint256 threshold) external onlyPoolAdmin { ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset); currentConfig.setLiquidationThreshold(threshold); @@ -533,7 +544,7 @@ contract LendingPoolConfigurator is VersionedInitializable { * @param asset the address of the reserve * @param bonus the new value for the liquidation bonus **/ - function setLiquidationBonus(address asset, uint256 bonus) external onlyAaveAdmin { + function setLiquidationBonus(address asset, uint256 bonus) external onlyPoolAdmin { ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset); currentConfig.setLiquidationBonus(bonus); @@ -548,7 +559,7 @@ contract LendingPoolConfigurator is VersionedInitializable { * @param asset the address of the reserve * @param decimals the new number of decimals **/ - function setReserveDecimals(address asset, uint256 decimals) external onlyAaveAdmin { + function setReserveDecimals(address asset, uint256 decimals) external onlyPoolAdmin { ReserveConfiguration.Map memory currentConfig = pool.getConfiguration(asset); currentConfig.setDecimals(decimals); @@ -565,7 +576,7 @@ contract LendingPoolConfigurator is VersionedInitializable { **/ function setReserveInterestRateStrategyAddress(address asset, address rateStrategyAddress) external - onlyAaveAdmin + onlyPoolAdmin { pool.setReserveInterestRateStrategyAddress(asset, rateStrategyAddress); emit ReserveInterestRateStrategyChanged(asset, rateStrategyAddress); @@ -620,7 +631,7 @@ contract LendingPoolConfigurator is VersionedInitializable { * @dev pauses or unpauses LendingPool actions * @param val the boolean value to set the current pause state of LendingPool **/ - function setPoolPause(bool val) external onlyAaveAdmin { + function setPoolPause(bool val) external onlyEmergencyAdmin { pool.setPause(val); } diff --git a/contracts/libraries/helpers/Errors.sol b/contracts/libraries/helpers/Errors.sol index 2b173fff..1276ed23 100644 --- a/contracts/libraries/helpers/Errors.sol +++ b/contracts/libraries/helpers/Errors.sol @@ -18,7 +18,7 @@ pragma solidity ^0.6.8; */ library Errors { //common errors - string public constant CALLER_NOT_AAVE_ADMIN = '33'; // 'The caller must be the aave admin' + string public constant CALLER_NOT_POOL_ADMIN = '33'; // 'The caller must be the pool admin' //contract specific errors string public constant VL_AMOUNT_NOT_GREATER_THAN_0 = '1'; // 'Amount must be greater than 0' @@ -47,7 +47,7 @@ library Errors { string public constant LP_NOT_ENOUGH_LIQUIDITY_TO_BORROW = '24'; // 'There is not enough liquidity available to borrow' string public constant LP_REQUESTED_AMOUNT_TOO_SMALL = '25'; // 'The requested amount is too small for a FlashLoan.' string public constant LP_INCONSISTENT_PROTOCOL_ACTUAL_BALANCE = '26'; // 'The actual balance of the protocol is inconsistent' - string public constant LP_CALLER_NOT_LENDING_POOL_CONFIGURATOR = '27'; // 'The actual balance of the protocol is inconsistent' + string public constant LP_CALLER_NOT_LENDING_POOL_CONFIGURATOR = '27'; // 'The caller of the function is not the lending pool configurator' string public constant LP_INCONSISTENT_FLASHLOAN_PARAMS = '28'; string public constant AT_CALLER_MUST_BE_LENDING_POOL = '29'; // 'The caller of this function must be a lending pool' string public constant AT_CANNOT_GIVE_ALLVWANCE_TO_HIMSELF = '30'; // 'User cannot give allowance to himself' @@ -61,6 +61,7 @@ library Errors { string public constant LPC_INVALID_VARIABLE_DEBT_TOKEN_UNDERLYING_ADDRESS = '39'; // 'The liquidity of the reserve needs to be 0' string public constant LPC_INVALID_ADDRESSES_PROVIDER_ID = '40'; // 'The liquidity of the reserve needs to be 0' string public constant LPC_INVALID_CONFIGURATION = '75'; // 'Invalid risk parameters for the reserve' + string public constant LPC_CALLER_NOT_EMERGENCY_ADMIN = '76'; // 'The caller must be the emergency admin' string public constant LPAPR_PROVIDER_NOT_REGISTERED = '41'; // 'Provider is not registered' string public constant LPCM_HEALTH_FACTOR_NOT_BELOW_THRESHOLD = '42'; // 'Health factor is not below the threshold' string public constant LPCM_COLLATERAL_CANNOT_BE_LIQUIDATED = '43'; // 'The collateral chosen cannot be liquidated' diff --git a/contracts/tokenization/DelegationAwareAToken.sol b/contracts/tokenization/DelegationAwareAToken.sol index 12e80292..794fd4f5 100644 --- a/contracts/tokenization/DelegationAwareAToken.sol +++ b/contracts/tokenization/DelegationAwareAToken.sol @@ -25,10 +25,10 @@ contract DelegationAwareAToken is AToken { /** * @dev only the aave admin can call this function **/ - modifier onlyAaveAdmin { + modifier onlyPoolAdmin { require( - _msgSender() == ILendingPool(POOL).getAddressesProvider().getAaveAdmin(), - Errors.CALLER_NOT_AAVE_ADMIN + _msgSender() == ILendingPool(POOL).getAddressesProvider().getPoolAdmin(), + Errors.CALLER_NOT_POOL_ADMIN ); _; } @@ -66,7 +66,7 @@ contract DelegationAwareAToken is AToken { * @dev delegates voting power of the underlying asset to a specific address * @param delegatee the address that will receive the delegation **/ - function delegateUnderlyingTo(address delegatee) external onlyAaveAdmin { + function delegateUnderlyingTo(address delegatee) external onlyPoolAdmin { IDelegationToken(UNDERLYING_ASSET_ADDRESS).delegate(delegatee); } } diff --git a/deployed-contracts.json b/deployed-contracts.json index d1b2f772..e0dddae5 100644 --- a/deployed-contracts.json +++ b/deployed-contracts.json @@ -157,31 +157,31 @@ }, "LendingPoolAddressesProviderRegistry": { "buidlerevm": { - "address": "0x5A0773Ff307Bf7C71a832dBB5312237fD3437f9F", + "address": "0x18b9306737eaf6E8FC8e737F488a1AE077b18053", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "ReserveLogic": { "buidlerevm": { - "address": "0x78Ee8Fb9fE5abD5e347Fc94c2fb85596d1f60e3c", + "address": "0x920d847fE49E54C19047ba8bc236C45A8068Bca7", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "GenericLogic": { "buidlerevm": { - "address": "0x920d847fE49E54C19047ba8bc236C45A8068Bca7", + "address": "0xA4765Ff72A9F3CfE73089bb2c3a41B838DF71574", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "ValidationLogic": { "buidlerevm": { - "address": "0xA4765Ff72A9F3CfE73089bb2c3a41B838DF71574", + "address": "0x35c1419Da7cf0Ff885B8Ef8EA9242FEF6800c99b", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "LendingPool": { "buidlerevm": { - "address": "0x35c1419Da7cf0Ff885B8Ef8EA9242FEF6800c99b", + "address": "0xe2607EabC87fd0A4856840bF23da8458cDF0434F", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -192,59 +192,59 @@ }, "StableAndVariableTokensHelper": { "buidlerevm": { - "address": "0x0C6c3C47A1f650809B0D1048FDf9603e09473D7E", + "address": "0x06bA8d8af0dF898D0712DffFb0f862cC51AF45c2", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "ATokensAndRatesHelper": { "buidlerevm": { - "address": "0x920d847fE49E54C19047ba8bc236C45A8068Bca7", + "address": "0xA4765Ff72A9F3CfE73089bb2c3a41B838DF71574", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "PriceOracle": { "buidlerevm": { - "address": "0xb682dEEf4f8e298d86bFc3e21f50c675151FB974", + "address": "0x1750499D05Ed1674d822430FB960d5F6731fDf64", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "MockAggregator": { "buidlerevm": { - "address": "0x3D8FFB457fedDFBc760F3F243283F52692b579B1", + "address": "0xEC1C93A9f6a9e18E97784c76aC52053587FcDB89", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "ChainlinkProxyPriceProvider": { "buidlerevm": { - "address": "0xEC1C93A9f6a9e18E97784c76aC52053587FcDB89", + "address": "0x7B6C3e5486D9e6959441ab554A889099eed76290", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "LendingRateOracle": { "buidlerevm": { - "address": "0xAF6BA11790D1942625C0c2dA07da19AB63845cfF", + "address": "0xD83D2773a7873ae2b5f8Fb92097e20a8C64F691E", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "AaveProtocolTestHelpers": { "buidlerevm": { - "address": "0xf4830d6b1D70C8595d3BD8A63f9ed9F636DB9ef2" + "address": "0xd5C35F41baD857A2D4F34D7554E78d0391BAcEDF" } }, "LendingPoolCollateralManager": { "buidlerevm": { - "address": "0x8D0206fEBEB380486729b64bB4cfEDC5b354a6D6", + "address": "0x3c5408De7435Dfa3eB2aF2Edf5E39385f68F69b2", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "MockFlashLoanReceiver": { "buidlerevm": { - "address": "0xfC88832bac6AbdF216BC5A67be68E9DE94aD5ba2" + "address": "0x1256eBA4d0a7A38D10BaF4F61775ba491Ce7EE25" } }, "WalletBalanceProvider": { "buidlerevm": { - "address": "0x1256eBA4d0a7A38D10BaF4F61775ba491Ce7EE25", + "address": "0x77B0b5636fEA30eA79BB65AeCCdb599997A849A8", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, @@ -268,13 +268,13 @@ }, "MintableDelegationERC20": { "buidlerevm": { - "address": "0x77B0b5636fEA30eA79BB65AeCCdb599997A849A8", + "address": "0x78Ee8Fb9fE5abD5e347Fc94c2fb85596d1f60e3c", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } }, "AToken": { "buidlerevm": { - "address": "0x78Ee8Fb9fE5abD5e347Fc94c2fb85596d1f60e3c", + "address": "0x920d847fE49E54C19047ba8bc236C45A8068Bca7", "deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6" } } diff --git a/helpers/configuration.ts b/helpers/configuration.ts index 1665d4a0..caccf9d9 100644 --- a/helpers/configuration.ts +++ b/helpers/configuration.ts @@ -63,16 +63,29 @@ export const getFeeDistributionParamsCommon = ( }; }; -export const getGenesisAaveAdmin = async (config: ICommonConfiguration) => { +export const getGenesisPoolAdmin = async (config: ICommonConfiguration) => { const currentNetwork = BRE.network.name; - const targetAddress = getParamPerNetwork(config.AaveAdmin, currentNetwork); + const targetAddress = getParamPerNetwork(config.PoolAdmin, currentNetwork); if (targetAddress) { return targetAddress; } const addressList = await Promise.all( (await BRE.ethers.getSigners()).map((signer) => signer.getAddress()) ); - const addressIndex = config.AaveAdminIndex; + const addressIndex = config.PoolAdminIndex; + return addressList[addressIndex]; +}; + +export const getEmergencyAdmin = async (config: ICommonConfiguration) => { + const currentNetwork = BRE.network.name; + const targetAddress = getParamPerNetwork(config.EmergencyAdmin, currentNetwork); + if (targetAddress) { + return targetAddress; + } + const addressList = await Promise.all( + (await BRE.ethers.getSigners()).map((signer) => signer.getAddress()) + ); + const addressIndex = config.EmergencyAdminIndex; return addressList[addressIndex]; }; diff --git a/helpers/init-helpers.ts b/helpers/init-helpers.ts index b33e3b9a..c4aa3978 100644 --- a/helpers/init-helpers.ts +++ b/helpers/init-helpers.ts @@ -24,7 +24,7 @@ export const initReservesByHelper = async ( const addressProvider = await getLendingPoolAddressesProvider(); // Set aTokenAndRatesDeployer as temporal admin - await waitForTx(await addressProvider.setAaveAdmin(atokenAndRatesDeployer.address)); + await waitForTx(await addressProvider.setPoolAdmin(atokenAndRatesDeployer.address)); // CHUNK CONFIGURATION const tokensChunks = 4; @@ -140,7 +140,7 @@ export const initReservesByHelper = async ( } // Set deployer back as admin - await waitForTx(await addressProvider.setAaveAdmin(admin)); + await waitForTx(await addressProvider.setPoolAdmin(admin)); }; export const getPairsTokenAggregator = ( @@ -207,7 +207,7 @@ export const enableReservesToBorrowByHelper = async ( } if (tokens.length) { // Set aTokenAndRatesDeployer as temporal admin - await waitForTx(await addressProvider.setAaveAdmin(atokenAndRatesDeployer.address)); + await waitForTx(await addressProvider.setPoolAdmin(atokenAndRatesDeployer.address)); // Deploy init per chunks const stableChunks = 20; @@ -233,7 +233,7 @@ export const enableReservesToBorrowByHelper = async ( console.log(` - Init for: ${chunkedSymbols[chunkIndex].join(', ')}`); } // Set deployer back as admin - await waitForTx(await addressProvider.setAaveAdmin(admin)); + await waitForTx(await addressProvider.setPoolAdmin(admin)); } }; @@ -280,7 +280,7 @@ export const enableReservesAsCollateralByHelper = async ( } if (tokens.length) { // Set aTokenAndRatesDeployer as temporal admin - await waitForTx(await addressProvider.setAaveAdmin(atokenAndRatesDeployer.address)); + await waitForTx(await addressProvider.setPoolAdmin(atokenAndRatesDeployer.address)); // Deploy init per chunks const enableChunks = 20; @@ -304,6 +304,6 @@ export const enableReservesAsCollateralByHelper = async ( console.log(` - Init for: ${chunkedSymbols[chunkIndex].join(', ')}`); } // Set deployer back as admin - await waitForTx(await addressProvider.setAaveAdmin(admin)); + await waitForTx(await addressProvider.setPoolAdmin(admin)); } }; diff --git a/helpers/types.ts b/helpers/types.ts index 80f3846d..d7c51e72 100644 --- a/helpers/types.ts +++ b/helpers/types.ts @@ -75,7 +75,7 @@ export enum eContractid { */ export enum ProtocolErrors { //common errors - CALLER_NOT_AAVE_ADMIN = '33', // 'The caller must be the aave admin' + CALLER_NOT_POOL_ADMIN = '33', // 'The caller must be the pool admin' //contract specific errors VL_AMOUNT_NOT_GREATER_THAN_0 = '1', // 'Amount must be greater than 0' @@ -104,7 +104,7 @@ export enum ProtocolErrors { LP_NOT_ENOUGH_LIQUIDITY_TO_BORROW = '24', // 'There is not enough liquidity available to borrow' LP_REQUESTED_AMOUNT_TOO_SMALL = '25', // 'The requested amount is too small for a FlashLoan.' LP_INCONSISTENT_PROTOCOL_ACTUAL_BALANCE = '26', // 'The actual balance of the protocol is inconsistent' - LP_CALLER_NOT_LENDING_POOL_CONFIGURATOR = '27', // 'The actual balance of the protocol is inconsistent' + LP_CALLER_NOT_LENDING_POOL_CONFIGURATOR = '27', // 'The caller is not the lending pool configurator' LP_INCONSISTENT_FLASHLOAN_PARAMS = '28', AT_CALLER_MUST_BE_LENDING_POOL = '29', // 'The caller of this function must be a lending pool' AT_CANNOT_GIVE_ALLVWANCE_TO_HIMSELF = '30', // 'User cannot give allowance to himself' @@ -117,6 +117,7 @@ export enum ProtocolErrors { LPC_INVALID_STABLE_DEBT_TOKEN_UNDERLYING_ADDRESS = '38', // 'The liquidity of the reserve needs to be 0' LPC_INVALID_VARIABLE_DEBT_TOKEN_UNDERLYING_ADDRESS = '39', // 'The liquidity of the reserve needs to be 0' LPC_INVALID_ADDRESSES_PROVIDER_ID = '40', // 'The liquidity of the reserve needs to be 0' + LPC_CALLER_NOT_EMERGENCY_ADMIN = '76', // 'The caller must be the emergencya admin' LPAPR_PROVIDER_NOT_REGISTERED = '41', // 'Provider is not registered' LPCM_HEALTH_FACTOR_NOT_BELOW_THRESHOLD = '42', // 'Health factor is not below the threshold' LPCM_COLLATERAL_CANNOT_BE_LIQUIDATED = '43', // 'The collateral chosen cannot be liquidated' @@ -372,8 +373,10 @@ export interface ICommonConfiguration { ChainlinkProxyPriceProvider: iParamsPerNetwork; FallbackOracle: iParamsPerNetwork; ChainlinkAggregator: iParamsPerNetwork; - AaveAdmin: iParamsPerNetwork; - AaveAdminIndex: number; + PoolAdmin: iParamsPerNetwork; + PoolAdminIndex: number; + EmergencyAdmin: iParamsPerNetwork; + EmergencyAdminIndex: number; ReserveAssets: iParamsPerNetwork>; ReservesConfig: iMultiPoolsAssets; ATokenDomainSeparator: iParamsPerNetwork; diff --git a/tasks/dev/2_address_provider_registry.ts b/tasks/dev/2_address_provider_registry.ts index 1c3da96d..13746a4b 100644 --- a/tasks/dev/2_address_provider_registry.ts +++ b/tasks/dev/2_address_provider_registry.ts @@ -16,7 +16,7 @@ task( const admin = await (await localBRE.ethers.getSigners())[0].getAddress(); const addressesProvider = await deployLendingPoolAddressesProvider(verify); - await waitForTx(await addressesProvider.setAaveAdmin(admin)); + await waitForTx(await addressesProvider.setPoolAdmin(admin)); const addressesProviderRegistry = await deployLendingPoolAddressesProviderRegistry(verify); await waitForTx( diff --git a/tasks/full/1_address_provider_registry.ts b/tasks/full/1_address_provider_registry.ts index 4dd84f08..a99d328c 100644 --- a/tasks/full/1_address_provider_registry.ts +++ b/tasks/full/1_address_provider_registry.ts @@ -5,7 +5,12 @@ import { deployLendingPoolAddressesProviderRegistry, } from '../../helpers/contracts-deployments'; import {waitForTx} from '../../helpers/misc-utils'; -import {ConfigNames, loadPoolConfig, getGenesisAaveAdmin} from '../../helpers/configuration'; +import { + ConfigNames, + loadPoolConfig, + getGenesisPoolAdmin, + getEmergencyAdmin, +} from '../../helpers/configuration'; import {eEthereumNetwork} from '../../helpers/types'; import {getLendingPoolAddressesProviderRegistry} from '../../helpers/contracts-getters'; @@ -24,7 +29,11 @@ task( const providerRegistryAddress = getParamPerNetwork(poolConfig.ProviderRegistry, network); // Deploy address provider and set genesis manager const addressesProvider = await deployLendingPoolAddressesProvider(verify); - await waitForTx(await addressesProvider.setAaveAdmin(await getGenesisAaveAdmin(poolConfig))); + await waitForTx(await addressesProvider.setPoolAdmin(await getGenesisPoolAdmin(poolConfig))); + const admin = await getEmergencyAdmin(poolConfig); + console.log('Admin is ', admin); + + await waitForTx(await addressesProvider.setEmergencyAdmin(admin)); // If no provider registry is set, deploy lending pool address provider registry and register the address provider const addressesProviderRegistry = !providerRegistryAddress diff --git a/test/__setup.spec.ts b/test/__setup.spec.ts index 4e6f24f8..7a3e4c60 100644 --- a/test/__setup.spec.ts +++ b/test/__setup.spec.ts @@ -24,7 +24,7 @@ import { import {Signer} from 'ethers'; import {TokenContractId, eContractid, tEthereumAddress, AavePools} from '../helpers/types'; import {MintableErc20 as MintableERC20} from '../types/MintableErc20'; -import {getReservesConfigByPool} from '../helpers/configuration'; +import {getEmergencyAdmin, getReservesConfigByPool} from '../helpers/configuration'; import {initializeMakeSuite} from './helpers/make-suite'; import { @@ -32,7 +32,7 @@ import { deployAllMockAggregators, setInitialMarketRatesInRatesOracleByHelper, } from '../helpers/oracles-helpers'; -import {waitForTx} from '../helpers/misc-utils'; +import {BRE, waitForTx} from '../helpers/misc-utils'; import { initReservesByHelper, enableReservesToBorrowByHelper, @@ -89,7 +89,14 @@ const buildTestEnv = async (deployer: Signer, secondaryWallet: Signer) => { const mockTokens = await deployAllMockTokens(deployer); const addressesProvider = await deployLendingPoolAddressesProvider(); - await waitForTx(await addressesProvider.setAaveAdmin(aaveAdmin)); + await waitForTx(await addressesProvider.setPoolAdmin(aaveAdmin)); + + //setting users[1] as emergency admin, which is in position 2 in the BRE addresses list + const addressList = await Promise.all( + (await BRE.ethers.getSigners()).map((signer) => signer.getAddress()) + ); + + await waitForTx(await addressesProvider.setEmergencyAdmin(addressList[2])); const addressesProviderRegistry = await deployLendingPoolAddressesProviderRegistry(); await waitForTx( diff --git a/test/configurator.spec.ts b/test/configurator.spec.ts index befe2d0f..b0db698d 100644 --- a/test/configurator.spec.ts +++ b/test/configurator.spec.ts @@ -11,7 +11,7 @@ const {expect} = require('chai'); makeSuite('LendingPoolConfigurator', (testEnv: TestEnv) => { const { - CALLER_NOT_AAVE_ADMIN, + CALLER_NOT_POOL_ADMIN, LPC_RESERVE_LIQUIDITY_NOT_0, RC_INVALID_LTV, RC_INVALID_LIQ_THRESHOLD, @@ -87,16 +87,16 @@ makeSuite('LendingPoolConfigurator', (testEnv: TestEnv) => { const {configurator, users, weth} = testEnv; await expect( configurator.connect(users[2].signer).deactivateReserve(weth.address), - CALLER_NOT_AAVE_ADMIN - ).to.be.revertedWith(CALLER_NOT_AAVE_ADMIN); + CALLER_NOT_POOL_ADMIN + ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); }); it('Check the onlyAaveAdmin on activateReserve ', async () => { const {configurator, users, weth} = testEnv; await expect( configurator.connect(users[2].signer).activateReserve(weth.address), - CALLER_NOT_AAVE_ADMIN - ).to.be.revertedWith(CALLER_NOT_AAVE_ADMIN); + CALLER_NOT_POOL_ADMIN + ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); }); it('Freezes the ETH reserve', async () => { @@ -156,16 +156,16 @@ makeSuite('LendingPoolConfigurator', (testEnv: TestEnv) => { const {configurator, users, weth} = testEnv; await expect( configurator.connect(users[2].signer).freezeReserve(weth.address), - CALLER_NOT_AAVE_ADMIN - ).to.be.revertedWith(CALLER_NOT_AAVE_ADMIN); + CALLER_NOT_POOL_ADMIN + ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); }); it('Check the onlyAaveAdmin on unfreezeReserve ', async () => { const {configurator, users, weth} = testEnv; await expect( configurator.connect(users[2].signer).unfreezeReserve(weth.address), - CALLER_NOT_AAVE_ADMIN - ).to.be.revertedWith(CALLER_NOT_AAVE_ADMIN); + CALLER_NOT_POOL_ADMIN + ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); }); it('Deactivates the ETH reserve for borrowing', async () => { @@ -228,16 +228,16 @@ makeSuite('LendingPoolConfigurator', (testEnv: TestEnv) => { const {configurator, users, weth} = testEnv; await expect( configurator.connect(users[2].signer).disableBorrowingOnReserve(weth.address), - CALLER_NOT_AAVE_ADMIN - ).to.be.revertedWith(CALLER_NOT_AAVE_ADMIN); + CALLER_NOT_POOL_ADMIN + ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); }); it('Check the onlyAaveAdmin on enableBorrowingOnReserve ', async () => { const {configurator, users, weth} = testEnv; await expect( configurator.connect(users[2].signer).enableBorrowingOnReserve(weth.address, true), - CALLER_NOT_AAVE_ADMIN - ).to.be.revertedWith(CALLER_NOT_AAVE_ADMIN); + CALLER_NOT_POOL_ADMIN + ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); }); it('Deactivates the ETH reserve as collateral', async () => { @@ -300,8 +300,8 @@ makeSuite('LendingPoolConfigurator', (testEnv: TestEnv) => { configurator .connect(users[2].signer) .configureReserveAsCollateral(weth.address, '7500', '8000', '10500'), - CALLER_NOT_AAVE_ADMIN - ).to.be.revertedWith(CALLER_NOT_AAVE_ADMIN); + CALLER_NOT_POOL_ADMIN + ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); }); it('Disable stable borrow rate on the ETH reserve', async () => { @@ -360,16 +360,16 @@ makeSuite('LendingPoolConfigurator', (testEnv: TestEnv) => { const {configurator, users, weth} = testEnv; await expect( configurator.connect(users[2].signer).disableReserveStableRate(weth.address), - CALLER_NOT_AAVE_ADMIN - ).to.be.revertedWith(CALLER_NOT_AAVE_ADMIN); + CALLER_NOT_POOL_ADMIN + ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); }); it('Check the onlyAaveAdmin on enableReserveStableRate', async () => { const {configurator, users, weth} = testEnv; await expect( configurator.connect(users[2].signer).enableReserveStableRate(weth.address), - CALLER_NOT_AAVE_ADMIN - ).to.be.revertedWith(CALLER_NOT_AAVE_ADMIN); + CALLER_NOT_POOL_ADMIN + ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); }); it('Changes LTV of the reserve', async () => { @@ -402,8 +402,8 @@ makeSuite('LendingPoolConfigurator', (testEnv: TestEnv) => { const {configurator, users, weth} = testEnv; await expect( configurator.connect(users[2].signer).setLtv(weth.address, '75'), - CALLER_NOT_AAVE_ADMIN - ).to.be.revertedWith(CALLER_NOT_AAVE_ADMIN); + CALLER_NOT_POOL_ADMIN + ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); }); it('Changes the reserve factor of the reserve', async () => { @@ -436,8 +436,8 @@ makeSuite('LendingPoolConfigurator', (testEnv: TestEnv) => { const {configurator, users, weth} = testEnv; await expect( configurator.connect(users[2].signer).setReserveFactor(weth.address, '2000'), - CALLER_NOT_AAVE_ADMIN - ).to.be.revertedWith(CALLER_NOT_AAVE_ADMIN); + CALLER_NOT_POOL_ADMIN + ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); }); it('Changes liquidation threshold of the reserve', async () => { @@ -470,8 +470,8 @@ makeSuite('LendingPoolConfigurator', (testEnv: TestEnv) => { const {configurator, users, weth} = testEnv; await expect( configurator.connect(users[2].signer).setLiquidationThreshold(weth.address, '80'), - CALLER_NOT_AAVE_ADMIN - ).to.be.revertedWith(CALLER_NOT_AAVE_ADMIN); + CALLER_NOT_POOL_ADMIN + ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); }); it('Changes liquidation bonus of the reserve', async () => { @@ -504,24 +504,24 @@ makeSuite('LendingPoolConfigurator', (testEnv: TestEnv) => { const {configurator, users, weth} = testEnv; await expect( configurator.connect(users[2].signer).setLiquidationBonus(weth.address, '80'), - CALLER_NOT_AAVE_ADMIN - ).to.be.revertedWith(CALLER_NOT_AAVE_ADMIN); + CALLER_NOT_POOL_ADMIN + ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); }); it('Check the onlyAaveAdmin on setReserveDecimals', async () => { const {configurator, users, weth} = testEnv; await expect( configurator.connect(users[2].signer).setReserveDecimals(weth.address, '80'), - CALLER_NOT_AAVE_ADMIN - ).to.be.revertedWith(CALLER_NOT_AAVE_ADMIN); + CALLER_NOT_POOL_ADMIN + ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); }); it('Check the onlyAaveAdmin on setLiquidationBonus', async () => { const {configurator, users, weth} = testEnv; await expect( configurator.connect(users[2].signer).setLiquidationBonus(weth.address, '80'), - CALLER_NOT_AAVE_ADMIN - ).to.be.revertedWith(CALLER_NOT_AAVE_ADMIN); + CALLER_NOT_POOL_ADMIN + ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); }); it('Reverts when trying to disable the DAI reserve with liquidity on it', async () => { diff --git a/test/delegation-aware-atoken.spec.ts b/test/delegation-aware-atoken.spec.ts index 7170cc22..018661b1 100644 --- a/test/delegation-aware-atoken.spec.ts +++ b/test/delegation-aware-atoken.spec.ts @@ -43,7 +43,7 @@ makeSuite('AToken: underlying delegation', (testEnv: TestEnv) => { await expect( delegationAToken.connect(users[1].signer).delegateUnderlyingTo(users[2].address) - ).to.be.revertedWith(ProtocolErrors.CALLER_NOT_AAVE_ADMIN); + ).to.be.revertedWith(ProtocolErrors.CALLER_NOT_POOL_ADMIN); }); it('Tries to delegate to user 2', async () => { diff --git a/test/lending-pool-addresses-provider.spec.ts b/test/lending-pool-addresses-provider.spec.ts index 4858531a..ac70c6a0 100644 --- a/test/lending-pool-addresses-provider.spec.ts +++ b/test/lending-pool-addresses-provider.spec.ts @@ -21,7 +21,7 @@ makeSuite('LendingPoolAddressesProvider', (testEnv: TestEnv) => { addressesProvider.setLendingPoolImpl, addressesProvider.setLendingPoolConfiguratorImpl, addressesProvider.setLendingPoolCollateralManager, - addressesProvider.setAaveAdmin, + addressesProvider.setPoolAdmin, addressesProvider.setPriceOracle, addressesProvider.setLendingRateOracle, ]) { diff --git a/test/pausable-functions.spec.ts b/test/pausable-functions.spec.ts index 9c7f6473..84d47188 100644 --- a/test/pausable-functions.spec.ts +++ b/test/pausable-functions.spec.ts @@ -39,7 +39,7 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { const user1Balance = await aDai.balanceOf(users[1].address); // Configurator pauses the pool - await configurator.setPoolPause(true); + await configurator.connect(users[1].signer).setPoolPause(true); // User 0 tries the transfer to User 1 await expect( @@ -59,7 +59,7 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { ); // Configurator unpauses the pool - await configurator.setPoolPause(false); + await configurator.connect(users[1].signer).setPoolPause(false); // User 0 succeeds transfer to User 1 await aDai.connect(users[0].signer).transfer(users[1].address, amountDAItoDeposit); @@ -88,13 +88,13 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { await dai.connect(users[0].signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL); // Configurator pauses the pool - await configurator.setPoolPause(true); + await configurator.connect(users[1].signer).setPoolPause(true); await expect( pool.connect(users[0].signer).deposit(dai.address, amountDAItoDeposit, users[0].address, '0') ).to.revertedWith(LP_IS_PAUSED); // Configurator unpauses the pool - await configurator.setPoolPause(false); + await configurator.connect(users[1].signer).setPoolPause(false); }); it('Withdraw', async () => { @@ -111,7 +111,7 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { .deposit(dai.address, amountDAItoDeposit, users[0].address, '0'); // Configurator pauses the pool - await configurator.setPoolPause(true); + await configurator.connect(users[1].signer).setPoolPause(true); // user tries to burn await expect( @@ -119,7 +119,7 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { ).to.revertedWith(LP_IS_PAUSED); // Configurator unpauses the pool - await configurator.setPoolPause(false); + await configurator.connect(users[1].signer).setPoolPause(false); }); it('DelegateBorrowAllowance', async () => { @@ -128,7 +128,7 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { const user = users[1]; const toUser = users[2]; // Pause the pool - await configurator.setPoolPause(true); + await configurator.connect(users[1].signer).setPoolPause(true); // Try to execute liquidation await expect( @@ -136,7 +136,7 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { ).revertedWith(LP_IS_PAUSED); // Unpause the pool - await configurator.setPoolPause(false); + await configurator.connect(users[1].signer).setPoolPause(false); }); it('Borrow', async () => { @@ -144,7 +144,7 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { const user = users[1]; // Pause the pool - await configurator.setPoolPause(true); + await configurator.connect(users[1].signer).setPoolPause(true); // Try to execute liquidation await expect( @@ -152,7 +152,7 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { ).revertedWith(LP_IS_PAUSED); // Unpause the pool - await configurator.setPoolPause(false); + await configurator.connect(users[1].signer).setPoolPause(false); }); it('Repay', async () => { @@ -160,7 +160,7 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { const user = users[1]; // Pause the pool - await configurator.setPoolPause(true); + await configurator.connect(users[1].signer).setPoolPause(true); // Try to execute liquidation await expect(pool.connect(user.signer).repay(dai.address, '1', '1', user.address)).revertedWith( @@ -168,7 +168,7 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { ); // Unpause the pool - await configurator.setPoolPause(false); + await configurator.connect(users[1].signer).setPoolPause(false); }); it('Flash loan', async () => { @@ -181,7 +181,7 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { await _mockFlashLoanReceiver.setFailExecutionTransfer(true); // Pause pool - await configurator.setPoolPause(true); + await configurator.connect(users[1].signer).setPoolPause(true); await expect( pool @@ -198,7 +198,7 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { ).revertedWith(LP_IS_PAUSED); // Unpause pool - await configurator.setPoolPause(false); + await configurator.connect(users[1].signer).setPoolPause(false); }); it('Liquidation call', async () => { @@ -271,7 +271,7 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { .toFixed(0); // Pause pool - await configurator.setPoolPause(true); + await configurator.connect(users[1].signer).setPoolPause(true); // Do liquidation expect( @@ -279,7 +279,7 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { ).revertedWith(LP_IS_PAUSED); // Unpause pool - await configurator.setPoolPause(false); + await configurator.connect(users[1].signer).setPoolPause(false); }); it('SwapBorrowRateMode', async () => { @@ -300,7 +300,7 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { await pool.connect(user.signer).borrow(usdc.address, amountToBorrow, 2, 0, user.address); // Pause pool - await configurator.setPoolPause(true); + await configurator.connect(users[1].signer).setPoolPause(true); // Try to repay await expect( @@ -308,21 +308,21 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { ).revertedWith(LP_IS_PAUSED); // Unpause pool - await configurator.setPoolPause(false); + await configurator.connect(users[1].signer).setPoolPause(false); }); it('RebalanceStableBorrowRate', async () => { const {pool, dai, users, configurator} = testEnv; const user = users[1]; // Pause pool - await configurator.setPoolPause(true); + await configurator.connect(users[1].signer).setPoolPause(true); await expect( pool.connect(user.signer).rebalanceStableBorrowRate(dai.address, user.address) ).revertedWith(LP_IS_PAUSED); // Unpause pool - await configurator.setPoolPause(false); + await configurator.connect(users[1].signer).setPoolPause(false); }); it('setUserUseReserveAsCollateral', async () => { @@ -335,13 +335,13 @@ makeSuite('Pausable Pool', (testEnv: TestEnv) => { await pool.connect(user.signer).deposit(weth.address, amountWETHToDeposit, user.address, '0'); // Pause pool - await configurator.setPoolPause(true); + await configurator.connect(users[1].signer).setPoolPause(true); await expect( pool.connect(user.signer).setUserUseReserveAsCollateral(weth.address, false) ).revertedWith(LP_IS_PAUSED); // Unpause pool - await configurator.setPoolPause(false); + await configurator.connect(users[1].signer).setPoolPause(false); }); }); diff --git a/test/upgradeability.spec.ts b/test/upgradeability.spec.ts index b1fe1ad9..92ab1ee1 100644 --- a/test/upgradeability.spec.ts +++ b/test/upgradeability.spec.ts @@ -19,7 +19,7 @@ import { } from '../helpers/contracts-deployments'; makeSuite('Upgradeability', (testEnv: TestEnv) => { - const {CALLER_NOT_AAVE_ADMIN} = ProtocolErrors; + const {CALLER_NOT_POOL_ADMIN} = ProtocolErrors; let newATokenAddress: string; let newStableTokenAddress: string; let newVariableTokenAddress: string; @@ -61,7 +61,7 @@ makeSuite('Upgradeability', (testEnv: TestEnv) => { await expect( configurator.connect(users[1].signer).updateAToken(dai.address, newATokenAddress) - ).to.be.revertedWith(CALLER_NOT_AAVE_ADMIN); + ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); }); it('Upgrades the DAI Atoken implementation ', async () => { @@ -83,7 +83,7 @@ makeSuite('Upgradeability', (testEnv: TestEnv) => { configurator .connect(users[1].signer) .updateStableDebtToken(dai.address, newStableTokenAddress) - ).to.be.revertedWith(CALLER_NOT_AAVE_ADMIN); + ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); }); it('Upgrades the DAI stable debt token implementation ', async () => { @@ -109,7 +109,7 @@ makeSuite('Upgradeability', (testEnv: TestEnv) => { configurator .connect(users[1].signer) .updateVariableDebtToken(dai.address, newVariableTokenAddress) - ).to.be.revertedWith(CALLER_NOT_AAVE_ADMIN); + ).to.be.revertedWith(CALLER_NOT_POOL_ADMIN); }); it('Upgrades the DAI variable debt token implementation ', async () => { From b101af21cc8a6a3433c7809bf46e81f9d710fa54 Mon Sep 17 00:00:00 2001 From: emilio Date: Thu, 5 Nov 2020 14:43:39 +0100 Subject: [PATCH 4/4] Fixed certora harness --- ...LendingPoolHarnessForVariableDebtToken.sol | 33 ++++++++----------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/specs/harness/LendingPoolHarnessForVariableDebtToken.sol b/specs/harness/LendingPoolHarnessForVariableDebtToken.sol index a6ffb6f2..f5ea9be1 100644 --- a/specs/harness/LendingPoolHarnessForVariableDebtToken.sol +++ b/specs/harness/LendingPoolHarnessForVariableDebtToken.sol @@ -8,6 +8,9 @@ import {UserConfiguration} from '../../contracts/libraries/configuration/UserCon import {ReserveLogic} from '../../contracts/libraries/logic/ReserveLogic.sol'; import {ILendingPool} from '../../contracts/interfaces/ILendingPool.sol'; import {LendingPool} from '../../contracts/lendingpool/LendingPool.sol'; +import { + ILendingPoolAddressesProvider +} from '../../contracts/interfaces/ILendingPoolAddressesProvider.sol'; /* Certora: Harness that delegates calls to the original LendingPool. @@ -25,26 +28,12 @@ contract LendingPoolHarnessForVariableDebtToken is ILendingPool { originalPool.deposit(asset, amount, onBehalfOf, referralCode); } - function withdraw(address asset, uint256 amount) external override { - originalPool.withdraw(asset, amount); - } - - function getBorrowAllowance( - address fromUser, - address toUser, + function withdraw( address asset, - uint256 interestRateMode - ) external override view returns (uint256) { - return originalPool.getBorrowAllowance(fromUser, toUser, asset, interestRateMode); - } - - function delegateBorrowAllowance( - address asset, - address user, - uint256 interestRateMode, - uint256 amount + uint256 amount, + address to ) external override { - originalPool.delegateBorrowAllowance(asset, user, interestRateMode, amount); + originalPool.withdraw(asset, amount, to); } function borrow( @@ -193,12 +182,12 @@ contract LendingPoolHarnessForVariableDebtToken is ILendingPool { address receiver, address[] calldata assets, uint256[] calldata amounts, - uint256 mode, + uint256[] calldata modes, address onBehalfOf, bytes calldata params, uint16 referralCode ) external override { - originalPool.flashLoan(receiver, assets, amounts, mode, onBehalfOf, params, referralCode); + originalPool.flashLoan(receiver, assets, amounts, modes, onBehalfOf, params, referralCode); } function finalizeTransfer( @@ -211,4 +200,8 @@ contract LendingPoolHarnessForVariableDebtToken is ILendingPool { ) external override { originalPool.finalizeTransfer(asset, from, to, amount, balanceFromAfter, balanceToBefore); } + + function getAddressesProvider() external override view returns (ILendingPoolAddressesProvider) { + return originalPool.getAddressesProvider(); + } }