aave-protocol-v2/contracts/protocol/lendingpool/PermissionedLendingPool.sol
2021-06-30 13:12:14 +02:00

356 lines
14 KiB
Solidity

// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
import {LendingPool} from './LendingPool.sol';
import {IPermissionManager} from '../../interfaces/IPermissionManager.sol';
import {IPermissionedLendingPool} from '../../interfaces/IPermissionedLendingPool.sol';
import {ILendingPool} from '../../interfaces/ILendingPool.sol';
import {Errors} from '../libraries/helpers/Errors.sol';
import {DataTypes} from '../libraries/types/DataTypes.sol';
/**
* @title PermissionedLendingPool
* @notice This smart contracts adds a permission layer to the LendingPool contract to enable whitelisting of users interacting with it
* @author Aave
**/
contract PermissionedLendingPool is IPermissionedLendingPool, LendingPool {
//identifier for the permission manager contract in the addresses provider
bytes32 public constant PERMISSION_MANAGER = keccak256('PERMISSION_MANAGER');
modifier onlyDepositors(address user) {
require(
_isInRole(user, DataTypes.Roles.DEPOSITOR) &&
((user == msg.sender) || _isInRole(msg.sender, DataTypes.Roles.DEPOSITOR)),
Errors.PLP_DEPOSITOR_UNAUTHORIZED
);
_;
}
modifier onlyUserPermissionAdmin(address user) {
require(_isPermissionAdminOf(user, msg.sender), Errors.PLP_INVALID_PERMISSION_ADMIN);
_;
}
modifier onlyValidPermissionAdmin(address user) {
require(_permissionAdminValid(user), Errors.PLP_INVALID_PERMISSION_ADMIN);
_;
}
modifier onlyBorrowers(address user) {
require(
_isInRole(user, DataTypes.Roles.BORROWER) &&
((user == msg.sender) || _isInRole(msg.sender, DataTypes.Roles.BORROWER)),
Errors.PLP_BORROWER_UNAUTHORIZED
);
_;
}
modifier onlyLiquidators {
require(_isInRole(msg.sender, DataTypes.Roles.LIQUIDATOR), Errors.PLP_LIQUIDATOR_UNAUTHORIZED);
_;
}
modifier onlyStableRateManagers {
require(
_isInRole(msg.sender, DataTypes.Roles.STABLE_RATE_MANAGER),
Errors.PLP_CALLER_NOT_STABLE_RATE_MANAGER
);
_;
}
/**
* @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
* - E.g. User deposits 100 USDC and gets in return 100 aUSDC
* @param asset The address of the underlying asset to deposit
* @param amount The amount to be deposited
* @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
* wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
* is a different wallet
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
**/
function deposit(
address asset,
uint256 amount,
address onBehalfOf,
uint16 referralCode
)
public
virtual
override(ILendingPool, LendingPool)
onlyDepositors(onBehalfOf)
onlyValidPermissionAdmin(onBehalfOf)
{
super.deposit(asset, amount, onBehalfOf, referralCode);
}
/**
* @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned
* E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC
* @param asset The address of the underlying asset to withdraw
* @param amount The underlying amount to be withdrawn
* - Send the value type(uint256).max in order to withdraw the whole aToken balance
* @param to Address that will receive the underlying, same as msg.sender if the user
* wants to receive it on his own wallet, or a different address if the beneficiary is a
* different wallet
* @return The final amount withdrawn
**/
function withdraw(
address asset,
uint256 amount,
address to
)
public
virtual
override(ILendingPool, LendingPool)
onlyDepositors(msg.sender)
returns (uint256)
{
return super.withdraw(asset, amount, to);
}
/**
* @dev Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower
* already deposited enough collateral, or he was given enough allowance by a credit delegator on the
* corresponding debt token (StableDebtToken or VariableDebtToken)
* - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet
* and 100 stable/variable debt tokens, depending on the `interestRateMode`
* @param asset The address of the underlying asset to borrow
* @param amount The amount to be borrowed
* @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
* @param onBehalfOf Address of the user who will receive the debt. Should be the address of the borrower itself
* calling the function if he wants to borrow against his own collateral, or the address of the credit delegator
* if he has been given credit delegation allowance
**/
function borrow(
address asset,
uint256 amount,
uint256 interestRateMode,
uint16 referralCode,
address onBehalfOf
)
public
virtual
override(ILendingPool, LendingPool)
onlyBorrowers(onBehalfOf)
onlyValidPermissionAdmin(onBehalfOf)
{
super.borrow(asset, amount, interestRateMode, referralCode, onBehalfOf);
}
/**
* @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned
* - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address
* @param asset The address of the borrowed underlying asset previously borrowed
* @param amount The amount to repay
* - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`
* @param rateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable
* @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the
* user calling the function if he wants to reduce/remove his own debt, or the address of any other
* other borrower whose debt should be removed
* @return The final amount repaid
**/
function repay(
address asset,
uint256 amount,
uint256 rateMode,
address onBehalfOf
)
public
virtual
override(ILendingPool, LendingPool)
onlyBorrowers(onBehalfOf)
onlyValidPermissionAdmin(onBehalfOf)
returns (uint256)
{
return super.repay(asset, amount, rateMode, onBehalfOf);
}
/**
* @dev Allows a borrower to swap his debt between stable and variable mode, or viceversa
* @param asset The address of the underlying asset borrowed
* @param rateMode The rate mode that the user wants to swap to
**/
function swapBorrowRateMode(address asset, uint256 rateMode)
public
virtual
override(ILendingPool, LendingPool)
onlyBorrowers(msg.sender)
onlyValidPermissionAdmin(msg.sender)
{
super.swapBorrowRateMode(asset, rateMode);
}
/**
* @dev Rebalances the stable interest rate of a user to the current stable rate defined on the reserve.
* - Users can be rebalanced if the following conditions are satisfied:
* 1. Usage ratio is above 95%
* 2. the current deposit APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too much has been
* borrowed at a stable rate and depositors are not earning enough
* @param asset The address of the underlying asset borrowed
* @param user The address of the user to be rebalanced
**/
function rebalanceStableBorrowRate(address asset, address user)
public
virtual
override(ILendingPool, LendingPool)
onlyStableRateManagers
{
super.rebalanceStableBorrowRate(asset, user);
}
/**
* @dev Allows depositors to enable/disable a specific deposited asset as collateral
* @param asset The address of the underlying asset deposited
* @param useAsCollateral `true` if the user wants to use the deposit as collateral, `false` otherwise
**/
function setUserUseReserveAsCollateral(address asset, bool useAsCollateral)
public
virtual
override(ILendingPool, LendingPool)
onlyDepositors(msg.sender)
onlyValidPermissionAdmin(msg.sender)
{
super.setUserUseReserveAsCollateral(asset, useAsCollateral);
}
/**
* @dev Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1
* - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives
* a proportionally amount of the `collateralAsset` plus a bonus to cover market risk
* @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
* @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
* @param user The address of the borrower getting liquidated
* @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
* @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants
* to receive the underlying collateral asset directly
**/
function liquidationCall(
address collateralAsset,
address debtAsset,
address user,
uint256 debtToCover,
bool receiveAToken
)
public
virtual
override(ILendingPool, LendingPool)
onlyLiquidators
onlyValidPermissionAdmin(msg.sender)
{
super.liquidationCall(collateralAsset, debtAsset, user, debtToCover, receiveAToken);
}
/**
* @dev Function to seize the collateral of a user. Only whitelisters of the user can call this function
* @param assets The addresses of the underlying assets to seize
* @param to The address that will receive the funds
**/
function seize(
address user,
address[] calldata assets,
address to
) public virtual override(IPermissionedLendingPool) onlyUserPermissionAdmin(user) whenNotPaused {
address collateralManager = _addressesProvider.getLendingPoolCollateralManager();
//solium-disable-next-line
(bool success, bytes memory result) =
collateralManager.delegatecall(
abi.encodeWithSignature('seize(address,address[],address)', user, assets, to)
);
require(success, Errors.LP_LIQUIDATION_CALL_FAILED);
(uint256 returnCode, string memory returnMessage) = abi.decode(result, (uint256, string));
require(returnCode == 0, string(abi.encodePacked(returnMessage)));
}
/**
* @dev Allows smartcontracts to access the liquidity of the pool within one transaction,
* as long as the amount taken plus a fee is returned.
* IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept into consideration.
* For further details please visit https://developers.aave.com
* @param receiverAddress The address of the contract receiving the funds, implementing the IFlashLoanReceiver interface
* @param assets The addresses of the assets being flash-borrowed
* @param amounts The amounts amounts being flash-borrowed
* @param modes Types of the debt to open if the flash loan is not returned:
* 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver
* 1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
* 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
* @param onBehalfOf The address that will receive the debt in the case of using on `modes` 1 or 2
* @param params Variadic packed params to pass to the receiver as extra information
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
**/
function flashLoan(
address receiverAddress,
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata modes,
address onBehalfOf,
bytes calldata params,
uint16 referralCode
) public virtual override(ILendingPool, LendingPool) {
//validating modes
for (uint256 i = 0; i < modes.length; i++) {
if (modes[i] == uint256(DataTypes.InterestRateMode.NONE)) {
require(_isInRole(msg.sender, DataTypes.Roles.BORROWER), Errors.PLP_BORROWER_UNAUTHORIZED);
require(_permissionAdminValid(msg.sender), Errors.PLP_INVALID_PERMISSION_ADMIN);
} else {
require(_isInRole(onBehalfOf, DataTypes.Roles.BORROWER), Errors.PLP_BORROWER_UNAUTHORIZED);
require(_permissionAdminValid(onBehalfOf), Errors.PLP_INVALID_PERMISSION_ADMIN);
}
}
super.flashLoan(receiverAddress, assets, amounts, modes, onBehalfOf, params, referralCode);
}
/**
* @dev Validates and finalizes an aToken transfer
* - Only callable by the overlying aToken of the `asset`
* @param asset The address of the underlying asset of the aToken
* @param from The user from which the aTokens are transferred
* @param to The user receiving the aTokens
* @param amount The amount being transferred/withdrawn
* @param balanceFromBefore The aToken balance of the `from` user before the transfer
* @param balanceToBefore The aToken balance of the `to` user before the transfer
*/
function finalizeTransfer(
address asset,
address from,
address to,
uint256 amount,
uint256 balanceFromBefore,
uint256 balanceToBefore
) public override(ILendingPool, LendingPool) {
require(_isInRole(from, DataTypes.Roles.DEPOSITOR), Errors.VL_TRANSFER_NOT_ALLOWED);
require(_isInRole(to, DataTypes.Roles.DEPOSITOR), Errors.VL_TRANSFER_NOT_ALLOWED);
super.finalizeTransfer(asset, from, to, amount, balanceFromBefore, balanceToBefore);
}
function _isPermissionAdminOf(address user, address caller) internal view returns (bool) {
return
IPermissionManager(_addressesProvider.getAddress(PERMISSION_MANAGER)).getUserPermissionAdmin(
user
) == caller;
}
function _isInRole(address user, DataTypes.Roles role) internal view returns (bool) {
return
IPermissionManager(_addressesProvider.getAddress(PERMISSION_MANAGER)).isInRole(
user,
uint256(role)
);
}
function _permissionAdminValid(address user) internal view returns (bool) {
return
IPermissionManager(_addressesProvider.getAddress(PERMISSION_MANAGER))
.isUserPermissionAdminValid(user);
}
}