mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
Added pausable to Pool actions and aTokens at transfer, triggered by LendingPoolConfigurator. Added basic test to aToken transfer.
This commit is contained in:
parent
4b8962d38f
commit
bbc11eb092
|
@ -129,6 +129,15 @@ interface ILendingPool {
|
|||
address liquidator,
|
||||
bool receiveAToken
|
||||
);
|
||||
/**
|
||||
* @dev Emitted when the pause is triggered by `account`.
|
||||
*/
|
||||
event Paused(address account);
|
||||
|
||||
/**
|
||||
* @dev Emitted when the pause is lifted by `account`.
|
||||
*/
|
||||
event Unpaused(address account);
|
||||
|
||||
/**
|
||||
* @dev deposits The underlying asset into the reserve. A corresponding amount of the overlying asset (aTokens)
|
||||
|
@ -374,4 +383,10 @@ interface ILendingPool {
|
|||
) external view returns (bool);
|
||||
|
||||
function getReserves() external view returns (address[] memory);
|
||||
|
||||
function pause() external;
|
||||
|
||||
function unpause() external;
|
||||
|
||||
function isPaused() external view returns (bool);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ pragma experimental ABIEncoderV2;
|
|||
|
||||
import {SafeMath} from '@openzeppelin/contracts/math/SafeMath.sol';
|
||||
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
|
||||
import {Pausable} from '@openzeppelin/contracts/utils/Pausable.sol';
|
||||
import {
|
||||
VersionedInitializable
|
||||
} from '../libraries/openzeppelin-upgradeability/VersionedInitializable.sol';
|
||||
|
@ -31,7 +32,7 @@ import {ILendingPool} from '../interfaces/ILendingPool.sol';
|
|||
* @author Aave
|
||||
**/
|
||||
|
||||
contract LendingPool is VersionedInitializable, ILendingPool {
|
||||
contract LendingPool is VersionedInitializable, Pausable, ILendingPool {
|
||||
using SafeMath for uint256;
|
||||
using WadRayMath for uint256;
|
||||
using ReserveLogic for ReserveLogic.ReserveData;
|
||||
|
@ -93,7 +94,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
uint256 amount,
|
||||
address onBehalfOf,
|
||||
uint16 referralCode
|
||||
) external override {
|
||||
) external override whenNotPaused {
|
||||
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
||||
|
||||
ValidationLogic.validateDeposit(reserve, amount);
|
||||
|
@ -121,7 +122,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
* @param asset the address of the reserve
|
||||
* @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 {
|
||||
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
||||
|
||||
address aToken = reserve.aTokenAddress;
|
||||
|
@ -172,7 +173,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
uint256 amount,
|
||||
uint256 interestRateMode,
|
||||
uint16 referralCode
|
||||
) external override {
|
||||
) external override whenNotPaused {
|
||||
_executeBorrow(
|
||||
ExecuteBorrowParams(
|
||||
asset,
|
||||
|
@ -199,7 +200,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
uint256 amount,
|
||||
uint256 rateMode,
|
||||
address onBehalfOf
|
||||
) external override {
|
||||
) external override whenNotPaused {
|
||||
_executeRepay(asset, msg.sender, amount, rateMode, onBehalfOf);
|
||||
}
|
||||
|
||||
|
@ -260,7 +261,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
* @param asset the address of the reserve on which the user borrowed
|
||||
* @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 {
|
||||
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
||||
|
||||
(uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(msg.sender, reserve);
|
||||
|
@ -303,7 +304,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
* @param asset the address of the reserve
|
||||
* @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 {
|
||||
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
||||
|
||||
IStableDebtToken stableDebtToken = IStableDebtToken(reserve.stableDebtTokenAddress);
|
||||
|
@ -348,7 +349,11 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
* @param asset the address of the reserve
|
||||
* @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
|
||||
{
|
||||
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
||||
|
||||
ValidationLogic.validateSetUseReserveAsCollateral(
|
||||
|
@ -384,7 +389,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
address user,
|
||||
uint256 purchaseAmount,
|
||||
bool receiveAToken
|
||||
) external override {
|
||||
) external override whenNotPaused {
|
||||
address liquidationManager = _addressesProvider.getLendingPoolLiquidationManager();
|
||||
|
||||
//solium-disable-next-line
|
||||
|
@ -440,7 +445,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
uint256 principalAmount,
|
||||
address receiver,
|
||||
bytes calldata params
|
||||
) external override {
|
||||
) external override whenNotPaused {
|
||||
require(!_flashLiquidationLocked, Errors.REENTRANCY_NOT_ALLOWED);
|
||||
_flashLiquidationLocked = true;
|
||||
|
||||
|
@ -487,7 +492,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
uint256 mode,
|
||||
bytes calldata params,
|
||||
uint16 referralCode
|
||||
) external override {
|
||||
) external override whenNotPaused {
|
||||
ReserveLogic.ReserveData storage reserve = _reserves[asset];
|
||||
FlashLoanLocalVars memory vars;
|
||||
|
||||
|
@ -706,7 +711,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
address stableDebtAddress,
|
||||
address variableDebtAddress,
|
||||
address interestRateStrategyAddress
|
||||
) external override onlyLendingPoolConfigurator {
|
||||
) external override onlyLendingPoolConfigurator whenNotPaused {
|
||||
_reserves[asset].init(
|
||||
aTokenAddress,
|
||||
stableDebtAddress,
|
||||
|
@ -726,6 +731,7 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
external
|
||||
override
|
||||
onlyLendingPoolConfigurator
|
||||
whenNotPaused
|
||||
{
|
||||
_reserves[asset].interestRateStrategyAddress = rateStrategyAddress;
|
||||
}
|
||||
|
@ -908,4 +914,25 @@ contract LendingPool is VersionedInitializable, ILendingPool {
|
|||
function getAddressesProvider() external view returns (ILendingPoolAddressesProvider) {
|
||||
return _addressesProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev pause all the Lending Pool actions
|
||||
*/
|
||||
function pause() external override onlyLendingPoolConfigurator {
|
||||
_pause();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev unpause all the Lending Pool actions
|
||||
*/
|
||||
function unpause() external override onlyLendingPoolConfigurator {
|
||||
_unpause();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns true if the contract is paused, and false otherwise.
|
||||
*/
|
||||
function isPaused() public override view returns (bool) {
|
||||
return Pausable.paused();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -582,4 +582,18 @@ contract LendingPoolConfigurator is VersionedInitializable {
|
|||
|
||||
proxy.upgradeToAndCall(implementation, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev pauses LendingPool actions
|
||||
**/
|
||||
function pausePool() external onlyLendingPoolManager {
|
||||
pool.pause();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev unpauses LendingPool actions
|
||||
**/
|
||||
function unpausePool() external onlyLendingPoolManager {
|
||||
pool.unpause();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,7 +67,6 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
|
|||
uint256 amount,
|
||||
uint256 index
|
||||
) external override onlyLendingPool {
|
||||
|
||||
uint256 currentBalance = balanceOf(user);
|
||||
|
||||
require(amount <= currentBalance, Errors.INVALID_ATOKEN_BALANCE);
|
||||
|
@ -79,7 +78,6 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
|
|||
//transfers the underlying to the target
|
||||
ERC20(UNDERLYING_ASSET_ADDRESS).safeTransfer(receiverOfUnderlying, amount);
|
||||
|
||||
|
||||
emit Burn(msg.sender, receiverOfUnderlying, amount, index);
|
||||
}
|
||||
|
||||
|
@ -89,13 +87,15 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
|
|||
* @param user the address receiving the minted tokens
|
||||
* @param amount the amount of tokens to mint
|
||||
*/
|
||||
function mint(address user, uint256 amount, uint256 index) external override onlyLendingPool {
|
||||
|
||||
|
||||
function mint(
|
||||
address user,
|
||||
uint256 amount,
|
||||
uint256 index
|
||||
) external override onlyLendingPool {
|
||||
uint256 scaledAmount = amount.rayDiv(index);
|
||||
|
||||
|
||||
//mint an equivalent amount of tokens to cover the new deposit
|
||||
_mint(user,scaledAmount);
|
||||
_mint(user, scaledAmount);
|
||||
|
||||
emit Mint(user, amount, index);
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
|
|||
|
||||
/**
|
||||
* @dev calculates the balance of the user, which is the
|
||||
* principal balance + interest generated by the principal balance
|
||||
* principal balance + interest generated by the principal balance
|
||||
* @param user the user for which the balance is being calculated
|
||||
* @return the total balance of the user
|
||||
**/
|
||||
|
@ -150,9 +150,7 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
|
|||
return 0;
|
||||
}
|
||||
|
||||
return
|
||||
currentSupplyScaled
|
||||
.rayMul(POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS));
|
||||
return currentSupplyScaled.rayMul(POOL.getReserveNormalizedIncome(UNDERLYING_ASSET_ADDRESS));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -162,16 +160,16 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
|
|||
* @return true if the user can transfer amount, false otherwise
|
||||
**/
|
||||
function isTransferAllowed(address user, uint256 amount) public override view returns (bool) {
|
||||
return POOL.balanceDecreaseAllowed(UNDERLYING_ASSET_ADDRESS, user, amount);
|
||||
return !POOL.isPaused() && POOL.balanceDecreaseAllowed(UNDERLYING_ASSET_ADDRESS, user, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev transfers the underlying asset to the target. Used by the lendingpool to transfer
|
||||
* assets in borrow(), redeem() and flashLoan()
|
||||
* @param target the target of the transfer
|
||||
* @param amount the amount to transfer
|
||||
* @return the amount transferred
|
||||
**/
|
||||
* @dev transfers the underlying asset to the target. Used by the lendingpool to transfer
|
||||
* assets in borrow(), redeem() and flashLoan()
|
||||
* @param target the target of the transfer
|
||||
* @param amount the amount to transfer
|
||||
* @return the amount transferred
|
||||
**/
|
||||
function transferUnderlyingTo(address target, uint256 amount)
|
||||
external
|
||||
override
|
||||
|
@ -187,8 +185,8 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
|
|||
address to,
|
||||
uint256 amount,
|
||||
bool validate
|
||||
) internal {
|
||||
if(validate){
|
||||
) internal {
|
||||
if (validate) {
|
||||
require(isTransferAllowed(from, amount), Errors.TRANSFER_NOT_ALLOWED);
|
||||
}
|
||||
|
||||
|
@ -199,17 +197,16 @@ contract AToken is VersionedInitializable, ERC20, IAToken {
|
|||
super._transfer(from, to, scaledAmount);
|
||||
|
||||
emit BalanceTransfer(from, to, amount, index);
|
||||
|
||||
}
|
||||
|
||||
|
||||
function _transfer(
|
||||
address from,
|
||||
address to,
|
||||
uint256 amount
|
||||
) internal override {
|
||||
|
||||
_transfer(from, to, amount, true);
|
||||
) internal override {
|
||||
_transfer(from, to, amount, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev aTokens should not receive ETH
|
||||
**/
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
"test-scenarios": "buidler test test/__setup.spec.ts test/scenario.spec.ts",
|
||||
"test-repay-with-collateral": "buidler test test/__setup.spec.ts test/repay-with-collateral.spec.ts",
|
||||
"test-liquidate-with-collateral": "buidler test test/__setup.spec.ts test/flash-liquidation-with-collateral.spec.ts",
|
||||
"test-transfers": "buidler test test/__setup.spec.ts test/atoken-transfer.spec.ts",
|
||||
"test-flash": "buidler test test/__setup.spec.ts test/flashloan.spec.ts",
|
||||
"dev:coverage": "buidler coverage --network coverage",
|
||||
"dev:deployment": "buidler dev-deployment",
|
||||
|
|
|
@ -45,7 +45,6 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => {
|
|||
);
|
||||
});
|
||||
|
||||
|
||||
it('User 0 deposits 1 WETH and user 1 tries to borrow, but the aTokens received as a transfer are not available as collateral (revert expected)', async () => {
|
||||
const {users, pool, weth} = testEnv;
|
||||
const userAddress = await pool.signer.getAddress();
|
||||
|
@ -81,4 +80,58 @@ makeSuite('AToken: Transfer', (testEnv: TestEnv) => {
|
|||
).to.be.revertedWith(TRANSFER_NOT_ALLOWED);
|
||||
});
|
||||
|
||||
it('User 0 deposits 1000 DAI. Configurator pauses pool. Transfers to user 1 reverts. Configurator unpauses the network and next transfer succees', async () => {
|
||||
const {users, pool, dai, aDai, configurator} = testEnv;
|
||||
|
||||
const amountDAItoDeposit = await convertToCurrencyDecimals(dai.address, '1000');
|
||||
|
||||
await dai.connect(users[0].signer).mint(amountDAItoDeposit);
|
||||
|
||||
// user 0 deposits 1000 DAI
|
||||
await dai.connect(users[0].signer).approve(pool.address, APPROVAL_AMOUNT_LENDING_POOL);
|
||||
await pool
|
||||
.connect(users[0].signer)
|
||||
.deposit(dai.address, amountDAItoDeposit, users[0].address, '0');
|
||||
|
||||
const user0Balance = await aDai.balanceOf(users[0].address);
|
||||
const user1Balance = await aDai.balanceOf(users[1].address);
|
||||
|
||||
// Configurator pauses the pool
|
||||
await configurator.pausePool();
|
||||
|
||||
// User 0 tries the transfer to User 1
|
||||
await expect(
|
||||
aDai.connect(users[0].signer).transfer(users[1].address, amountDAItoDeposit)
|
||||
).to.revertedWith(TRANSFER_NOT_ALLOWED);
|
||||
|
||||
const pausedFromBalance = await aDai.balanceOf(users[0].address);
|
||||
const pausedToBalance = await aDai.balanceOf(users[1].address);
|
||||
|
||||
expect(pausedFromBalance).to.be.equal(
|
||||
user0Balance.toString(),
|
||||
INVALID_TO_BALANCE_AFTER_TRANSFER
|
||||
);
|
||||
expect(pausedToBalance.toString()).to.be.equal(
|
||||
user1Balance.toString(),
|
||||
INVALID_FROM_BALANCE_AFTER_TRANSFER
|
||||
);
|
||||
|
||||
// Configurator unpauses the pool
|
||||
await configurator.unpausePool();
|
||||
|
||||
// User 0 succeeds transfer to User 1
|
||||
await aDai.connect(users[0].signer).transfer(users[1].address, amountDAItoDeposit);
|
||||
|
||||
const fromBalance = await aDai.balanceOf(users[0].address);
|
||||
const toBalance = await aDai.balanceOf(users[1].address);
|
||||
|
||||
expect(fromBalance.toString()).to.be.equal(
|
||||
user0Balance.sub(amountDAItoDeposit),
|
||||
INVALID_FROM_BALANCE_AFTER_TRANSFER
|
||||
);
|
||||
expect(toBalance.toString()).to.be.equal(
|
||||
user1Balance.add(amountDAItoDeposit),
|
||||
INVALID_TO_BALANCE_AFTER_TRANSFER
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user