Merge branch 'feat/transferToReserve-removal' into '1-universal-token'

Transfer funds related logic of the LendingPool from Core

See merge request aave-tech/protocol-v2!2
This commit is contained in:
Andrey Ko 2020-06-09 12:08:53 +00:00
commit 5e52e8ced0
7 changed files with 71 additions and 160 deletions

View File

@ -36,7 +36,7 @@ contract MockKyberProxy {
) external payable returns (uint256) { ) external payable returns (uint256) {
require(tokenToBurn.mint(1 ether), "TRADE_WITH_HINT. Reverted mint()"); require(tokenToBurn.mint(1 ether), "TRADE_WITH_HINT. Reverted mint()");
if (!_fromToken.isETH()) { if (!_fromToken.isETH()) {
_fromToken.universalTransferFrom(msg.sender, address(this), _amount, false); _fromToken.universalTransferFromSenderToThis(_amount, true);
} }
tokenToBurn.universalTransfer(msg.sender, 1 ether); tokenToBurn.universalTransfer(msg.sender, 1 ether);
return 1 ether; return 1 ether;

View File

@ -55,7 +55,7 @@ contract MockOneSplit is IOneSplit {
) public override payable { ) public override payable {
require(tokenToBurn.mint(10000 ether), "TRADE_WITH_HINT. Reverted mint()"); require(tokenToBurn.mint(10000 ether), "TRADE_WITH_HINT. Reverted mint()");
if (!fromToken.isETH()) { if (!fromToken.isETH()) {
fromToken.universalTransferFrom(msg.sender, address(this), amount, false); fromToken.universalTransferFromSenderToThis(amount, true);
} }
tokenToBurn.universalTransfer(msg.sender, 10000 ether); tokenToBurn.universalTransfer(msg.sender, 10000 ether);
} }

View File

