mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
Merge branch 'feat/funds-allocation' into 'master'
Feat/funds allocation Closes #6 See merge request aave-tech/protocol-v2!4
This commit is contained in:
commit
7b66a05c5d
|
@ -6,6 +6,7 @@ import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
|
||||||
import '../interfaces/IFlashLoanReceiver.sol';
|
import '../interfaces/IFlashLoanReceiver.sol';
|
||||||
import '../../interfaces/ILendingPoolAddressesProvider.sol';
|
import '../../interfaces/ILendingPoolAddressesProvider.sol';
|
||||||
import '../../libraries/UniversalERC20.sol';
|
import '../../libraries/UniversalERC20.sol';
|
||||||
|
import '@nomiclabs/buidler/console.sol';
|
||||||
|
|
||||||
abstract contract FlashLoanReceiverBase is IFlashLoanReceiver {
|
abstract contract FlashLoanReceiverBase is IFlashLoanReceiver {
|
||||||
using UniversalERC20 for IERC20;
|
using UniversalERC20 for IERC20;
|
||||||
|
@ -19,10 +20,12 @@ abstract contract FlashLoanReceiverBase is IFlashLoanReceiver {
|
||||||
|
|
||||||
receive() external payable {}
|
receive() external payable {}
|
||||||
|
|
||||||
function transferFundsBackToPoolInternal(address _reserve, uint256 _amount) internal {
|
function transferFundsBackInternal(
|
||||||
address payable pool = payable(addressesProvider.getLendingPool());
|
address _reserve,
|
||||||
|
address _destination,
|
||||||
transferInternal(pool, _reserve, _amount);
|
uint256 _amount
|
||||||
|
) internal {
|
||||||
|
transferInternal(payable(_destination), _reserve, _amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
function transferInternal(
|
function transferInternal(
|
||||||
|
@ -30,12 +33,6 @@ abstract contract FlashLoanReceiverBase is IFlashLoanReceiver {
|
||||||
address _reserve,
|
address _reserve,
|
||||||
uint256 _amount
|
uint256 _amount
|
||||||
) internal {
|
) internal {
|
||||||
if (IERC20(_reserve).isETH()) {
|
|
||||||
//solium-disable-next-line
|
|
||||||
_destination.call{value: _amount}('');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IERC20(_reserve).universalTransfer(_destination, _amount);
|
IERC20(_reserve).universalTransfer(_destination, _amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ pragma solidity ^0.6.8;
|
||||||
interface IFlashLoanReceiver {
|
interface IFlashLoanReceiver {
|
||||||
function executeOperation(
|
function executeOperation(
|
||||||
address _reserve,
|
address _reserve,
|
||||||
|
address _destination,
|
||||||
uint256 _amount,
|
uint256 _amount,
|
||||||
uint256 _fee,
|
uint256 _fee,
|
||||||
bytes calldata _params
|
bytes calldata _params
|
||||||
|
|
|
@ -262,7 +262,7 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
|
||||||
|
|
||||||
ValidationLogic.validateDeposit(reserve, _amount);
|
ValidationLogic.validateDeposit(reserve, _amount);
|
||||||
|
|
||||||
AToken aToken = AToken(reserve.aTokenAddress);
|
AToken aToken = AToken(payable(reserve.aTokenAddress));
|
||||||
|
|
||||||
bool isFirstDeposit = aToken.balanceOf(msg.sender) == 0;
|
bool isFirstDeposit = aToken.balanceOf(msg.sender) == 0;
|
||||||
|
|
||||||
|
@ -276,8 +276,8 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
|
||||||
//minting AToken to user 1:1 with the specific exchange rate
|
//minting AToken to user 1:1 with the specific exchange rate
|
||||||
aToken.mintOnDeposit(msg.sender, _amount);
|
aToken.mintOnDeposit(msg.sender, _amount);
|
||||||
|
|
||||||
//transfer to the core contract
|
//transfer to the aToken contract
|
||||||
IERC20(_reserve).universalTransferFromSenderToThis(_amount, true);
|
IERC20(_reserve).universalTransferFrom(msg.sender, address(aToken), _amount, true);
|
||||||
|
|
||||||
//solium-disable-next-line
|
//solium-disable-next-line
|
||||||
emit Deposit(_reserve, msg.sender, _amount, _referralCode, block.timestamp);
|
emit Deposit(_reserve, msg.sender, _amount, _referralCode, block.timestamp);
|
||||||
|
@ -299,16 +299,19 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
|
||||||
ReserveLogic.ReserveData storage reserve = reserves[_reserve];
|
ReserveLogic.ReserveData storage reserve = reserves[_reserve];
|
||||||
UserLogic.UserReserveData storage user = usersReserveData[_user][_reserve];
|
UserLogic.UserReserveData storage user = usersReserveData[_user][_reserve];
|
||||||
|
|
||||||
|
AToken aToken = AToken(payable(reserve.aTokenAddress));
|
||||||
|
|
||||||
ValidationLogic.validateRedeem(reserve, _reserve, _amount);
|
ValidationLogic.validateRedeem(reserve, _reserve, _amount);
|
||||||
|
|
||||||
|
reserve.updateCumulativeIndexesAndTimestamp();
|
||||||
|
|
||||||
|
reserve.updateInterestRates(_reserve, 0, _amount);
|
||||||
|
|
||||||
if (_aTokenBalanceAfterRedeem == 0) {
|
if (_aTokenBalanceAfterRedeem == 0) {
|
||||||
user.useAsCollateral = false;
|
user.useAsCollateral = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
reserve.updateCumulativeIndexesAndTimestamp();
|
AToken(reserve.aTokenAddress).transferUnderlyingTo(_user, _amount);
|
||||||
reserve.updateInterestRates(_reserve, 0, _amount);
|
|
||||||
|
|
||||||
IERC20(_reserve).universalTransfer(_user, _amount);
|
|
||||||
|
|
||||||
//solium-disable-next-line
|
//solium-disable-next-line
|
||||||
emit RedeemUnderlying(_reserve, _user, _amount, block.timestamp);
|
emit RedeemUnderlying(_reserve, _user, _amount, block.timestamp);
|
||||||
|
@ -368,7 +371,7 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
|
||||||
reserve.updateInterestRates(_reserve, 0, _amount);
|
reserve.updateInterestRates(_reserve, 0, _amount);
|
||||||
|
|
||||||
//if we reached this point, we can transfer
|
//if we reached this point, we can transfer
|
||||||
IERC20(_reserve).universalTransfer(msg.sender, _amount);
|
AToken(reserve.aTokenAddress).transferUnderlyingTo(msg.sender, _amount);
|
||||||
|
|
||||||
emit Borrow(
|
emit Borrow(
|
||||||
_reserve,
|
_reserve,
|
||||||
|
@ -446,7 +449,12 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
|
||||||
|
|
||||||
reserve.updateInterestRates(_reserve, vars.paybackAmount, 0);
|
reserve.updateInterestRates(_reserve, vars.paybackAmount, 0);
|
||||||
|
|
||||||
IERC20(_reserve).universalTransferFromSenderToThis(vars.paybackAmount, false);
|
IERC20(_reserve).universalTransferFrom(
|
||||||
|
msg.sender,
|
||||||
|
reserve.aTokenAddress,
|
||||||
|
vars.paybackAmount,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
if (IERC20(_reserve).isETH()) {
|
if (IERC20(_reserve).isETH()) {
|
||||||
//send excess ETH back to the caller if needed
|
//send excess ETH back to the caller if needed
|
||||||
|
@ -635,6 +643,7 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
|
||||||
uint256 protocolFeeBips;
|
uint256 protocolFeeBips;
|
||||||
uint256 amountFee;
|
uint256 amountFee;
|
||||||
uint256 protocolFee;
|
uint256 protocolFee;
|
||||||
|
address payable aTokenAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -655,8 +664,10 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
|
||||||
|
|
||||||
ReserveLogic.ReserveData storage reserve = reserves[_reserve];
|
ReserveLogic.ReserveData storage reserve = reserves[_reserve];
|
||||||
|
|
||||||
|
vars.aTokenAddress = payable(reserve.aTokenAddress);
|
||||||
|
|
||||||
//check that the reserve has enough available liquidity
|
//check that the reserve has enough available liquidity
|
||||||
vars.availableLiquidityBefore = IERC20(_reserve).universalBalanceOf(address(this));
|
vars.availableLiquidityBefore = IERC20(_reserve).universalBalanceOf(vars.aTokenAddress);
|
||||||
|
|
||||||
//calculate amount fee
|
//calculate amount fee
|
||||||
vars.amountFee = _amount.mul(FLASHLOAN_FEE_TOTAL).div(10000);
|
vars.amountFee = _amount.mul(FLASHLOAN_FEE_TOTAL).div(10000);
|
||||||
|
@ -679,13 +690,13 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
|
||||||
address payable userPayable = address(uint160(_receiver));
|
address payable userPayable = address(uint160(_receiver));
|
||||||
|
|
||||||
//transfer funds to the receiver
|
//transfer funds to the receiver
|
||||||
IERC20(_reserve).universalTransfer(userPayable, _amount);
|
AToken(vars.aTokenAddress).transferUnderlyingTo(userPayable, _amount);
|
||||||
|
|
||||||
//execute action of the receiver
|
//execute action of the receiver
|
||||||
receiver.executeOperation(_reserve, _amount, vars.amountFee, _params);
|
receiver.executeOperation(_reserve, vars.aTokenAddress, _amount, vars.amountFee, _params);
|
||||||
|
|
||||||
//check that the actual balance of the core contract includes the returned amount
|
//check that the actual balance of the core contract includes the returned amount
|
||||||
uint256 availableLiquidityAfter = IERC20(_reserve).universalBalanceOf(address(this));
|
uint256 availableLiquidityAfter = IERC20(_reserve).universalBalanceOf(vars.aTokenAddress);
|
||||||
|
|
||||||
require(
|
require(
|
||||||
availableLiquidityAfter == vars.availableLiquidityBefore.add(vars.amountFee),
|
availableLiquidityAfter == vars.availableLiquidityBefore.add(vars.amountFee),
|
||||||
|
@ -699,7 +710,11 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
|
||||||
vars.protocolFee
|
vars.protocolFee
|
||||||
);
|
);
|
||||||
|
|
||||||
IERC20(_reserve).universalTransfer(addressesProvider.getTokenDistributor(), vars.protocolFee);
|
//transfer funds to the receiver
|
||||||
|
AToken(vars.aTokenAddress).transferUnderlyingTo(
|
||||||
|
addressesProvider.getTokenDistributor(),
|
||||||
|
vars.protocolFee
|
||||||
|
);
|
||||||
|
|
||||||
//solium-disable-next-line
|
//solium-disable-next-line
|
||||||
emit FlashLoan(_receiver, _reserve, _amount, vars.amountFee, vars.protocolFee, block.timestamp);
|
emit FlashLoan(_receiver, _reserve, _amount, vars.amountFee, vars.protocolFee, block.timestamp);
|
||||||
|
@ -777,7 +792,7 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
|
||||||
{
|
{
|
||||||
ReserveLogic.ReserveData memory reserve = reserves[_reserve];
|
ReserveLogic.ReserveData memory reserve = reserves[_reserve];
|
||||||
return (
|
return (
|
||||||
IERC20(_reserve).universalBalanceOf(address(this)),
|
IERC20(_reserve).universalBalanceOf(reserve.aTokenAddress),
|
||||||
IERC20(reserve.stableDebtTokenAddress).totalSupply(),
|
IERC20(reserve.stableDebtTokenAddress).totalSupply(),
|
||||||
IERC20(reserve.variableDebtTokenAddress).totalSupply(),
|
IERC20(reserve.variableDebtTokenAddress).totalSupply(),
|
||||||
reserve.currentLiquidityRate,
|
reserve.currentLiquidityRate,
|
||||||
|
|
|
@ -201,13 +201,21 @@ contract LendingPoolLiquidationManager is ReentrancyGuard, VersionedInitializabl
|
||||||
//of _collateral to cover the actual amount that is being liquidated, hence we liquidate
|
//of _collateral to cover the actual amount that is being liquidated, hence we liquidate
|
||||||
//a smaller amount
|
//a smaller amount
|
||||||
|
|
||||||
|
vars.collateralAtoken = AToken(payable(collateralReserve.aTokenAddress));
|
||||||
|
|
||||||
|
//if principalAmountNeeded < vars.ActualAmountToLiquidate, there isn't enough
|
||||||
|
//of _collateral to cover the actual amount that is being liquidated, hence we liquidate
|
||||||
|
//a smaller amount
|
||||||
|
|
||||||
if (vars.principalAmountNeeded < vars.actualAmountToLiquidate) {
|
if (vars.principalAmountNeeded < vars.actualAmountToLiquidate) {
|
||||||
vars.actualAmountToLiquidate = vars.principalAmountNeeded;
|
vars.actualAmountToLiquidate = vars.principalAmountNeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if liquidator reclaims the underlying asset, we make sure there is enough available collateral in the reserve
|
//if liquidator reclaims the underlying asset, we make sure there is enough available collateral in the reserve
|
||||||
if (!_receiveAToken) {
|
if (!_receiveAToken) {
|
||||||
uint256 currentAvailableCollateral = IERC20(_collateral).universalBalanceOf(address(this));
|
uint256 currentAvailableCollateral = IERC20(_collateral).universalBalanceOf(
|
||||||
|
address(vars.collateralAtoken)
|
||||||
|
);
|
||||||
if (currentAvailableCollateral < vars.maxCollateralToLiquidate) {
|
if (currentAvailableCollateral < vars.maxCollateralToLiquidate) {
|
||||||
return (
|
return (
|
||||||
uint256(LiquidationErrors.NOT_ENOUGH_LIQUIDITY),
|
uint256(LiquidationErrors.NOT_ENOUGH_LIQUIDITY),
|
||||||
|
@ -216,7 +224,6 @@ contract LendingPoolLiquidationManager is ReentrancyGuard, VersionedInitializabl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO Burn debt tokens
|
|
||||||
if (vars.userVariableDebt >= vars.actualAmountToLiquidate) {
|
if (vars.userVariableDebt >= vars.actualAmountToLiquidate) {
|
||||||
IVariableDebtToken(principalReserve.variableDebtTokenAddress).burn(
|
IVariableDebtToken(principalReserve.variableDebtTokenAddress).burn(
|
||||||
_user,
|
_user,
|
||||||
|
@ -233,8 +240,6 @@ contract LendingPoolLiquidationManager is ReentrancyGuard, VersionedInitializabl
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
vars.collateralAtoken = AToken(collateralReserve.aTokenAddress);
|
|
||||||
|
|
||||||
//if liquidator reclaims the aToken, he receives the equivalent atoken amount
|
//if liquidator reclaims the aToken, he receives the equivalent atoken amount
|
||||||
if (_receiveAToken) {
|
if (_receiveAToken) {
|
||||||
vars.collateralAtoken.transferOnLiquidation(_user, msg.sender, vars.maxCollateralToLiquidate);
|
vars.collateralAtoken.transferOnLiquidation(_user, msg.sender, vars.maxCollateralToLiquidate);
|
||||||
|
@ -242,12 +247,16 @@ contract LendingPoolLiquidationManager is ReentrancyGuard, VersionedInitializabl
|
||||||
//otherwise receives the underlying asset
|
//otherwise receives the underlying asset
|
||||||
//burn the equivalent amount of atoken
|
//burn the equivalent amount of atoken
|
||||||
vars.collateralAtoken.burnOnLiquidation(_user, vars.maxCollateralToLiquidate);
|
vars.collateralAtoken.burnOnLiquidation(_user, vars.maxCollateralToLiquidate);
|
||||||
|
vars.collateralAtoken.transferUnderlyingTo(msg.sender, vars.maxCollateralToLiquidate);
|
||||||
IERC20(_collateral).universalTransfer(msg.sender, vars.maxCollateralToLiquidate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//transfers the principal currency to the pool
|
//transfers the principal currency to the aToken
|
||||||
IERC20(_reserve).universalTransferFromSenderToThis(vars.actualAmountToLiquidate, true);
|
IERC20(_reserve).universalTransferFrom(
|
||||||
|
msg.sender,
|
||||||
|
principalReserve.aTokenAddress,
|
||||||
|
vars.actualAmountToLiquidate,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
emit LiquidationCall(
|
emit LiquidationCall(
|
||||||
_collateral,
|
_collateral,
|
||||||
|
|
|
@ -15,6 +15,7 @@ import '../interfaces/ILendingRateOracle.sol';
|
||||||
import '../interfaces/IReserveInterestRateStrategy.sol';
|
import '../interfaces/IReserveInterestRateStrategy.sol';
|
||||||
import '../tokenization/AToken.sol';
|
import '../tokenization/AToken.sol';
|
||||||
import './WadRayMath.sol';
|
import './WadRayMath.sol';
|
||||||
|
import '@nomiclabs/buidler/console.sol';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @title ReserveLogic library
|
* @title ReserveLogic library
|
||||||
|
@ -56,7 +57,7 @@ library ReserveLogic {
|
||||||
/**
|
/**
|
||||||
* @dev address of the aToken representing the asset
|
* @dev address of the aToken representing the asset
|
||||||
**/
|
**/
|
||||||
address aTokenAddress;
|
address payable aTokenAddress;
|
||||||
address stableDebtTokenAddress;
|
address stableDebtTokenAddress;
|
||||||
address variableDebtTokenAddress;
|
address variableDebtTokenAddress;
|
||||||
/**
|
/**
|
||||||
|
@ -185,7 +186,7 @@ library ReserveLogic {
|
||||||
_self.lastVariableBorrowCumulativeIndex = WadRayMath.ray();
|
_self.lastVariableBorrowCumulativeIndex = WadRayMath.ray();
|
||||||
}
|
}
|
||||||
|
|
||||||
_self.aTokenAddress = _aTokenAddress;
|
_self.aTokenAddress = payable(_aTokenAddress);
|
||||||
_self.stableDebtTokenAddress = _stableDebtAddress;
|
_self.stableDebtTokenAddress = _stableDebtAddress;
|
||||||
_self.variableDebtTokenAddress = _variableDebtAddress;
|
_self.variableDebtTokenAddress = _variableDebtAddress;
|
||||||
_self.decimals = _decimals;
|
_self.decimals = _decimals;
|
||||||
|
@ -348,12 +349,7 @@ library ReserveLogic {
|
||||||
uint256 currentAvgStableRate = IStableDebtToken(_reserve.stableDebtTokenAddress)
|
uint256 currentAvgStableRate = IStableDebtToken(_reserve.stableDebtTokenAddress)
|
||||||
.getAverageStableRate();
|
.getAverageStableRate();
|
||||||
|
|
||||||
uint256 balance = IERC20(_reserveAddress).universalBalanceOf(address(this));
|
uint256 balance = IERC20(_reserveAddress).universalBalanceOf(_reserve.aTokenAddress);
|
||||||
|
|
||||||
//if the reserve is ETH, the msg.value has already been cumulated to the balance of the reserve
|
|
||||||
if (IERC20(_reserveAddress).isETH()) {
|
|
||||||
balance = balance.sub(msg.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
(
|
(
|
||||||
uint256 newLiquidityRate,
|
uint256 newLiquidityRate,
|
||||||
|
|
|
@ -53,7 +53,10 @@ library ValidationLogic {
|
||||||
|
|
||||||
require(msg.sender == _reserve.aTokenAddress, '31');
|
require(msg.sender == _reserve.aTokenAddress, '31');
|
||||||
|
|
||||||
uint256 currentAvailableLiquidity = IERC20(_reserveAddress).universalBalanceOf(address(this));
|
uint256 currentAvailableLiquidity = IERC20(_reserveAddress).universalBalanceOf(
|
||||||
|
address(_reserve.aTokenAddress)
|
||||||
|
);
|
||||||
|
|
||||||
require(currentAvailableLiquidity >= _amount, '4');
|
require(currentAvailableLiquidity >= _amount, '4');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +120,9 @@ library ValidationLogic {
|
||||||
);
|
);
|
||||||
|
|
||||||
//check that the amount is available in the reserve
|
//check that the amount is available in the reserve
|
||||||
vars.availableLiquidity = IERC20(_reserveAddress).universalBalanceOf(address(this));
|
vars.availableLiquidity = IERC20(_reserveAddress).universalBalanceOf(
|
||||||
|
address(_reserve.aTokenAddress)
|
||||||
|
);
|
||||||
|
|
||||||
require(vars.availableLiquidity >= _amount, '7');
|
require(vars.availableLiquidity >= _amount, '7');
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,10 @@ contract AaveProtocolTestHelpers {
|
||||||
TokenData[] memory aTokens = new TokenData[](reserves.length);
|
TokenData[] memory aTokens = new TokenData[](reserves.length);
|
||||||
for (uint256 i = 0; i < reserves.length; i++) {
|
for (uint256 i = 0; i < reserves.length; i++) {
|
||||||
(address aTokenAddress, , ) = pool.getReserveTokensAddresses(reserves[i]);
|
(address aTokenAddress, , ) = pool.getReserveTokensAddresses(reserves[i]);
|
||||||
aTokens[i] = TokenData({symbol: AToken(aTokenAddress).symbol(), tokenAddress: aTokenAddress});
|
aTokens[i] = TokenData({
|
||||||
|
symbol: AToken(payable(aTokenAddress)).symbol(),
|
||||||
|
tokenAddress: aTokenAddress
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return aTokens;
|
return aTokens;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ contract MockFlashLoanReceiver is FlashLoanReceiverBase {
|
||||||
|
|
||||||
function executeOperation(
|
function executeOperation(
|
||||||
address _reserve,
|
address _reserve,
|
||||||
|
address _destination,
|
||||||
uint256 _amount,
|
uint256 _amount,
|
||||||
uint256 _fee,
|
uint256 _fee,
|
||||||
bytes memory _params
|
bytes memory _params
|
||||||
|
@ -34,7 +35,7 @@ contract MockFlashLoanReceiver is FlashLoanReceiverBase {
|
||||||
|
|
||||||
//check the contract has the specified balance
|
//check the contract has the specified balance
|
||||||
require(
|
require(
|
||||||
_amount <= IERC20(_reserve).universalBalanceOf(address(this)),
|
_amount <= getBalanceInternal(address(this), _reserve),
|
||||||
'Invalid balance for the contract'
|
'Invalid balance for the contract'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -49,8 +50,10 @@ contract MockFlashLoanReceiver is FlashLoanReceiverBase {
|
||||||
if (!IERC20(_reserve).isETH()) {
|
if (!IERC20(_reserve).isETH()) {
|
||||||
token.mint(_fee);
|
token.mint(_fee);
|
||||||
}
|
}
|
||||||
|
|
||||||
//returning amount + fee to the destination
|
//returning amount + fee to the destination
|
||||||
transferFundsBackToPoolInternal(_reserve, _amount.add(_fee));
|
transferFundsBackInternal(_reserve, _destination, _amount.add(_fee));
|
||||||
|
|
||||||
emit ExecutedWithSuccess(_reserve, _amount, _fee);
|
emit ExecutedWithSuccess(_reserve, _amount, _fee);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
// SPDX-License-Identifier: agpl-3.0
|
// SPDX-License-Identifier: agpl-3.0
|
||||||
pragma solidity ^0.6.8;
|
pragma solidity ^0.6.8;
|
||||||
|
|
||||||
import './ERC20.sol';
|
import {ERC20} from './ERC20.sol';
|
||||||
import '../configuration/LendingPoolAddressesProvider.sol';
|
import {LendingPoolAddressesProvider} from '../configuration/LendingPoolAddressesProvider.sol';
|
||||||
import '../lendingpool/LendingPool.sol';
|
import {LendingPool} from '../lendingpool/LendingPool.sol';
|
||||||
import '../libraries/WadRayMath.sol';
|
import {WadRayMath} from '../libraries/WadRayMath.sol';
|
||||||
|
import {UniversalERC20} from '../libraries/UniversalERC20.sol';
|
||||||
|
import '@nomiclabs/buidler/console.sol';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @title Aave ERC20 AToken
|
* @title Aave ERC20 AToken
|
||||||
|
@ -14,6 +16,7 @@ import '../libraries/WadRayMath.sol';
|
||||||
*/
|
*/
|
||||||
contract AToken is ERC20 {
|
contract AToken is ERC20 {
|
||||||
using WadRayMath for uint256;
|
using WadRayMath for uint256;
|
||||||
|
using UniversalERC20 for ERC20;
|
||||||
|
|
||||||
uint256 public constant UINT_MAX_VALUE = uint256(-1);
|
uint256 public constant UINT_MAX_VALUE = uint256(-1);
|
||||||
|
|
||||||
|
@ -636,4 +639,31 @@ contract AToken is ERC20 {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
onlyLendingPool
|
||||||
|
returns (uint256)
|
||||||
|
{
|
||||||
|
ERC20(underlyingAssetAddress).universalTransfer(_target, _amount);
|
||||||
|
return _amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev receive() function for aTokens who hold ETH as the underlying asset
|
||||||
|
**/
|
||||||
|
receive() external payable {
|
||||||
|
require(
|
||||||
|
ERC20(underlyingAssetAddress).isETH(),
|
||||||
|
'Transfers are only allowed if the underlying asset is ETH'
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -438,4 +438,4 @@
|
||||||
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
"deployer": "0xc783df8a850f42e7F7e57013759C285caa701eB6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -25,4 +25,11 @@ makeSuite('AToken: Modifiers', (testEnv: TestEnv) => {
|
||||||
aDai.transferOnLiquidation(deployer.address, users[0].address, '1')
|
aDai.transferOnLiquidation(deployer.address, users[0].address, '1')
|
||||||
).to.be.revertedWith(INVALID_POOL_CALLER_MSG_1);
|
).to.be.revertedWith(INVALID_POOL_CALLER_MSG_1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Tries to invoke transferUnderlyingTo not being the LendingPool', async () => {
|
||||||
|
const {deployer, users, aDai} = testEnv;
|
||||||
|
await expect(aDai.transferUnderlyingTo(deployer.address, '1')).to.be.revertedWith(
|
||||||
|
INVALID_POOL_CALLER_MSG_1
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue
Block a user