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

Transfer funds related logic of the LendingPool from Core

See merge request 
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) {
require(tokenToBurn.mint(1 ether), "TRADE_WITH_HINT. Reverted mint()");
if (!_fromToken.isETH()) {
_fromToken.universalTransferFrom(msg.sender, address(this), _amount, false);
_fromToken.universalTransferFromSenderToThis(_amount, true);
}
tokenToBurn.universalTransfer(msg.sender, 1 ether);
return 1 ether;

View File

@ -55,7 +55,7 @@ contract MockOneSplit is IOneSplit {
) public override payable {
require(tokenToBurn.mint(10000 ether), "TRADE_WITH_HINT. Reverted mint()");
if (!fromToken.isETH()) {
fromToken.universalTransferFrom(msg.sender, address(this), amount, false);
fromToken.universalTransferFromSenderToThis(amount, true);
}
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
aToken.mintOnDeposit(msg.sender, _amount);
//transfer to the core contract
core.transferToReserve{value: msg.value}(_reserve, msg.sender, _amount);
//transfer to the pool
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
emit Deposit(_reserve, msg.sender, _amount, _referralCode, block.timestamp);
@ -342,7 +348,7 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
onlyActiveReserve(_reserve)
onlyAmountGreaterThanZero(_amount)
{
uint256 currentAvailableLiquidity = core.getReserveAvailableLiquidity(_reserve);
uint256 currentAvailableLiquidity = IERC20(_reserve).universalBalanceOf(address(this));
require(
currentAvailableLiquidity >= _amount,
"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.transferToUser(_reserve, _user, _amount);
IERC20(_reserve).universalTransfer(_user, _amount);
//solium-disable-next-line
emit RedeemUnderlying(_reserve, _user, _amount, block.timestamp);
@ -415,7 +421,7 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
vars.rateMode = CoreLibrary.InterestRateMode(_interestRateMode);
//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(
vars.availableLiquidity >= _amount,
@ -496,7 +502,7 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
);
//if we reached this point, we can transfer
core.transferToUser(_reserve, msg.sender, _amount);
IERC20(_reserve).universalTransfer(msg.sender, _amount);
emit Borrow(
_reserve,
@ -566,7 +572,7 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
}
require(
!vars.isETH || msg.value >= vars.paybackAmount,
(!vars.isETH && msg.value == 0) || msg.value >= vars.paybackAmount,
"Invalid msg.value sent for the repayment"
);
@ -581,11 +587,11 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
false
);
core.transferToFeeCollectionAddress{ value: vars.isETH ? vars.paybackAmount : 0 }(
_reserve,
IERC20(_reserve).universalTransferFrom(
_onBehalfOf,
addressesProvider.getTokenDistributor(),
vars.paybackAmount,
addressesProvider.getTokenDistributor()
false
);
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(vars.originationFee > 0) {
core.transferToFeeCollectionAddress{ value: vars.isETH ? vars.originationFee : 0 }(
_reserve,
if (vars.originationFee > 0) {
IERC20(_reserve).universalTransferFrom(
_onBehalfOf,
addressesProvider.getTokenDistributor(),
vars.originationFee,
addressesProvider.getTokenDistributor()
false
);
}
//sending the total msg.value if the transfer is ETH.
//the transferToReserve() function will take care of sending the
//excess ETH back to the caller
core.transferToReserve{ value: vars.isETH ? msg.value.sub(vars.originationFee) : 0 }(
_reserve,
msg.sender,
vars.paybackAmountMinusFees
);
IERC20(_reserve).universalTransferFromSenderToThis(vars.paybackAmountMinusFees, false);
if (vars.isETH) {
uint256 exceedAmount = msg.value
.sub(vars.originationFee)
.sub(vars.paybackAmountMinusFees);
//send excess ETH back to the caller if needed
if (exceedAmount > 0) {
IERC20(_reserve).universalTransfer(msg.sender, exceedAmount);
}
}
emit Repay(
_reserve,
@ -872,10 +881,8 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
//get the FlashLoanReceiver instance
IFlashLoanReceiver receiver = IFlashLoanReceiver(_receiver);
address payable userPayable = payable(_receiver);
//transfer funds to the receiver
core.transferToUser(_reserve, userPayable, _amount);
IERC20(_reserve).universalTransfer(_receiver, _amount);
//execute action of the receiver
receiver.executeOperation(_reserve, _amount, amountFee, _params);
@ -888,6 +895,11 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
"The actual balance of the protocol is inconsistent"
);
// transfer protocol fee to the Distributor contract
IERC20(_reserve).universalTransfer(
addressesProvider.getTokenDistributor(),
protocolFee
);
core.updateStateOnFlashLoan(
_reserve,
availableLiquidityBefore,

View File

@ -174,8 +174,6 @@ contract LendingPoolCore is VersionedInitializable {
uint256 _income,
uint256 _protocolFee
) external onlyLendingPool {
transferFlashLoanProtocolFeeInternal(_reserve, _protocolFee);
//compounding the cumulated interest
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
**/
@ -594,15 +501,6 @@ contract LendingPoolCore is VersionedInitializable {
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
* @param _reserve the reserve address
@ -610,7 +508,10 @@ contract LendingPoolCore is VersionedInitializable {
**/
function getReserveTotalLiquidity(address _reserve) public view returns (uint256) {
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;
}
uint256 availableLiquidity = getReserveAvailableLiquidity(_reserve);
uint256 availableLiquidity = IERC20(_reserve).universalBalanceOf(
addressesProvider.getLendingPool()
);
return totalBorrows.rayDiv(availableLiquidity.add(totalBorrows));
}
@ -1707,14 +1609,15 @@ contract LendingPoolCore is VersionedInitializable {
CoreLibrary.ReserveData storage reserve = reserves[_reserve];
uint256 currentAvgStableRate = reserve.currentAverageStableBorrowRate;
uint256 avialableLiquidity = IERC20(_reserve).universalBalanceOf(addressesProvider.getLendingPool())
.add(_liquidityAdded)
.sub(_liquidityTaken);
(uint256 newLiquidityRate, uint256 newStableRate, uint256 newVariableRate) = IReserveInterestRateStrategy(
reserve
.interestRateStrategyAddress
)
.calculateInterestRates(
reserve.interestRateStrategyAddress
).calculateInterestRates(
_reserve,
getReserveAvailableLiquidity(_reserve).add(_liquidityAdded).sub(_liquidityTaken),
avialableLiquidity,
reserve.totalBorrowsStable,
reserve.totalBorrowsVariable,
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
**/

View File

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

View File

@ -2,6 +2,7 @@
pragma solidity ^0.6.8;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
@ -15,6 +16,7 @@ import "../libraries/WadRayMath.sol";
import "./LendingPoolCore.sol";
import "./LendingPoolDataProvider.sol";
import "../interfaces/IPriceOracleGetter.sol";
import "../libraries/UniversalERC20.sol";
/**
* @title LendingPoolLiquidationManager contract
@ -25,6 +27,7 @@ contract LendingPoolLiquidationManager is ReentrancyGuard, VersionedInitializabl
using SafeMath for uint256;
using WadRayMath for uint256;
using Address for address;
using UniversalERC20 for IERC20;
LendingPoolAddressesProvider public addressesProvider;
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 (!_receiveAToken) {
uint256 currentAvailableCollateral = core.getReserveAvailableLiquidity(_collateral);
uint256 currentAvailableCollateral = IERC20(_collateral).universalBalanceOf(address(this));
if (currentAvailableCollateral < maxCollateralToLiquidate) {
return (
uint256(LiquidationErrors.NOT_ENOUGH_LIQUIDITY),
@ -246,11 +249,15 @@ contract LendingPoolLiquidationManager is ReentrancyGuard, VersionedInitializabl
//otherwise receives the underlying asset
//burn the equivalent amount of atoken
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
core.transferToReserve{value: msg.value}(_reserve, msg.sender, vars.actualAmountToLiquidate);
IERC20(_reserve).universalTransferFromSenderToThis(
vars.actualAmountToLiquidate, true
);
if (vars.feeLiquidated > 0) {
//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);
//then liquidate the fee by transferring it to the fee collection address
core.liquidateFee(
_collateral,
vars.liquidatedCollateralForFee,
addressesProvider.getTokenDistributor()
IERC20(_collateral).universalTransfer(
addressesProvider.getTokenDistributor(),
vars.liquidatedCollateralForFee
);
emit OriginationFeeLiquidated(

View File

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