mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
351 lines
11 KiB
Solidity
351 lines
11 KiB
Solidity
// SPDX-License-Identifier: agpl-3.0
|
|
pragma solidity 0.6.12;
|
|
pragma experimental ABIEncoderV2;
|
|
|
|
import {IERC20} from '../../../dependencies/openzeppelin/contracts/IERC20.sol';
|
|
import {SafeMath} from '../../../dependencies/openzeppelin/contracts/SafeMath.sol';
|
|
import {SafeERC20} from '../../../dependencies/openzeppelin/contracts/SafeERC20.sol';
|
|
import {IAToken} from '../../../interfaces/IAToken.sol';
|
|
import {Helpers} from '../helpers/Helpers.sol';
|
|
import {ValidationLogic} from './ValidationLogic.sol';
|
|
import {ReserveLogic} from './ReserveLogic.sol';
|
|
import {DataTypes} from './../types/DataTypes.sol';
|
|
|
|
import {IStableDebtToken} from '../../../interfaces/IStableDebtToken.sol';
|
|
import {IVariableDebtToken} from '../../../interfaces/IVariableDebtToken.sol';
|
|
|
|
import {UserConfiguration} from './../configuration/UserConfiguration.sol';
|
|
|
|
import {WadRayMath} from '../math/WadRayMath.sol';
|
|
|
|
/**
|
|
* @title LendingPoolBaseLogic Library
|
|
* @author Aave
|
|
* @title Implements lendingpool basic logic to perform actions to limit the contract size.
|
|
*/
|
|
|
|
library LendingPoolBaseLogic {
|
|
using ReserveLogic for DataTypes.ReserveCache;
|
|
using ReserveLogic for DataTypes.ReserveData;
|
|
using UserConfiguration for DataTypes.UserConfigurationMap;
|
|
using SafeMath for uint256;
|
|
using SafeERC20 for IERC20;
|
|
using WadRayMath for uint256;
|
|
|
|
/**
|
|
* @dev Emitted on deposit()
|
|
* @param reserve The address of the underlying asset of the reserve
|
|
* @param user The address initiating the deposit
|
|
* @param onBehalfOf The beneficiary of the deposit, receiving the aTokens
|
|
* @param amount The amount deposited
|
|
* @param referral The referral code used
|
|
**/
|
|
event Deposit(
|
|
address indexed reserve,
|
|
address user,
|
|
address indexed onBehalfOf,
|
|
uint256 amount,
|
|
uint16 indexed referral
|
|
);
|
|
|
|
/**
|
|
* @dev Emitted on withdraw()
|
|
* @param reserve The address of the underlyng asset being withdrawn
|
|
* @param user The address initiating the withdrawal, owner of aTokens
|
|
* @param to Address that will receive the underlying
|
|
* @param amount The amount to be withdrawn
|
|
**/
|
|
event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount);
|
|
|
|
/**
|
|
* @dev Emitted on borrow() and flashLoan() when debt needs to be opened
|
|
* @param reserve The address of the underlying asset being borrowed
|
|
* @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just
|
|
* initiator of the transaction on flashLoan()
|
|
* @param onBehalfOf The address that will be getting the debt
|
|
* @param amount The amount borrowed out
|
|
* @param borrowRateMode The rate mode: 1 for Stable, 2 for Variable
|
|
* @param borrowRate The numeric rate at which the user has borrowed
|
|
* @param referral The referral code used
|
|
**/
|
|
event Borrow(
|
|
address indexed reserve,
|
|
address user,
|
|
address indexed onBehalfOf,
|
|
uint256 amount,
|
|
uint256 borrowRateMode,
|
|
uint256 borrowRate,
|
|
uint16 indexed referral
|
|
);
|
|
|
|
/**
|
|
* @dev Emitted on repay()
|
|
* @param reserve The address of the underlying asset of the reserve
|
|
* @param user The beneficiary of the repayment, getting his debt reduced
|
|
* @param repayer The address of the user initiating the repay(), providing the funds
|
|
* @param amount The amount repaid
|
|
**/
|
|
event Repay(
|
|
address indexed reserve,
|
|
address indexed user,
|
|
address indexed repayer,
|
|
uint256 amount
|
|
);
|
|
|
|
/**
|
|
* @dev Emitted on setUserUseReserveAsCollateral()
|
|
* @param reserve The address of the underlying asset of the reserve
|
|
* @param user The address of the user enabling the usage as collateral
|
|
**/
|
|
event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user);
|
|
|
|
/**
|
|
* @dev Emitted on setUserUseReserveAsCollateral()
|
|
* @param reserve The address of the underlying asset of the reserve
|
|
* @param user The address of the user enabling the usage as collateral
|
|
**/
|
|
event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user);
|
|
|
|
function _executeDeposit(
|
|
DataTypes.ReserveData storage reserve,
|
|
DataTypes.UserConfigurationMap storage userConfig,
|
|
address asset,
|
|
uint256 amount,
|
|
address onBehalfOf,
|
|
uint16 referralCode
|
|
) public {
|
|
DataTypes.ReserveCache memory reserveCache = reserve.cache();
|
|
|
|
reserve.updateState(reserveCache);
|
|
|
|
ValidationLogic.validateDeposit(reserveCache, amount);
|
|
|
|
reserve.updateInterestRates(reserveCache, asset, amount, 0);
|
|
|
|
IERC20(asset).safeTransferFrom(msg.sender, reserveCache.aTokenAddress, amount);
|
|
|
|
bool isFirstDeposit =
|
|
IAToken(reserveCache.aTokenAddress).mint(onBehalfOf, amount, reserveCache.nextLiquidityIndex);
|
|
|
|
if (isFirstDeposit) {
|
|
userConfig.setUsingAsCollateral(reserve.id, true);
|
|
emit ReserveUsedAsCollateralEnabled(asset, onBehalfOf);
|
|
}
|
|
|
|
emit Deposit(asset, msg.sender, onBehalfOf, amount, referralCode);
|
|
}
|
|
|
|
function _executeWithdraw(
|
|
mapping(address => DataTypes.ReserveData) storage reserves,
|
|
DataTypes.UserConfigurationMap storage userConfig,
|
|
address asset,
|
|
uint256 amount,
|
|
address to,
|
|
mapping(uint256 => address) storage reservesList,
|
|
uint256 reservesCount,
|
|
address priceOracle
|
|
) public returns (uint256) {
|
|
DataTypes.ReserveData storage reserve = reserves[asset];
|
|
DataTypes.ReserveCache memory reserveCache = reserve.cache();
|
|
|
|
reserve.updateState(reserveCache);
|
|
|
|
uint256 userBalance =
|
|
IAToken(reserveCache.aTokenAddress).scaledBalanceOf(msg.sender).rayMul(
|
|
reserveCache.nextLiquidityIndex
|
|
);
|
|
|
|
uint256 amountToWithdraw = amount;
|
|
|
|
if (amount == type(uint256).max) {
|
|
amountToWithdraw = userBalance;
|
|
}
|
|
|
|
ValidationLogic.validateWithdraw(reserveCache, amountToWithdraw, userBalance);
|
|
|
|
reserve.updateInterestRates(reserveCache, asset, 0, amountToWithdraw);
|
|
|
|
IAToken(reserveCache.aTokenAddress).burn(
|
|
msg.sender,
|
|
to,
|
|
amountToWithdraw,
|
|
reserveCache.nextLiquidityIndex
|
|
);
|
|
|
|
if (userConfig.isUsingAsCollateral(reserve.id)) {
|
|
if (userConfig.isBorrowingAny()) {
|
|
_validateHFAndLtv(asset, reserves, userConfig, reservesList, reservesCount, priceOracle);
|
|
}
|
|
|
|
if (amountToWithdraw == userBalance) {
|
|
userConfig.setUsingAsCollateral(reserve.id, false);
|
|
emit ReserveUsedAsCollateralDisabled(asset, msg.sender);
|
|
}
|
|
}
|
|
|
|
emit Withdraw(asset, msg.sender, to, amountToWithdraw);
|
|
|
|
return amountToWithdraw;
|
|
}
|
|
|
|
function _validateHFAndLtv(
|
|
address asset,
|
|
mapping(address => DataTypes.ReserveData) storage reserves,
|
|
DataTypes.UserConfigurationMap storage userConfig,
|
|
mapping(uint256 => address) storage reservesList,
|
|
uint256 reservesCount,
|
|
address priceOracle
|
|
) public {
|
|
ValidationLogic.validateHFAndLtv(
|
|
asset,
|
|
msg.sender,
|
|
reserves,
|
|
userConfig,
|
|
reservesList,
|
|
reservesCount,
|
|
priceOracle
|
|
);
|
|
}
|
|
|
|
function _executeBorrow(
|
|
mapping(address => DataTypes.ReserveData) storage reserves,
|
|
DataTypes.ReserveCache memory reserveCache,
|
|
DataTypes.UserConfigurationMap storage userConfig,
|
|
DataTypes.ExecuteBorrowParams memory vars
|
|
) public {
|
|
DataTypes.ReserveData storage reserve = reserves[vars.asset];
|
|
|
|
uint256 currentStableRate = 0;
|
|
bool isFirstBorrowing = false;
|
|
|
|
if (DataTypes.InterestRateMode(vars.interestRateMode) == DataTypes.InterestRateMode.STABLE) {
|
|
currentStableRate = reserve.currentStableBorrowRate;
|
|
isFirstBorrowing = IStableDebtToken(reserveCache.stableDebtTokenAddress).mint(
|
|
vars.user,
|
|
vars.onBehalfOf,
|
|
vars.amount,
|
|
currentStableRate
|
|
);
|
|
reserveCache.refreshDebt(vars.amount, 0, 0, 0);
|
|
} else {
|
|
isFirstBorrowing = IVariableDebtToken(reserveCache.variableDebtTokenAddress).mint(
|
|
vars.user,
|
|
vars.onBehalfOf,
|
|
vars.amount,
|
|
reserveCache.nextVariableBorrowIndex
|
|
);
|
|
reserveCache.refreshDebt(0, 0, vars.amount, 0);
|
|
}
|
|
|
|
if (isFirstBorrowing) {
|
|
userConfig.setBorrowing(reserve.id, true);
|
|
}
|
|
|
|
reserve.updateInterestRates(
|
|
reserveCache,
|
|
vars.asset,
|
|
0,
|
|
vars.releaseUnderlying ? vars.amount : 0
|
|
);
|
|
|
|
if (vars.releaseUnderlying) {
|
|
IAToken(reserveCache.aTokenAddress).transferUnderlyingTo(vars.user, vars.amount);
|
|
}
|
|
|
|
emit Borrow(
|
|
vars.asset,
|
|
vars.user,
|
|
vars.onBehalfOf,
|
|
vars.amount,
|
|
vars.interestRateMode,
|
|
DataTypes.InterestRateMode(vars.interestRateMode) == DataTypes.InterestRateMode.STABLE
|
|
? currentStableRate
|
|
: reserve.currentVariableBorrowRate,
|
|
vars.referralCode
|
|
);
|
|
}
|
|
|
|
function _executeRepay(
|
|
DataTypes.ReserveData storage reserve,
|
|
DataTypes.UserConfigurationMap storage userConfig,
|
|
address asset,
|
|
uint256 amount,
|
|
uint256 rateMode,
|
|
address onBehalfOf,
|
|
address lastBorrower,
|
|
uint40 lastBorrowTimestamp
|
|
) public returns (uint256) {
|
|
DataTypes.ReserveCache memory reserveCache = reserve.cache();
|
|
(uint256 stableDebt, uint256 variableDebt) = Helpers.getUserCurrentDebt(onBehalfOf, reserve);
|
|
DataTypes.InterestRateMode interestRateMode = DataTypes.InterestRateMode(rateMode);
|
|
|
|
ValidationLogic.validateRepay(
|
|
lastBorrower,
|
|
lastBorrowTimestamp,
|
|
reserveCache,
|
|
amount,
|
|
interestRateMode,
|
|
onBehalfOf,
|
|
stableDebt,
|
|
variableDebt
|
|
);
|
|
|
|
uint256 paybackAmount =
|
|
interestRateMode == DataTypes.InterestRateMode.STABLE ? stableDebt : variableDebt;
|
|
|
|
if (amount < paybackAmount) {
|
|
paybackAmount = amount;
|
|
}
|
|
|
|
reserve.updateState(reserveCache);
|
|
|
|
if (interestRateMode == DataTypes.InterestRateMode.STABLE) {
|
|
IStableDebtToken(reserveCache.stableDebtTokenAddress).burn(onBehalfOf, paybackAmount);
|
|
reserveCache.refreshDebt(0, paybackAmount, 0, 0);
|
|
} else {
|
|
IVariableDebtToken(reserveCache.variableDebtTokenAddress).burn(
|
|
onBehalfOf,
|
|
paybackAmount,
|
|
reserveCache.nextVariableBorrowIndex
|
|
);
|
|
reserveCache.refreshDebt(0, 0, 0, paybackAmount);
|
|
}
|
|
|
|
return
|
|
_executeRepayHelper(
|
|
reserve,
|
|
reserveCache,
|
|
userConfig,
|
|
asset,
|
|
onBehalfOf,
|
|
paybackAmount,
|
|
variableDebt,
|
|
stableDebt
|
|
);
|
|
}
|
|
|
|
function _executeRepayHelper(
|
|
DataTypes.ReserveData storage reserve,
|
|
DataTypes.ReserveCache memory reserveCache,
|
|
DataTypes.UserConfigurationMap storage userConfig,
|
|
address asset,
|
|
address onBehalfOf,
|
|
uint256 paybackAmount,
|
|
uint256 variableDebt,
|
|
uint256 stableDebt
|
|
) public returns (uint256) {
|
|
reserve.updateInterestRates(reserveCache, asset, paybackAmount, 0);
|
|
|
|
if (stableDebt.add(variableDebt).sub(paybackAmount) == 0) {
|
|
userConfig.setBorrowing(reserve.id, false);
|
|
}
|
|
|
|
IERC20(asset).safeTransferFrom(msg.sender, reserveCache.aTokenAddress, paybackAmount);
|
|
|
|
IAToken(reserveCache.aTokenAddress).handleRepayment(msg.sender, paybackAmount);
|
|
|
|
emit Repay(asset, onBehalfOf, msg.sender, paybackAmount);
|
|
|
|
return paybackAmount;
|
|
}
|
|
} |