diff --git a/contracts/fees/MockKyberProxy.sol b/contracts/fees/MockKyberProxy.sol index 044c4b20..4dc31f3a 100644 --- a/contracts/fees/MockKyberProxy.sol +++ b/contracts/fees/MockKyberProxy.sol @@ -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); } tokenToBurn.universalTransfer(msg.sender, 1 ether); return 1 ether; diff --git a/contracts/fees/MockOneSplit.sol b/contracts/fees/MockOneSplit.sol index 96d8fc74..d8791e21 100644 --- a/contracts/fees/MockOneSplit.sol +++ b/contracts/fees/MockOneSplit.sol @@ -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); } tokenToBurn.universalTransfer(msg.sender, 10000 ether); } diff --git a/contracts/lendingpool/LendingPool.sol b/contracts/lendingpool/LendingPool.sol index 0a209f24..fcf73c82 100644 --- a/contracts/lendingpool/LendingPool.sol +++ b/contracts/lendingpool/LendingPool.sol @@ -321,6 +321,7 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable { msg.value == 0, "User is sending ETH along with the ERC20 transfer." ); + } IERC20(_reserve).universalTransferFromSenderToThis(_amount); //solium-disable-next-line @@ -347,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" @@ -355,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); @@ -420,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, @@ -501,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, @@ -586,11 +587,17 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable { false ); - core.transferToFeeCollectionAddress{ value: vars.isETH ? vars.paybackAmount : 0 }( - _reserve, + if (!vars.isETH) { // TODO: review needed, maybe we should not care + require( + msg.value == 0, + "User is sending ETH along with the ERC20 transfer. Check the value attribute of the transaction" + ); + } + IERC20(_reserve).universalTransferFrom( _onBehalfOf, + addressesProvider.getTokenDistributor(), vars.paybackAmount, - addressesProvider.getTokenDistributor() + false ); emit Repay( @@ -618,27 +625,38 @@ 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) { + if (!vars.isETH) { // TODO: review needed, maybe we should not care + require( + msg.value == 0, + "User is sending ETH along with the ERC20 transfer. Check the value attribute of the transaction" + ); + } + IERC20(_reserve).universalTransferFrom( _onBehalfOf, + addressesProvider.getTokenDistributor(), vars.originationFee, - addressesProvider.getTokenDistributor() + false ); } - //sending the total msg.value if the transfer is ETH. - //the universalTransferFromSenderToThis() function will take care of sending the - //excess ETH back to the caller - if (!IERC20(_reserve).isETH()) { //TODO: review needed, most probably we can remove it + if (vars.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{ - value: vars.isETH ? msg.value.sub(vars.originationFee) : 0 - }(vars.paybackAmountMinusFees); + IERC20(_reserve).universalTransferFromSenderToThis(vars.paybackAmountMinusFees); + + if (vars.isETH) { + uint256 exceedAmount = msg.value + .sub(vars.originationFee) + .sub(vars.paybackAmountMinusFees); + //send excess ETH back to the caller in needed + if (exceedAmount > 0) { + IERC20(_reserve).universalTransfer(msg.sender, exceedAmount); + } + } emit Repay( _reserve, @@ -881,10 +899,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); @@ -897,6 +913,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, diff --git a/contracts/lendingpool/LendingPoolCore.sol b/contracts/lendingpool/LendingPoolCore.sol index 5273d028..b2ad2f65 100644 --- a/contracts/lendingpool/LendingPoolCore.sol +++ b/contracts/lendingpool/LendingPoolCore.sol @@ -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,70 +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); - } - /** * @notice data access functions **/ @@ -567,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 @@ -583,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()); } /** @@ -850,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)); } @@ -1680,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 @@ -1711,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 **/ diff --git a/contracts/lendingpool/LendingPoolDataProvider.sol b/contracts/lendingpool/LendingPoolDataProvider.sol index d1c7318b..4cef745d 100644 --- a/contracts/lendingpool/LendingPoolDataProvider.sol +++ b/contracts/lendingpool/LendingPoolDataProvider.sol @@ -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); diff --git a/contracts/lendingpool/LendingPoolLiquidationManager.sol b/contracts/lendingpool/LendingPoolLiquidationManager.sol index fb28f4c0..9543a7fc 100644 --- a/contracts/lendingpool/LendingPoolLiquidationManager.sol +++ b/contracts/lendingpool/LendingPoolLiquidationManager.sol @@ -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,15 +249,14 @@ 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); //TODO: update to universal transfer + // 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 - IERC20(_reserve).universalTransferFrom( - msg.sender, - addressesProvider.getLendingPool(), - vars.actualAmountToLiquidate, - true + IERC20(_reserve).universalTransferFromSenderToThis( + vars.actualAmountToLiquidate ); if (vars.feeLiquidated > 0) { @@ -263,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(