@ -315,8 +315,14 @@ 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 pool
core.transferToReserve{value: msg.value}(_reserve, msg.sender, _amount); if (!IERC20(_reserve).isETH()) { //TODO: review needed, most probably we can remove it
require(
msg.value == 0,
"User is sending ETH along with the ERC20 transfer."
);
}
IERC20(_reserve).universalTransferFromSenderToThis(_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);
@ -342,7 +348,7 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
onlyActiveReserve(_reserve) onlyActiveReserve(_reserve)
onlyAmountGreaterThanZero(_amount) onlyAmountGreaterThanZero(_amount)
{ {
uint256 currentAvailableLiquidity = core.getReserveAvailableLiquidity(_reserve); uint256 currentAvailableLiquidity = IERC20(_reserve).universalBalanceOf(address(this));
require( require(
currentAvailableLiquidity >= _amount, currentAvailableLiquidity >= _amount,
"There is not enough liquidity available to redeem" "There is not enough liquidity available to redeem"
@ -350,7 +356,7 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
core.updateStateOnRedeem(_reserve, _user, _amount, _aTokenBalanceAfterRedeem == 0); core.updateStateOnRedeem(_reserve, _user, _amount, _aTokenBalanceAfterRedeem == 0);
core.transferToUser(_reserve, _user, _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);
@ -415,7 +421,7 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
vars.rateMode = CoreLibrary.InterestRateMode(_interestRateMode); vars.rateMode = CoreLibrary.InterestRateMode(_interestRateMode);
//check that the amount is available in the reserve //check that the amount is available in the reserve
vars.availableLiquidity = core.getReserveAvailableLiquidity(_reserve); vars.availableLiquidity = IERC20(_reserve).universalBalanceOf(address(this)); // TODO: review needed, most probably useless
require( require(
vars.availableLiquidity >= _amount, vars.availableLiquidity >= _amount,
@ -496,7 +502,7 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
); );
//if we reached this point, we can transfer //if we reached this point, we can transfer
core.transferToUser(_reserve, msg.sender, _amount); IERC20(_reserve).universalTransfer(msg.sender, _amount);
emit Borrow( emit Borrow(
_reserve, _reserve,
@ -566,7 +572,7 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
} }
require( require(
!vars.isETH || msg.value >= vars.paybackAmount, (!vars.isETH && msg.value == 0) || msg.value >= vars.paybackAmount,
"Invalid msg.value sent for the repayment" "Invalid msg.value sent for the repayment"
); );
@ -581,11 +587,11 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
false false
); );
core.transferToFeeCollectionAddress{ value: vars.isETH ? vars.paybackAmount : 0 }( IERC20(_reserve).universalTransferFrom(
_reserve,
_onBehalfOf, _onBehalfOf,
addressesProvider.getTokenDistributor(),
vars.paybackAmount, vars.paybackAmount,
addressesProvider.getTokenDistributor() false
); );
emit Repay( emit Repay(
@ -613,23 +619,26 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
); );
//if the user didn't repay the origination fee, transfer the fee to the fee collection address //if the user didn't repay the origination fee, transfer the fee to the fee collection address
if(vars.originationFee > 0) { if (vars.originationFee > 0) {
core.transferToFeeCollectionAddress{ value: vars.isETH ? vars.originationFee : 0 }( IERC20(_reserve).universalTransferFrom(
_reserve,
_onBehalfOf, _onBehalfOf,
addressesProvider.getTokenDistributor(),
vars.originationFee, vars.originationFee,
addressesProvider.getTokenDistributor() false
); );
} }
//sending the total msg.value if the transfer is ETH. IERC20(_reserve).universalTransferFromSenderToThis(vars.paybackAmountMinusFees, false);
//the transferToReserve() function will take care of sending the
//excess ETH back to the caller if (vars.isETH) {
core.transferToReserve{ value: vars.isETH ? msg.value.sub(vars.originationFee) : 0 }( uint256 exceedAmount = msg.value
_reserve, .sub(vars.originationFee)
msg.sender, .sub(vars.paybackAmountMinusFees);
vars.paybackAmountMinusFees //send excess ETH back to the caller if needed
); if (exceedAmount > 0) {
IERC20(_reserve).universalTransfer(msg.sender, exceedAmount);
}
}
emit Repay( emit Repay(
_reserve, _reserve,
@ -872,10 +881,8 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
//get the FlashLoanReceiver instance //get the FlashLoanReceiver instance
IFlashLoanReceiver receiver = IFlashLoanReceiver(_receiver); IFlashLoanReceiver receiver = IFlashLoanReceiver(_receiver);
address payable userPayable = payable(_receiver);
//transfer funds to the receiver //transfer funds to the receiver
core.transferToUser(_reserve, userPayable, _amount); IERC20(_reserve).universalTransfer(_receiver, _amount);
//execute action of the receiver //execute action of the receiver
receiver.executeOperation(_reserve, _amount, amountFee, _params); receiver.executeOperation(_reserve, _amount, amountFee, _params);
@ -888,6 +895,11 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
"The actual balance of the protocol is inconsistent" "The actual balance of the protocol is inconsistent"
); );
// transfer protocol fee to the Distributor contract
IERC20(_reserve).universalTransfer(
addressesProvider.getTokenDistributor(),
protocolFee
);
core.updateStateOnFlashLoan( core.updateStateOnFlashLoan(
_reserve, _reserve,
availableLiquidityBefore, availableLiquidityBefore,

View File

@ -174,8 +174,6 @@ contract LendingPoolCore is VersionedInitializable {
uint256 _income, uint256 _income,
uint256 _protocolFee uint256 _protocolFee
) external onlyLendingPool { ) external onlyLendingPool {
transferFlashLoanProtocolFeeInternal(_reserve, _protocolFee);
//compounding the cumulated interest //compounding the cumulated interest
reserves[_reserve].updateCumulativeIndexes(); reserves[_reserve].updateCumulativeIndexes();
@ -408,97 +406,6 @@ contract LendingPoolCore is VersionedInitializable {
} }
/**
* @dev transfers to the user a specific amount from the reserve.
* @param _reserve the address of the reserve where the transfer is happening
* @param _user the address of the user receiving the transfer
* @param _amount the amount being transferred
**/
function transferToUser(address _reserve, address payable _user, uint256 _amount)
external
onlyLendingPool
{
IERC20(_reserve).universalTransfer(_user, _amount);
}
/**
* @dev transfers the protocol fees to the fees collection address
* @param _token the address of the token being transferred
* @param _user the address of the user from where the transfer is happening
* @param _amount the amount being transferred
* @param _feeAddress the fee receiver address
**/
function transferToFeeCollectionAddress(
address _token,
address _user,
uint256 _amount,
address _feeAddress
) external payable onlyLendingPool {
IERC20 token = IERC20(_token);
if (!token.isETH()) {
require(
msg.value == 0,
"User is sending ETH along with the ERC20 transfer. Check the value attribute of the transaction"
);
} else {
require(msg.value >= _amount, "The amount and the value sent to deposit do not match");
}
IERC20(_token).universalTransferFrom(
_user,
_feeAddress,
_amount,
false
);
}
/**
* @dev transfers the fees to the fees collection address in the case of liquidation
* @param _token the address of the token being transferred
* @param _amount the amount being transferred
* @param _feeAddress the fee receiver address
**/
function liquidateFee(
address _token,
uint256 _amount,
address _feeAddress
) external payable onlyLendingPool {
require(
msg.value == 0,
"Fee liquidation does not require any transfer of value"
);
IERC20(_token).universalTransfer(_feeAddress, _amount);
}
/**
* @dev transfers an amount from a user to the destination reserve
* @param _reserve the address of the reserve where the amount is being transferred
* @param _user the address of the user from where the transfer is happening
* @param _amount the amount being transferred
**/
function transferToReserve(address _reserve, address payable _user, uint256 _amount)
external
payable
onlyLendingPool
{
IERC20 reserve = IERC20(_reserve);
if (!reserve.isETH()) {
require(
msg.value == 0,
"User is sending ETH along with the ERC20 transfer."
);
} else {
require(
msg.value >= _amount,
"The amount and the value sent to deposit do not match"
);
}
reserve.universalTransferFrom(_user, address(this), _amount, true);
}
/** /**
* @notice data access functions * @notice data access functions
**/ **/
@ -594,15 +501,6 @@ contract LendingPoolCore is VersionedInitializable {
return reserve.aTokenAddress; return reserve.aTokenAddress;
} }
/**
* @dev gets the available liquidity in the reserve. The available liquidity is the balance of the core contract
* @param _reserve the reserve address
* @return the available liquidity
**/
function getReserveAvailableLiquidity(address _reserve) public view returns (uint256) {
return IERC20(_reserve).universalBalanceOf(address(this));
}
/** /**
* @dev gets the total liquidity in the reserve. The total liquidity is the balance of the core contract + total borrows * @dev gets the total liquidity in the reserve. The total liquidity is the balance of the core contract + total borrows
* @param _reserve the reserve address * @param _reserve the reserve address
@ -610,7 +508,10 @@ contract LendingPoolCore is VersionedInitializable {
**/ **/
function getReserveTotalLiquidity(address _reserve) public view returns (uint256) { function getReserveTotalLiquidity(address _reserve) public view returns (uint256) {
CoreLibrary.ReserveData storage reserve = reserves[_reserve]; CoreLibrary.ReserveData storage reserve = reserves[_reserve];
return getReserveAvailableLiquidity(_reserve).add(reserve.getTotalBorrows());
return IERC20(_reserve)
.universalBalanceOf(addressesProvider.getLendingPool())
.add(reserve.getTotalBorrows());
} }
/** /**
@ -877,8 +778,9 @@ contract LendingPoolCore is VersionedInitializable {
return 0; return 0;
} }
uint256 availableLiquidity = getReserveAvailableLiquidity(_reserve); uint256 availableLiquidity = IERC20(_reserve).universalBalanceOf(
addressesProvider.getLendingPool()
);
return totalBorrows.rayDiv(availableLiquidity.add(totalBorrows)); return totalBorrows.rayDiv(availableLiquidity.add(totalBorrows));
} }
@ -1707,14 +1609,15 @@ contract LendingPoolCore is VersionedInitializable {
CoreLibrary.ReserveData storage reserve = reserves[_reserve]; CoreLibrary.ReserveData storage reserve = reserves[_reserve];
uint256 currentAvgStableRate = reserve.currentAverageStableBorrowRate; uint256 currentAvgStableRate = reserve.currentAverageStableBorrowRate;
uint256 avialableLiquidity = IERC20(_reserve).universalBalanceOf(addressesProvider.getLendingPool())
.add(_liquidityAdded)
.sub(_liquidityTaken);
(uint256 newLiquidityRate, uint256 newStableRate, uint256 newVariableRate) = IReserveInterestRateStrategy( (uint256 newLiquidityRate, uint256 newStableRate, uint256 newVariableRate) = IReserveInterestRateStrategy(
reserve reserve.interestRateStrategyAddress
.interestRateStrategyAddress ).calculateInterestRates(
)
.calculateInterestRates(
_reserve, _reserve,
getReserveAvailableLiquidity(_reserve).add(_liquidityAdded).sub(_liquidityTaken), avialableLiquidity,
reserve.totalBorrowsStable, reserve.totalBorrowsStable,
reserve.totalBorrowsVariable, reserve.totalBorrowsVariable,
currentAvgStableRate currentAvgStableRate
@ -1738,19 +1641,6 @@ contract LendingPoolCore is VersionedInitializable {
); );
} }
/**
* @dev transfers to the protocol fees of a flashloan to the fees collection address
* @param _token the address of the token being transferred
* @param _amount the amount being transferred
**/
function transferFlashLoanProtocolFeeInternal(address _token, uint256 _amount) internal {
IERC20(_token).universalTransfer(
addressesProvider.getTokenDistributor(),
_amount
);
}
/** /**
* @dev updates the internal configuration of the core * @dev updates the internal configuration of the core
**/ **/

View File

@ -2,6 +2,7 @@
pragma solidity ^0.6.8; pragma solidity ^0.6.8;
import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../libraries/openzeppelin-upgradeability/VersionedInitializable.sol"; import "../libraries/openzeppelin-upgradeability/VersionedInitializable.sol";
import "../libraries/CoreLibrary.sol"; import "../libraries/CoreLibrary.sol";
@ -10,6 +11,7 @@ import "../libraries/WadRayMath.sol";
import "../interfaces/IPriceOracleGetter.sol"; import "../interfaces/IPriceOracleGetter.sol";
import "../interfaces/IFeeProvider.sol"; import "../interfaces/IFeeProvider.sol";
import "../tokenization/AToken.sol"; import "../tokenization/AToken.sol";
import "../libraries/UniversalERC20.sol";
import "./LendingPoolCore.sol"; import "./LendingPoolCore.sol";
@ -22,6 +24,7 @@ import "./LendingPoolCore.sol";
contract LendingPoolDataProvider is VersionedInitializable { contract LendingPoolDataProvider is VersionedInitializable {
using SafeMath for uint256; using SafeMath for uint256;
using WadRayMath for uint256; using WadRayMath for uint256;
using UniversalERC20 for IERC20;
LendingPoolCore public core; LendingPoolCore public core;
LendingPoolAddressesProvider public addressesProvider; LendingPoolAddressesProvider public addressesProvider;
@ -395,7 +398,7 @@ contract LendingPoolDataProvider is VersionedInitializable {
) )
{ {
totalLiquidity = core.getReserveTotalLiquidity(_reserve); totalLiquidity = core.getReserveTotalLiquidity(_reserve);
availableLiquidity = core.getReserveAvailableLiquidity(_reserve); availableLiquidity = IERC20(_reserve).universalBalanceOf(addressesProvider.getLendingPool());
totalBorrowsStable = core.getReserveTotalBorrowsStable(_reserve); totalBorrowsStable = core.getReserveTotalBorrowsStable(_reserve);
totalBorrowsVariable = core.getReserveTotalBorrowsVariable(_reserve); totalBorrowsVariable = core.getReserveTotalBorrowsVariable(_reserve);
liquidityRate = core.getReserveCurrentLiquidityRate(_reserve); liquidityRate = core.getReserveCurrentLiquidityRate(_reserve);

View File

@ -2,6 +2,7 @@
pragma solidity ^0.6.8; pragma solidity ^0.6.8;
import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
@ -15,6 +16,7 @@ import "../libraries/WadRayMath.sol";
import "./LendingPoolCore.sol"; import "./LendingPoolCore.sol";
import "./LendingPoolDataProvider.sol"; import "./LendingPoolDataProvider.sol";
import "../interfaces/IPriceOracleGetter.sol"; import "../interfaces/IPriceOracleGetter.sol";
import "../libraries/UniversalERC20.sol";
/** /**
* @title LendingPoolLiquidationManager contract * @title LendingPoolLiquidationManager contract
@ -25,6 +27,7 @@ contract LendingPoolLiquidationManager is ReentrancyGuard, VersionedInitializabl
using SafeMath for uint256; using SafeMath for uint256;
using WadRayMath for uint256; using WadRayMath for uint256;
using Address for address; using Address for address;
using UniversalERC20 for IERC20;
LendingPoolAddressesProvider public addressesProvider; LendingPoolAddressesProvider public addressesProvider;
LendingPoolCore core; LendingPoolCore core;
@ -216,7 +219,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 = core.getReserveAvailableLiquidity(_collateral); uint256 currentAvailableCollateral = IERC20(_collateral).universalBalanceOf(address(this));
if (currentAvailableCollateral < maxCollateralToLiquidate) { if (currentAvailableCollateral < maxCollateralToLiquidate) {
return ( return (
uint256(LiquidationErrors.NOT_ENOUGH_LIQUIDITY), uint256(LiquidationErrors.NOT_ENOUGH_LIQUIDITY),
@ -246,11 +249,15 @@ 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
collateralAtoken.burnOnLiquidation(_user, maxCollateralToLiquidate); collateralAtoken.burnOnLiquidation(_user, maxCollateralToLiquidate);
core.transferToUser(_collateral, msg.sender, maxCollateralToLiquidate); // because liquidate function executed as delegated call this will be LendingPool contract address
// and funds will be transferred from there
IERC20(_collateral).universalTransfer(msg.sender, maxCollateralToLiquidate);
} }
//transfers the principal currency to the pool //transfers the principal currency to the pool
core.transferToReserve{value: msg.value}(_reserve, msg.sender, vars.actualAmountToLiquidate); IERC20(_reserve).universalTransferFromSenderToThis(
vars.actualAmountToLiquidate, true
);
if (vars.feeLiquidated > 0) { if (vars.feeLiquidated > 0) {
//if there is enough collateral to liquidate the fee, first transfer burn an equivalent amount of //if there is enough collateral to liquidate the fee, first transfer burn an equivalent amount of
@ -258,10 +265,9 @@ contract LendingPoolLiquidationManager is ReentrancyGuard, VersionedInitializabl
collateralAtoken.burnOnLiquidation(_user, vars.liquidatedCollateralForFee); collateralAtoken.burnOnLiquidation(_user, vars.liquidatedCollateralForFee);
//then liquidate the fee by transferring it to the fee collection address //then liquidate the fee by transferring it to the fee collection address
core.liquidateFee( IERC20(_collateral).universalTransfer(
_collateral, addressesProvider.getTokenDistributor(),
vars.liquidatedCollateralForFee, vars.liquidatedCollateralForFee
addressesProvider.getTokenDistributor()
); );
emit OriginationFeeLiquidated( emit OriginationFeeLiquidated(

View File

@ -99,7 +99,7 @@ library UniversalERC20 {
* @param token underlying asset address * @param token underlying asset address
* @param amount to move * @param amount to move
**/ **/
function universalTransferFromSenderToThis(IERC20 token, uint256 amount) function universalTransferFromSenderToThis(IERC20 token, uint256 amount, bool returnExcess)
internal internal
{ {
if (amount == 0) { if (amount == 0) {
@ -107,7 +107,7 @@ library UniversalERC20 {
} }
if (isETH(token)) { if (isETH(token)) {
if (msg.value > amount) { if (msg.value > amount && returnExcess) {
// Return remainder if exist // Return remainder if exist
(bool result, ) = msg.sender.call{ (bool result, ) = msg.sender.call{
value: msg.value.sub(amount), value: msg.value.sub(amount),