mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
Added transfer of the funds to aTokens
This commit is contained in:
parent
e5f0206f87
commit
edd7ad3b15
|
@ -21,14 +21,13 @@ abstract contract FlashLoanReceiverBase is IFlashLoanReceiver {
|
||||||
|
|
||||||
receive() external payable {}
|
receive() external payable {}
|
||||||
|
|
||||||
function transferFundsBackToPoolInternal(address _reserve, uint256 _amount) internal {
|
function transferFundsBackInternal(address _reserve, address _destination, uint256 _amount) internal {
|
||||||
|
|
||||||
address payable pool = payable(addressesProvider.getLendingPool());
|
transferInternal(payable(_destination),_reserve, _amount);
|
||||||
|
|
||||||
transferInternal(pool,_reserve, _amount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function transferInternal(address payable _destination, address _reserve, uint256 _amount) internal {
|
function transferInternal(address payable _destination, address _reserve, uint256 _amount) internal {
|
||||||
|
|
||||||
if(_reserve == EthAddressLib.ethAddress()) {
|
if(_reserve == EthAddressLib.ethAddress()) {
|
||||||
//solium-disable-next-line
|
//solium-disable-next-line
|
||||||
_destination.call{value: _amount}("");
|
_destination.call{value: _amount}("");
|
||||||
|
|
|
@ -9,5 +9,5 @@ pragma solidity ^0.6.8;
|
||||||
**/
|
**/
|
||||||
interface IFlashLoanReceiver {
|
interface IFlashLoanReceiver {
|
||||||
|
|
||||||
function executeOperation(address _reserve, uint256 _amount, uint256 _fee, bytes calldata _params) external;
|
function executeOperation(address _reserve, address _destination, uint256 _amount, uint256 _fee, bytes calldata _params) external;
|
||||||
}
|
}
|
||||||
|
|
|
@ -261,12 +261,13 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
|
||||||
uint256 _amount,
|
uint256 _amount,
|
||||||
uint16 _referralCode
|
uint16 _referralCode
|
||||||
) external payable nonReentrant {
|
) external payable nonReentrant {
|
||||||
|
|
||||||
ReserveLogic.ReserveData storage reserve = reserves[_reserve];
|
ReserveLogic.ReserveData storage reserve = reserves[_reserve];
|
||||||
UserLogic.UserReserveData storage user = usersReserveData[msg.sender][_reserve];
|
UserLogic.UserReserveData storage user = usersReserveData[msg.sender][_reserve];
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
@ -280,8 +281,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);
|
||||||
|
@ -303,16 +304,20 @@ 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();
|
|
||||||
reserve.updateInterestRates(_reserve, 0, _amount);
|
|
||||||
|
|
||||||
IERC20(_reserve).universalTransfer(_user, _amount);
|
AToken(reserve.aTokenAddress).transferUnderlyingTo(_user, _amount);
|
||||||
|
|
||||||
//solium-disable-next-line
|
//solium-disable-next-line
|
||||||
emit RedeemUnderlying(_reserve, _user, _amount, block.timestamp);
|
emit RedeemUnderlying(_reserve, _user, _amount, block.timestamp);
|
||||||
|
@ -372,7 +377,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,
|
||||||
|
@ -453,7 +458,7 @@ 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
|
||||||
|
@ -651,6 +656,7 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
|
||||||
uint256 protocolFeeBips;
|
uint256 protocolFeeBips;
|
||||||
uint256 amountFee;
|
uint256 amountFee;
|
||||||
uint256 protocolFee;
|
uint256 protocolFee;
|
||||||
|
address payable aTokenAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -667,12 +673,15 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
|
||||||
uint256 _amount,
|
uint256 _amount,
|
||||||
bytes memory _params
|
bytes memory _params
|
||||||
) public nonReentrant {
|
) public nonReentrant {
|
||||||
|
|
||||||
FlashLoanLocalVars memory vars;
|
FlashLoanLocalVars memory vars;
|
||||||
|
|
||||||
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);
|
||||||
|
@ -680,6 +689,7 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
|
||||||
//protocol fee is the part of the amountFee reserved for the protocol - the rest goes to depositors
|
//protocol fee is the part of the amountFee reserved for the protocol - the rest goes to depositors
|
||||||
vars.protocolFee = vars.amountFee.mul(FLASHLOAN_FEE_PROTOCOL).div(10000);
|
vars.protocolFee = vars.amountFee.mul(FLASHLOAN_FEE_PROTOCOL).div(10000);
|
||||||
|
|
||||||
|
|
||||||
require(
|
require(
|
||||||
vars.availableLiquidityBefore >= _amount,
|
vars.availableLiquidityBefore >= _amount,
|
||||||
'There is not enough liquidity available to borrow'
|
'There is not enough liquidity available to borrow'
|
||||||
|
@ -695,13 +705,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),
|
||||||
|
@ -791,7 +801,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,
|
||||||
|
|
|
@ -192,6 +192,9 @@ contract LendingPoolLiquidationManager is ReentrancyGuard, VersionedInitializabl
|
||||||
vars.userCollateralBalance
|
vars.userCollateralBalance
|
||||||
);
|
);
|
||||||
|
|
||||||
|
vars.collateralAtoken = AToken(payable(collateralReserve.aTokenAddress));
|
||||||
|
|
||||||
|
|
||||||
//if principalAmountNeeded < vars.ActualAmountToLiquidate, there isn't enough
|
//if principalAmountNeeded < vars.ActualAmountToLiquidate, there isn't enough
|
||||||
//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
|
||||||
|
@ -202,7 +205,7 @@ contract LendingPoolLiquidationManager is ReentrancyGuard, VersionedInitializabl
|
||||||
|
|
||||||
//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),
|
||||||
|
@ -220,8 +223,6 @@ contract LendingPoolLiquidationManager is ReentrancyGuard, VersionedInitializabl
|
||||||
IStableDebtToken(principalReserve.stableDebtTokenAddress).burn(_user, vars.actualAmountToLiquidate.sub(vars.userVariableDebt));
|
IStableDebtToken(principalReserve.stableDebtTokenAddress).burn(_user, vars.actualAmountToLiquidate.sub(vars.userVariableDebt));
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
vars.collateralAtoken.transferOnLiquidation(
|
||||||
|
@ -233,13 +234,11 @@ 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;
|
||||||
/**
|
/**
|
||||||
|
@ -193,7 +194,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;
|
||||||
|
@ -353,15 +354,11 @@ library ReserveLogic {
|
||||||
uint256 _liquidityAdded,
|
uint256 _liquidityAdded,
|
||||||
uint256 _liquidityTaken
|
uint256 _liquidityTaken
|
||||||
) internal {
|
) internal {
|
||||||
|
|
||||||
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,8 @@ 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 +118,7 @@ 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');
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ contract AaveProtocolTestHelpers {
|
||||||
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({
|
aTokens[i] = TokenData({
|
||||||
symbol: AToken(aTokenAddress).symbol(),
|
symbol: AToken(payable(aTokenAddress)).symbol(),
|
||||||
tokenAddress: aTokenAddress
|
tokenAddress: aTokenAddress
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,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) public override {
|
bytes memory _params) public override {
|
||||||
|
@ -46,7 +47,7 @@ contract MockFlashLoanReceiver is FlashLoanReceiverBase {
|
||||||
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,11 +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 {SafeERC20} from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
|
import {ERC20} from './ERC20.sol';
|
||||||
import {ERC20} from "./ERC20.sol";
|
import {LendingPoolAddressesProvider} from '../configuration/LendingPoolAddressesProvider.sol';
|
||||||
import {LendingPoolAddressesProvider} from "../configuration/LendingPoolAddressesProvider.sol";
|
import {LendingPool} from '../lendingpool/LendingPool.sol';
|
||||||
import {LendingPool} from "../lendingpool/LendingPool.sol";
|
import {WadRayMath} from '../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
|
||||||
|
@ -15,7 +16,7 @@ import {WadRayMath} from "../libraries/WadRayMath.sol";
|
||||||
*/
|
*/
|
||||||
contract AToken is ERC20 {
|
contract AToken is ERC20 {
|
||||||
using WadRayMath for uint256;
|
using WadRayMath for uint256;
|
||||||
using SafeERC20 for ERC20;
|
using UniversalERC20 for ERC20;
|
||||||
|
|
||||||
uint256 public constant UINT_MAX_VALUE = uint256(-1);
|
uint256 public constant UINT_MAX_VALUE = uint256(-1);
|
||||||
|
|
||||||
|
@ -114,10 +115,7 @@ contract AToken is ERC20 {
|
||||||
uint256 _redirectedBalanceRemoved
|
uint256 _redirectedBalanceRemoved
|
||||||
);
|
);
|
||||||
|
|
||||||
event InterestRedirectionAllowanceChanged(
|
event InterestRedirectionAllowanceChanged(address indexed _from, address indexed _to);
|
||||||
address indexed _from,
|
|
||||||
address indexed _to
|
|
||||||
);
|
|
||||||
|
|
||||||
address public underlyingAssetAddress;
|
address public underlyingAssetAddress;
|
||||||
|
|
||||||
|
@ -130,15 +128,12 @@ contract AToken is ERC20 {
|
||||||
LendingPool private pool;
|
LendingPool private pool;
|
||||||
|
|
||||||
modifier onlyLendingPool {
|
modifier onlyLendingPool {
|
||||||
require(
|
require(msg.sender == address(pool), 'The caller of this function must be a lending pool');
|
||||||
msg.sender == address(pool),
|
|
||||||
"The caller of this function must be a lending pool"
|
|
||||||
);
|
|
||||||
_;
|
_;
|
||||||
}
|
}
|
||||||
|
|
||||||
modifier whenTransferAllowed(address _from, uint256 _amount) {
|
modifier whenTransferAllowed(address _from, uint256 _amount) {
|
||||||
require(isTransferAllowed(_from, _amount), "Transfer cannot be allowed.");
|
require(isTransferAllowed(_from, _amount), 'Transfer cannot be allowed.');
|
||||||
_;
|
_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,19 +148,20 @@ contract AToken is ERC20 {
|
||||||
addressesProvider = _addressesProvider;
|
addressesProvider = _addressesProvider;
|
||||||
pool = LendingPool(payable(addressesProvider.getLendingPool()));
|
pool = LendingPool(payable(addressesProvider.getLendingPool()));
|
||||||
underlyingAssetAddress = _underlyingAsset;
|
underlyingAssetAddress = _underlyingAsset;
|
||||||
ERC20(underlyingAssetAddress).safeApprove(address(pool), type(uint256).max);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @notice ERC20 implementation internal function backing transfer() and transferFrom()
|
* @notice ERC20 implementation internal function backing transfer() and transferFrom()
|
||||||
* @dev validates the transfer before allowing it. NOTE: This is not standard ERC20 behavior
|
* @dev validates the transfer before allowing it. NOTE: This is not standard ERC20 behavior
|
||||||
**/
|
**/
|
||||||
function _transfer(address _from, address _to, uint256 _amount) internal override whenTransferAllowed(_from, _amount) {
|
function _transfer(
|
||||||
|
address _from,
|
||||||
|
address _to,
|
||||||
|
uint256 _amount
|
||||||
|
) internal override whenTransferAllowed(_from, _amount) {
|
||||||
executeTransferInternal(_from, _to, _amount);
|
executeTransferInternal(_from, _to, _amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev redirects the interest generated to a target address.
|
* @dev redirects the interest generated to a target address.
|
||||||
* when the interest is redirected, the user balance is added to
|
* when the interest is redirected, the user balance is added to
|
||||||
|
@ -187,7 +183,7 @@ contract AToken is ERC20 {
|
||||||
function redirectInterestStreamOf(address _from, address _to) external {
|
function redirectInterestStreamOf(address _from, address _to) external {
|
||||||
require(
|
require(
|
||||||
msg.sender == interestRedirectionAllowances[_from],
|
msg.sender == interestRedirectionAllowances[_from],
|
||||||
"Caller is not allowed to redirect the interest of the user"
|
'Caller is not allowed to redirect the interest of the user'
|
||||||
);
|
);
|
||||||
redirectInterestStreamInternal(_from, _to);
|
redirectInterestStreamInternal(_from, _to);
|
||||||
}
|
}
|
||||||
|
@ -199,12 +195,9 @@ contract AToken is ERC20 {
|
||||||
* the allowance.
|
* the allowance.
|
||||||
**/
|
**/
|
||||||
function allowInterestRedirectionTo(address _to) external {
|
function allowInterestRedirectionTo(address _to) external {
|
||||||
require(_to != msg.sender, "User cannot give allowance to himself");
|
require(_to != msg.sender, 'User cannot give allowance to himself');
|
||||||
interestRedirectionAllowances[msg.sender] = _to;
|
interestRedirectionAllowances[msg.sender] = _to;
|
||||||
emit InterestRedirectionAllowanceChanged(
|
emit InterestRedirectionAllowanceChanged(msg.sender, _to);
|
||||||
msg.sender,
|
|
||||||
_to
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -212,14 +205,12 @@ contract AToken is ERC20 {
|
||||||
* @param _amount the amount being redeemed
|
* @param _amount the amount being redeemed
|
||||||
**/
|
**/
|
||||||
function redeem(uint256 _amount) external {
|
function redeem(uint256 _amount) external {
|
||||||
|
require(_amount > 0, 'Amount to redeem needs to be > 0');
|
||||||
require(_amount > 0, "Amount to redeem needs to be > 0");
|
|
||||||
|
|
||||||
//cumulates the balance of the user
|
//cumulates the balance of the user
|
||||||
(,
|
(, uint256 currentBalance, uint256 balanceIncrease, uint256 index) = cumulateBalanceInternal(
|
||||||
uint256 currentBalance,
|
msg.sender
|
||||||
uint256 balanceIncrease,
|
);
|
||||||
uint256 index) = cumulateBalanceInternal(msg.sender);
|
|
||||||
|
|
||||||
uint256 amountToRedeem = _amount;
|
uint256 amountToRedeem = _amount;
|
||||||
|
|
||||||
|
@ -228,15 +219,19 @@ contract AToken is ERC20 {
|
||||||
amountToRedeem = currentBalance;
|
amountToRedeem = currentBalance;
|
||||||
}
|
}
|
||||||
|
|
||||||
require(amountToRedeem <= currentBalance, "User cannot redeem more than the available balance");
|
require(amountToRedeem <= currentBalance, 'User cannot redeem more than the available balance');
|
||||||
|
|
||||||
//check that the user is allowed to redeem the amount
|
//check that the user is allowed to redeem the amount
|
||||||
require(isTransferAllowed(msg.sender, amountToRedeem), "Transfer cannot be allowed.");
|
require(isTransferAllowed(msg.sender, amountToRedeem), 'Transfer cannot be allowed.');
|
||||||
|
|
||||||
//if the user is redirecting his interest towards someone else,
|
//if the user is redirecting his interest towards someone else,
|
||||||
//we update the redirected balance of the redirection address by adding the accrued interest,
|
//we update the redirected balance of the redirection address by adding the accrued interest,
|
||||||
//and removing the amount to redeem
|
//and removing the amount to redeem
|
||||||
updateRedirectedBalanceOfRedirectionAddressInternal(msg.sender, balanceIncrease, amountToRedeem);
|
updateRedirectedBalanceOfRedirectionAddressInternal(
|
||||||
|
msg.sender,
|
||||||
|
balanceIncrease,
|
||||||
|
amountToRedeem
|
||||||
|
);
|
||||||
|
|
||||||
// burns tokens equivalent to the amount requested
|
// burns tokens equivalent to the amount requested
|
||||||
_burn(msg.sender, amountToRedeem);
|
_burn(msg.sender, amountToRedeem);
|
||||||
|
@ -265,12 +260,8 @@ contract AToken is ERC20 {
|
||||||
* @param _amount the amount of tokens to mint
|
* @param _amount the amount of tokens to mint
|
||||||
*/
|
*/
|
||||||
function mintOnDeposit(address _account, uint256 _amount) external onlyLendingPool {
|
function mintOnDeposit(address _account, uint256 _amount) external onlyLendingPool {
|
||||||
|
|
||||||
//cumulates the balance of the user
|
//cumulates the balance of the user
|
||||||
(,
|
(, , uint256 balanceIncrease, uint256 index) = cumulateBalanceInternal(_account);
|
||||||
,
|
|
||||||
uint256 balanceIncrease,
|
|
||||||
uint256 index) = cumulateBalanceInternal(_account);
|
|
||||||
|
|
||||||
//if the user is redirecting his interest towards someone else,
|
//if the user is redirecting his interest towards someone else,
|
||||||
//we update the redirected balance of the redirection address by adding the accrued interest
|
//we update the redirected balance of the redirection address by adding the accrued interest
|
||||||
|
@ -291,9 +282,10 @@ contract AToken is ERC20 {
|
||||||
* @param _value the amount to burn
|
* @param _value the amount to burn
|
||||||
**/
|
**/
|
||||||
function burnOnLiquidation(address _account, uint256 _value) external onlyLendingPool {
|
function burnOnLiquidation(address _account, uint256 _value) external onlyLendingPool {
|
||||||
|
|
||||||
//cumulates the balance of the user being liquidated
|
//cumulates the balance of the user being liquidated
|
||||||
(,uint256 accountBalance,uint256 balanceIncrease,uint256 index) = cumulateBalanceInternal(_account);
|
(, uint256 accountBalance, uint256 balanceIncrease, uint256 index) = cumulateBalanceInternal(
|
||||||
|
_account
|
||||||
|
);
|
||||||
|
|
||||||
//adds the accrued interest and substracts the burned amount to
|
//adds the accrued interest and substracts the burned amount to
|
||||||
//the redirected balance
|
//the redirected balance
|
||||||
|
@ -318,8 +310,11 @@ contract AToken is ERC20 {
|
||||||
* @param _to the destination address
|
* @param _to the destination address
|
||||||
* @param _value the amount to transfer
|
* @param _value the amount to transfer
|
||||||
**/
|
**/
|
||||||
function transferOnLiquidation(address _from, address _to, uint256 _value) external onlyLendingPool {
|
function transferOnLiquidation(
|
||||||
|
address _from,
|
||||||
|
address _to,
|
||||||
|
uint256 _value
|
||||||
|
) external onlyLendingPool {
|
||||||
//being a normal transfer, the Transfer() and BalanceTransfer() are emitted
|
//being a normal transfer, the Transfer() and BalanceTransfer() are emitted
|
||||||
//so no need to emit a specific event here
|
//so no need to emit a specific event here
|
||||||
executeTransferInternal(_from, _to, _value);
|
executeTransferInternal(_from, _to, _value);
|
||||||
|
@ -332,7 +327,6 @@ contract AToken is ERC20 {
|
||||||
* @return the total balance of the user
|
* @return the total balance of the user
|
||||||
**/
|
**/
|
||||||
function balanceOf(address _user) public override view returns (uint256) {
|
function balanceOf(address _user) public override view returns (uint256) {
|
||||||
|
|
||||||
//current principal balance of the user
|
//current principal balance of the user
|
||||||
uint256 currentPrincipalBalance = super.balanceOf(_user);
|
uint256 currentPrincipalBalance = super.balanceOf(_user);
|
||||||
//balance redirected by other users to _user for interest rate accrual
|
//balance redirected by other users to _user for interest rate accrual
|
||||||
|
@ -345,25 +339,18 @@ contract AToken is ERC20 {
|
||||||
//the interest for himself
|
//the interest for himself
|
||||||
|
|
||||||
if (interestRedirectionAddresses[_user] == address(0)) {
|
if (interestRedirectionAddresses[_user] == address(0)) {
|
||||||
|
|
||||||
//accruing for himself means that both the principal balance and
|
//accruing for himself means that both the principal balance and
|
||||||
//the redirected balance partecipate in the interest
|
//the redirected balance partecipate in the interest
|
||||||
return calculateCumulatedBalanceInternal(
|
return
|
||||||
_user,
|
calculateCumulatedBalanceInternal(_user, currentPrincipalBalance.add(redirectedBalance))
|
||||||
currentPrincipalBalance.add(redirectedBalance)
|
|
||||||
)
|
|
||||||
.sub(redirectedBalance);
|
.sub(redirectedBalance);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
//if the user redirected the interest, then only the redirected
|
//if the user redirected the interest, then only the redirected
|
||||||
//balance generates interest. In that case, the interest generated
|
//balance generates interest. In that case, the interest generated
|
||||||
//by the redirected balance is added to the current principal balance.
|
//by the redirected balance is added to the current principal balance.
|
||||||
return currentPrincipalBalance.add(
|
return
|
||||||
calculateCumulatedBalanceInternal(
|
currentPrincipalBalance.add(
|
||||||
_user,
|
calculateCumulatedBalanceInternal(_user, redirectedBalance).sub(redirectedBalance)
|
||||||
redirectedBalance
|
|
||||||
)
|
|
||||||
.sub(redirectedBalance)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -378,7 +365,6 @@ contract AToken is ERC20 {
|
||||||
return super.balanceOf(_user);
|
return super.balanceOf(_user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev calculates the total supply of the specific aToken
|
* @dev calculates the total supply of the specific aToken
|
||||||
* since the balance of every single user increases over time, the total supply
|
* since the balance of every single user increases over time, the total supply
|
||||||
|
@ -386,20 +372,19 @@ contract AToken is ERC20 {
|
||||||
* @return the current total supply
|
* @return the current total supply
|
||||||
**/
|
**/
|
||||||
function totalSupply() public override view returns (uint256) {
|
function totalSupply() public override view returns (uint256) {
|
||||||
|
|
||||||
uint256 currentSupplyPrincipal = super.totalSupply();
|
uint256 currentSupplyPrincipal = super.totalSupply();
|
||||||
|
|
||||||
if (currentSupplyPrincipal == 0) {
|
if (currentSupplyPrincipal == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentSupplyPrincipal
|
return
|
||||||
|
currentSupplyPrincipal
|
||||||
.wadToRay()
|
.wadToRay()
|
||||||
.rayMul(pool.getReserveNormalizedIncome(underlyingAssetAddress))
|
.rayMul(pool.getReserveNormalizedIncome(underlyingAssetAddress))
|
||||||
.rayToWad();
|
.rayToWad();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Used to validate transfers before actually executing them.
|
* @dev Used to validate transfers before actually executing them.
|
||||||
* @param _user address of the user to check
|
* @param _user address of the user to check
|
||||||
|
@ -419,7 +404,6 @@ contract AToken is ERC20 {
|
||||||
return userIndexes[_user];
|
return userIndexes[_user];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev returns the address to which the interest is redirected
|
* @dev returns the address to which the interest is redirected
|
||||||
* @param _user address of the user
|
* @param _user address of the user
|
||||||
|
@ -447,8 +431,13 @@ contract AToken is ERC20 {
|
||||||
**/
|
**/
|
||||||
function cumulateBalanceInternal(address _user)
|
function cumulateBalanceInternal(address _user)
|
||||||
internal
|
internal
|
||||||
returns(uint256, uint256, uint256, uint256) {
|
returns (
|
||||||
|
uint256,
|
||||||
|
uint256,
|
||||||
|
uint256,
|
||||||
|
uint256
|
||||||
|
)
|
||||||
|
{
|
||||||
uint256 previousPrincipalBalance = super.balanceOf(_user);
|
uint256 previousPrincipalBalance = super.balanceOf(_user);
|
||||||
|
|
||||||
//calculate the accrued interest since the last accumulation
|
//calculate the accrued interest since the last accumulation
|
||||||
|
@ -477,7 +466,6 @@ contract AToken is ERC20 {
|
||||||
uint256 _balanceToAdd,
|
uint256 _balanceToAdd,
|
||||||
uint256 _balanceToRemove
|
uint256 _balanceToRemove
|
||||||
) internal {
|
) internal {
|
||||||
|
|
||||||
address redirectionAddress = interestRedirectionAddresses[_user];
|
address redirectionAddress = interestRedirectionAddresses[_user];
|
||||||
//if there isn't any redirection, nothing to be done
|
//if there isn't any redirection, nothing to be done
|
||||||
if (redirectionAddress == address(0)) {
|
if (redirectionAddress == address(0)) {
|
||||||
|
@ -497,7 +485,8 @@ contract AToken is ERC20 {
|
||||||
address targetOfRedirectionAddress = interestRedirectionAddresses[redirectionAddress];
|
address targetOfRedirectionAddress = interestRedirectionAddresses[redirectionAddress];
|
||||||
|
|
||||||
if (targetOfRedirectionAddress != address(0)) {
|
if (targetOfRedirectionAddress != address(0)) {
|
||||||
redirectedBalances[targetOfRedirectionAddress] = redirectedBalances[targetOfRedirectionAddress].add(balanceIncrease);
|
redirectedBalances[targetOfRedirectionAddress] = redirectedBalances[targetOfRedirectionAddress]
|
||||||
|
.add(balanceIncrease);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit RedirectedBalanceUpdated(
|
emit RedirectedBalanceUpdated(
|
||||||
|
@ -515,11 +504,13 @@ contract AToken is ERC20 {
|
||||||
* @param _balance the balance on which the interest is calculated
|
* @param _balance the balance on which the interest is calculated
|
||||||
* @return the interest rate accrued
|
* @return the interest rate accrued
|
||||||
**/
|
**/
|
||||||
function calculateCumulatedBalanceInternal(
|
function calculateCumulatedBalanceInternal(address _user, uint256 _balance)
|
||||||
address _user,
|
internal
|
||||||
uint256 _balance
|
view
|
||||||
) internal view returns (uint256) {
|
returns (uint256)
|
||||||
return _balance
|
{
|
||||||
|
return
|
||||||
|
_balance
|
||||||
.wadToRay()
|
.wadToRay()
|
||||||
.rayMul(pool.getReserveNormalizedIncome(underlyingAssetAddress))
|
.rayMul(pool.getReserveNormalizedIncome(underlyingAssetAddress))
|
||||||
.rayDiv(userIndexes[_user])
|
.rayDiv(userIndexes[_user])
|
||||||
|
@ -538,22 +529,18 @@ contract AToken is ERC20 {
|
||||||
address _to,
|
address _to,
|
||||||
uint256 _value
|
uint256 _value
|
||||||
) internal {
|
) internal {
|
||||||
|
require(_value > 0, 'Transferred amount needs to be greater than zero');
|
||||||
require(_value > 0, "Transferred amount needs to be greater than zero");
|
|
||||||
|
|
||||||
//cumulate the balance of the sender
|
//cumulate the balance of the sender
|
||||||
(,
|
(
|
||||||
|
,
|
||||||
uint256 fromBalance,
|
uint256 fromBalance,
|
||||||
uint256 fromBalanceIncrease,
|
uint256 fromBalanceIncrease,
|
||||||
uint256 fromIndex
|
uint256 fromIndex
|
||||||
) = cumulateBalanceInternal(_from);
|
) = cumulateBalanceInternal(_from);
|
||||||
|
|
||||||
//cumulate the balance of the receiver
|
//cumulate the balance of the receiver
|
||||||
(,
|
(, , uint256 toBalanceIncrease, uint256 toIndex) = cumulateBalanceInternal(_to);
|
||||||
,
|
|
||||||
uint256 toBalanceIncrease,
|
|
||||||
uint256 toIndex
|
|
||||||
) = cumulateBalanceInternal(_to);
|
|
||||||
|
|
||||||
//if the sender is redirecting his interest towards someone else,
|
//if the sender is redirecting his interest towards someone else,
|
||||||
//adds to the redirected balance the accrued interest and removes the amount
|
//adds to the redirected balance the accrued interest and removes the amount
|
||||||
|
@ -591,22 +578,20 @@ contract AToken is ERC20 {
|
||||||
* @param _from the address from which transfer the aTokens
|
* @param _from the address from which transfer the aTokens
|
||||||
* @param _to the destination address
|
* @param _to the destination address
|
||||||
**/
|
**/
|
||||||
function redirectInterestStreamInternal(
|
function redirectInterestStreamInternal(address _from, address _to) internal {
|
||||||
address _from,
|
|
||||||
address _to
|
|
||||||
) internal {
|
|
||||||
|
|
||||||
address currentRedirectionAddress = interestRedirectionAddresses[_from];
|
address currentRedirectionAddress = interestRedirectionAddresses[_from];
|
||||||
|
|
||||||
require(_to != currentRedirectionAddress, "Interest is already redirected to the user");
|
require(_to != currentRedirectionAddress, 'Interest is already redirected to the user');
|
||||||
|
|
||||||
//accumulates the accrued interest to the principal
|
//accumulates the accrued interest to the principal
|
||||||
(uint256 previousPrincipalBalance,
|
(
|
||||||
|
uint256 previousPrincipalBalance,
|
||||||
uint256 fromBalance,
|
uint256 fromBalance,
|
||||||
uint256 balanceIncrease,
|
uint256 balanceIncrease,
|
||||||
uint256 fromIndex) = cumulateBalanceInternal(_from);
|
uint256 fromIndex
|
||||||
|
) = cumulateBalanceInternal(_from);
|
||||||
|
|
||||||
require(fromBalance > 0, "Interest stream can only be redirected if there is a valid balance");
|
require(fromBalance > 0, 'Interest stream can only be redirected if there is a valid balance');
|
||||||
|
|
||||||
//if the user is already redirecting the interest to someone, before changing
|
//if the user is already redirecting the interest to someone, before changing
|
||||||
//the redirection address we substract the redirected balance of the previous
|
//the redirection address we substract the redirected balance of the previous
|
||||||
|
@ -619,13 +604,7 @@ contract AToken is ERC20 {
|
||||||
//we simply set to 0 the interest redirection address
|
//we simply set to 0 the interest redirection address
|
||||||
if (_to == _from) {
|
if (_to == _from) {
|
||||||
interestRedirectionAddresses[_from] = address(0);
|
interestRedirectionAddresses[_from] = address(0);
|
||||||
emit InterestStreamRedirected(
|
emit InterestStreamRedirected(_from, address(0), fromBalance, balanceIncrease, fromIndex);
|
||||||
_from,
|
|
||||||
address(0),
|
|
||||||
fromBalance,
|
|
||||||
balanceIncrease,
|
|
||||||
fromIndex
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -635,13 +614,7 @@ contract AToken is ERC20 {
|
||||||
//adds the user balance to the redirected balance of the destination
|
//adds the user balance to the redirected balance of the destination
|
||||||
updateRedirectedBalanceOfRedirectionAddressInternal(_from, fromBalance, 0);
|
updateRedirectedBalanceOfRedirectionAddressInternal(_from, fromBalance, 0);
|
||||||
|
|
||||||
emit InterestStreamRedirected(
|
emit InterestStreamRedirected(_from, _to, fromBalance, balanceIncrease, fromIndex);
|
||||||
_from,
|
|
||||||
_to,
|
|
||||||
fromBalance,
|
|
||||||
balanceIncrease,
|
|
||||||
fromIndex
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -651,7 +624,6 @@ contract AToken is ERC20 {
|
||||||
* @return true if the user index has also been reset, false otherwise. useful to emit the proper user index value
|
* @return true if the user index has also been reset, false otherwise. useful to emit the proper user index value
|
||||||
**/
|
**/
|
||||||
function resetDataOnZeroBalanceInternal(address _user) internal returns (bool) {
|
function resetDataOnZeroBalanceInternal(address _user) internal returns (bool) {
|
||||||
|
|
||||||
//if the user has 0 principal balance, the interest stream redirection gets reset
|
//if the user has 0 principal balance, the interest stream redirection gets reset
|
||||||
interestRedirectionAddresses[_user] = address(0);
|
interestRedirectionAddresses[_user] = address(0);
|
||||||
|
|
||||||
|
@ -662,9 +634,20 @@ contract AToken is ERC20 {
|
||||||
if (redirectedBalances[_user] == 0) {
|
if (redirectedBalances[_user] == 0) {
|
||||||
userIndexes[_user] = 0;
|
userIndexes[_user] = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
} else {
|
||||||
else{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function transferUnderlyingTo(address _user, uint256 _amount)
|
||||||
|
external
|
||||||
|
onlyLendingPool
|
||||||
|
returns (uint256)
|
||||||
|
{
|
||||||
|
ERC20(underlyingAssetAddress).universalTransfer(_user, _amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
receive() external payable{
|
||||||
|
require(ERC20(underlyingAssetAddress).isETH(), "Transfers are only allowed if the underlying asset is ETH");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user