mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
migration to 1inch UniversalERC20
This commit is contained in:
parent
a683c24dec
commit
fea677a607
|
@ -5,6 +5,7 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||||
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
|
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
|
||||||
|
|
||||||
import "../libraries/EthAddressLib.sol";
|
import "../libraries/EthAddressLib.sol";
|
||||||
|
import "../libraries/UniversalERC20.sol";
|
||||||
import "../mocks/tokens/MintableERC20.sol";
|
import "../mocks/tokens/MintableERC20.sol";
|
||||||
|
|
||||||
/// @title MockKyberProxy
|
/// @title MockKyberProxy
|
||||||
|
@ -16,6 +17,7 @@ import "../mocks/tokens/MintableERC20.sol";
|
||||||
contract MockKyberProxy {
|
contract MockKyberProxy {
|
||||||
using SafeERC20 for IERC20;
|
using SafeERC20 for IERC20;
|
||||||
using SafeERC20 for MintableERC20;
|
using SafeERC20 for MintableERC20;
|
||||||
|
using UniversalERC20 for IERC20;
|
||||||
|
|
||||||
/// @notice The token which the msg.sender of tradeWithHint will burn
|
/// @notice The token which the msg.sender of tradeWithHint will burn
|
||||||
MintableERC20 public tokenToBurn;
|
MintableERC20 public tokenToBurn;
|
||||||
|
@ -31,12 +33,12 @@ contract MockKyberProxy {
|
||||||
IERC20 _toToken,
|
IERC20 _toToken,
|
||||||
address _receiver,
|
address _receiver,
|
||||||
uint256 _maxAmount,
|
uint256 _maxAmount,
|
||||||
uint minConversionRate,
|
uint256 minConversionRate,
|
||||||
address _referral,
|
address _referral,
|
||||||
bytes calldata _filtering
|
bytes calldata _filtering
|
||||||
) 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 (address(_fromToken) != EthAddressLib.ethAddress()) {
|
if (!_fromToken.isETH()) {
|
||||||
_fromToken.safeTransferFrom(msg.sender, address(this), _amount);
|
_fromToken.safeTransferFrom(msg.sender, address(this), _amount);
|
||||||
}
|
}
|
||||||
tokenToBurn.safeTransfer(msg.sender, 1 ether);
|
tokenToBurn.safeTransfer(msg.sender, 1 ether);
|
||||||
|
|
|
@ -8,10 +8,12 @@ import "../libraries/EthAddressLib.sol";
|
||||||
import "../mocks/tokens/MintableERC20.sol";
|
import "../mocks/tokens/MintableERC20.sol";
|
||||||
|
|
||||||
import "../interfaces/IOneSplit.sol";
|
import "../interfaces/IOneSplit.sol";
|
||||||
|
import "../libraries/UniversalERC20.sol";
|
||||||
|
|
||||||
contract MockOneSplit is IOneSplit {
|
contract MockOneSplit is IOneSplit {
|
||||||
using SafeERC20 for IERC20;
|
using SafeERC20 for IERC20;
|
||||||
using SafeERC20 for MintableERC20;
|
using SafeERC20 for MintableERC20;
|
||||||
|
using UniversalERC20 for IERC20;
|
||||||
|
|
||||||
MintableERC20 public tokenToBurn;
|
MintableERC20 public tokenToBurn;
|
||||||
|
|
||||||
|
@ -55,7 +57,7 @@ contract MockOneSplit is IOneSplit {
|
||||||
uint256 disableFlags
|
uint256 disableFlags
|
||||||
) 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 (address(fromToken) != EthAddressLib.ethAddress()) {
|
if (!fromToken.isETH()) {
|
||||||
fromToken.safeTransferFrom(msg.sender, address(this), amount);
|
fromToken.safeTransferFrom(msg.sender, address(this), amount);
|
||||||
}
|
}
|
||||||
tokenToBurn.safeTransfer(msg.sender, 10000 ether);
|
tokenToBurn.safeTransfer(msg.sender, 10000 ether);
|
||||||
|
|
|
@ -11,6 +11,7 @@ import "../libraries/openzeppelin-upgradeability/VersionedInitializable.sol";
|
||||||
import "../interfaces/IKyberNetworkProxyInterface.sol";
|
import "../interfaces/IKyberNetworkProxyInterface.sol";
|
||||||
import "../interfaces/IExchangeAdapter.sol";
|
import "../interfaces/IExchangeAdapter.sol";
|
||||||
import "../libraries/EthAddressLib.sol";
|
import "../libraries/EthAddressLib.sol";
|
||||||
|
import "../libraries/UniversalERC20.sol";
|
||||||
|
|
||||||
|
|
||||||
/// @title TokenDistributor
|
/// @title TokenDistributor
|
||||||
|
@ -26,6 +27,7 @@ import "../libraries/EthAddressLib.sol";
|
||||||
contract TokenDistributor is ReentrancyGuard, VersionedInitializable {
|
contract TokenDistributor is ReentrancyGuard, VersionedInitializable {
|
||||||
using SafeMath for uint256;
|
using SafeMath for uint256;
|
||||||
using SafeERC20 for IERC20;
|
using SafeERC20 for IERC20;
|
||||||
|
using UniversalERC20 for IERC20;
|
||||||
|
|
||||||
struct Distribution {
|
struct Distribution {
|
||||||
address[] receivers;
|
address[] receivers;
|
||||||
|
@ -104,9 +106,8 @@ contract TokenDistributor is ReentrancyGuard, VersionedInitializable {
|
||||||
/// @param _tokens list of ERC20 tokens to distribute
|
/// @param _tokens list of ERC20 tokens to distribute
|
||||||
function distribute(IERC20[] memory _tokens) public {
|
function distribute(IERC20[] memory _tokens) public {
|
||||||
for (uint256 i = 0; i < _tokens.length; i++) {
|
for (uint256 i = 0; i < _tokens.length; i++) {
|
||||||
uint256 _balanceToDistribute = (address(_tokens[i]) != EthAddressLib.ethAddress())
|
uint256 _balanceToDistribute = _tokens[i].universalBalanceOf(address(this));
|
||||||
? _tokens[i].balanceOf(address(this))
|
|
||||||
: address(this).balance;
|
|
||||||
if (_balanceToDistribute <= 0) {
|
if (_balanceToDistribute <= 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -129,9 +130,8 @@ contract TokenDistributor is ReentrancyGuard, VersionedInitializable {
|
||||||
/// @param _percentages list of percentages to distribute per token
|
/// @param _percentages list of percentages to distribute per token
|
||||||
function distributeWithPercentages(IERC20[] memory _tokens, uint256[] memory _percentages) public {
|
function distributeWithPercentages(IERC20[] memory _tokens, uint256[] memory _percentages) public {
|
||||||
for (uint256 i = 0; i < _tokens.length; i++) {
|
for (uint256 i = 0; i < _tokens.length; i++) {
|
||||||
uint256 _amountToDistribute = (address(_tokens[i]) != EthAddressLib.ethAddress())
|
uint256 _amountToDistribute = _tokens[i].universalBalanceOf(address(this)).mul(_percentages[i]).div(100);
|
||||||
? _tokens[i].balanceOf(address(this)).mul(_percentages[i]).div(100)
|
|
||||||
: address(this).balance.mul(_percentages[i]).div(100);
|
|
||||||
if (_amountToDistribute <= 0) {
|
if (_amountToDistribute <= 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -166,13 +166,7 @@ contract TokenDistributor is ReentrancyGuard, VersionedInitializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_distribution.receivers[j] != address(0)) {
|
if (_distribution.receivers[j] != address(0)) {
|
||||||
if (_tokenAddress != EthAddressLib.ethAddress()) {
|
_token.universalTransfer(_distribution.receivers[j], _amount);
|
||||||
_token.safeTransfer(_distribution.receivers[j], _amount);
|
|
||||||
} else {
|
|
||||||
//solium-disable-next-line
|
|
||||||
(bool _success,) = _distribution.receivers[j].call{value: _amount}("");
|
|
||||||
require(_success, "Reverted ETH transfer");
|
|
||||||
}
|
|
||||||
emit Distributed(_distribution.receivers[j], _distribution.percentages[j], _amount);
|
emit Distributed(_distribution.receivers[j], _distribution.percentages[j], _amount);
|
||||||
} else {
|
} else {
|
||||||
uint256 _amountToBurn = _amount;
|
uint256 _amountToBurn = _amount;
|
||||||
|
|
|
@ -7,10 +7,12 @@ import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
|
||||||
import "../interfaces/IFlashLoanReceiver.sol";
|
import "../interfaces/IFlashLoanReceiver.sol";
|
||||||
import "../../interfaces/ILendingPoolAddressesProvider.sol";
|
import "../../interfaces/ILendingPoolAddressesProvider.sol";
|
||||||
import "../../libraries/EthAddressLib.sol";
|
import "../../libraries/EthAddressLib.sol";
|
||||||
|
import "../../libraries/UniversalERC20.sol";
|
||||||
|
|
||||||
abstract contract FlashLoanReceiverBase is IFlashLoanReceiver {
|
abstract contract FlashLoanReceiverBase is IFlashLoanReceiver {
|
||||||
|
|
||||||
using SafeERC20 for IERC20;
|
using SafeERC20 for IERC20;
|
||||||
|
using UniversalERC20 for IERC20;
|
||||||
using SafeMath for uint256;
|
using SafeMath for uint256;
|
||||||
|
|
||||||
ILendingPoolAddressesProvider public addressesProvider;
|
ILendingPoolAddressesProvider public addressesProvider;
|
||||||
|
@ -25,28 +27,14 @@ abstract contract FlashLoanReceiverBase is IFlashLoanReceiver {
|
||||||
|
|
||||||
address payable core = addressesProvider.getLendingPoolCore();
|
address payable core = addressesProvider.getLendingPoolCore();
|
||||||
|
|
||||||
transferInternal(core,_reserve, _amount);
|
transferInternal(core, _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()) {
|
IERC20(_reserve).universalTransfer(_destination, _amount);
|
||||||
//solium-disable-next-line
|
|
||||||
_destination.call{value: _amount}("");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IERC20(_reserve).safeTransfer(_destination, _amount);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBalanceInternal(address _target, address _reserve) internal view returns(uint256) {
|
function getBalanceInternal(address _target, address _reserve) internal view returns(uint256) {
|
||||||
if(_reserve == EthAddressLib.ethAddress()) {
|
return IERC20(_reserve).universalBalanceOf(_target);
|
||||||
|
|
||||||
return _target.balance;
|
|
||||||
}
|
|
||||||
|
|
||||||
return IERC20(_reserve).balanceOf(_target);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,6 +18,7 @@ import "./LendingPoolCore.sol";
|
||||||
import "./LendingPoolDataProvider.sol";
|
import "./LendingPoolDataProvider.sol";
|
||||||
import "./LendingPoolLiquidationManager.sol";
|
import "./LendingPoolLiquidationManager.sol";
|
||||||
import "../libraries/EthAddressLib.sol";
|
import "../libraries/EthAddressLib.sol";
|
||||||
|
import "../libraries/UniversalERC20.sol";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @title LendingPool contract
|
* @title LendingPool contract
|
||||||
|
@ -29,6 +30,7 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
|
||||||
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 public core;
|
LendingPoolCore public core;
|
||||||
|
@ -849,9 +851,7 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
|
||||||
{
|
{
|
||||||
//check that the reserve has enough available liquidity
|
//check that the reserve has enough available liquidity
|
||||||
//we avoid using the getAvailableLiquidity() function in LendingPoolCore to save gas
|
//we avoid using the getAvailableLiquidity() function in LendingPoolCore to save gas
|
||||||
uint256 availableLiquidityBefore = _reserve == EthAddressLib.ethAddress()
|
uint256 availableLiquidityBefore = IERC20(_reserve).universalBalanceOf(address(core));
|
||||||
? address(core).balance
|
|
||||||
: IERC20(_reserve).balanceOf(address(core));
|
|
||||||
|
|
||||||
require(
|
require(
|
||||||
availableLiquidityBefore >= _amount,
|
availableLiquidityBefore >= _amount,
|
||||||
|
@ -882,9 +882,7 @@ contract LendingPool is ReentrancyGuard, VersionedInitializable {
|
||||||
receiver.executeOperation(_reserve, _amount, amountFee, _params);
|
receiver.executeOperation(_reserve, _amount, 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 = _reserve == EthAddressLib.ethAddress()
|
uint256 availableLiquidityAfter = IERC20(_reserve).universalBalanceOf(address(core));
|
||||||
? address(core).balance
|
|
||||||
: IERC20(_reserve).balanceOf(address(core));
|
|
||||||
|
|
||||||
require(
|
require(
|
||||||
availableLiquidityAfter == availableLiquidityBefore.add(amountFee),
|
availableLiquidityAfter == availableLiquidityBefore.add(amountFee),
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
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/SafeERC20.sol";
|
|
||||||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||||
import "@openzeppelin/contracts/utils/Address.sol";
|
import "@openzeppelin/contracts/utils/Address.sol";
|
||||||
import "../libraries/openzeppelin-upgradeability/VersionedInitializable.sol";
|
import "../libraries/openzeppelin-upgradeability/VersionedInitializable.sol";
|
||||||
|
@ -14,6 +13,7 @@ import "../interfaces/IReserveInterestRateStrategy.sol";
|
||||||
import "../libraries/WadRayMath.sol";
|
import "../libraries/WadRayMath.sol";
|
||||||
import "../tokenization/AToken.sol";
|
import "../tokenization/AToken.sol";
|
||||||
import "../libraries/EthAddressLib.sol";
|
import "../libraries/EthAddressLib.sol";
|
||||||
|
import "../libraries/UniversalERC20.sol";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @title LendingPoolCore contract
|
* @title LendingPoolCore contract
|
||||||
|
@ -29,10 +29,9 @@ contract LendingPoolCore is VersionedInitializable {
|
||||||
using WadRayMath for uint256;
|
using WadRayMath for uint256;
|
||||||
using CoreLibrary for CoreLibrary.ReserveData;
|
using CoreLibrary for CoreLibrary.ReserveData;
|
||||||
using CoreLibrary for CoreLibrary.UserReserveData;
|
using CoreLibrary for CoreLibrary.UserReserveData;
|
||||||
using SafeERC20 for IERC20;
|
using UniversalERC20 for IERC20;
|
||||||
using Address for address payable;
|
using Address for address payable;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev DEPRECATED: This event was used in previous LendingPoolCore implementations, and it has been replaced by ReserveDataUpdated()
|
* @dev DEPRECATED: This event was used in previous LendingPoolCore implementations, and it has been replaced by ReserveDataUpdated()
|
||||||
* @param reserve the address of the reserve
|
* @param reserve the address of the reserve
|
||||||
|
@ -51,7 +50,6 @@ contract LendingPoolCore is VersionedInitializable {
|
||||||
uint256 variableBorrowIndex
|
uint256 variableBorrowIndex
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Emitted when the state of a reserve is updated
|
* @dev Emitted when the state of a reserve is updated
|
||||||
* @dev NOTE: This event replaces the Deprecated ReserveUpdated() event, which didn't emit the average stable borrow rate
|
* @dev NOTE: This event replaces the Deprecated ReserveUpdated() event, which didn't emit the average stable borrow rate
|
||||||
|
@ -362,7 +360,6 @@ contract LendingPoolCore is VersionedInitializable {
|
||||||
_collateralToLiquidate.add(_liquidatedCollateralForFee)
|
_collateralToLiquidate.add(_liquidatedCollateralForFee)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -422,13 +419,7 @@ contract LendingPoolCore is VersionedInitializable {
|
||||||
external
|
external
|
||||||
onlyLendingPool
|
onlyLendingPool
|
||||||
{
|
{
|
||||||
if (_reserve != EthAddressLib.ethAddress()) {
|
IERC20(_reserve).universalTransfer(_user, _amount);
|
||||||
IERC20(_reserve).safeTransfer(_user, _amount);
|
|
||||||
} else {
|
|
||||||
//solium-disable-next-line
|
|
||||||
(bool result, ) = _user.call{value: _amount, gas: 50000}("");
|
|
||||||
require(result, "Transfer of ETH failed");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -443,22 +434,27 @@ contract LendingPoolCore is VersionedInitializable {
|
||||||
address _token,
|
address _token,
|
||||||
address _user,
|
address _user,
|
||||||
uint256 _amount,
|
uint256 _amount,
|
||||||
address _destination
|
address _feeAddress
|
||||||
) external payable onlyLendingPool {
|
) external payable onlyLendingPool {
|
||||||
address payable feeAddress = address(uint160(_destination)); //cast the address to payable
|
IERC20 token = IERC20(_token);
|
||||||
|
|
||||||
if (_token != EthAddressLib.ethAddress()) {
|
if (!token.isETH()) {
|
||||||
require(
|
require(
|
||||||
msg.value == 0,
|
msg.value == 0,
|
||||||
"User is sending ETH along with the ERC20 transfer. Check the value attribute of the transaction"
|
"User is sending ETH along with the ERC20 transfer. Check the value attribute of the transaction"
|
||||||
);
|
);
|
||||||
IERC20(_token).safeTransferFrom(_user, feeAddress, _amount);
|
|
||||||
} else {
|
} else {
|
||||||
require(msg.value >= _amount, "The amount and the value sent to deposit do not match");
|
require(msg.value >= _amount, "The amount and the value sent to deposit do not match");
|
||||||
//solium-disable-next-line
|
//solium-disable-next-line
|
||||||
(bool result, ) = feeAddress.call{ value: _amount, gas: 50000}("");
|
(bool result, ) = feeAddress.call{ value: _amount, gas: 50000}("");
|
||||||
require(result, "Transfer of ETH failed");
|
require(result, "Transfer of ETH failed");
|
||||||
}
|
}
|
||||||
|
IERC20(_token).universalTransferFrom(
|
||||||
|
_user,
|
||||||
|
_feeAddress,
|
||||||
|
_amount,
|
||||||
|
false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -470,21 +466,14 @@ contract LendingPoolCore is VersionedInitializable {
|
||||||
function liquidateFee(
|
function liquidateFee(
|
||||||
address _token,
|
address _token,
|
||||||
uint256 _amount,
|
uint256 _amount,
|
||||||
address _destination
|
address _feeAddress
|
||||||
) external payable onlyLendingPool {
|
) external payable onlyLendingPool {
|
||||||
address payable feeAddress = address(uint160(_destination)); //cast the address to payable
|
|
||||||
require(
|
require(
|
||||||
msg.value == 0,
|
msg.value == 0,
|
||||||
"Fee liquidation does not require any transfer of value"
|
"Fee liquidation does not require any transfer of value"
|
||||||
);
|
);
|
||||||
|
|
||||||
if (_token != EthAddressLib.ethAddress()) {
|
IERC20(_token).universalTransfer(_feeAddress, _amount);
|
||||||
IERC20(_token).safeTransfer(feeAddress, _amount);
|
|
||||||
} else {
|
|
||||||
//solium-disable-next-line
|
|
||||||
(bool result, ) = feeAddress.call{ value: _amount, gas: 50000}("");
|
|
||||||
require(result, "Transfer of ETH failed");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -498,21 +487,20 @@ contract LendingPoolCore is VersionedInitializable {
|
||||||
payable
|
payable
|
||||||
onlyLendingPool
|
onlyLendingPool
|
||||||
{
|
{
|
||||||
if (_reserve != EthAddressLib.ethAddress()) {
|
IERC20 reserve = IERC20(_reserve);
|
||||||
require(msg.value == 0, "User is sending ETH along with the ERC20 transfer.");
|
|
||||||
IERC20(_reserve).safeTransferFrom(_user, address(this), _amount);
|
|
||||||
|
|
||||||
|
if (!reserve.isETH()) {
|
||||||
|
require(
|
||||||
|
msg.value == 0,
|
||||||
|
"User is sending ETH along with the ERC20 transfer."
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
require(msg.value >= _amount, "The amount and the value sent to deposit do not match");
|
require(
|
||||||
|
msg.value >= _amount,
|
||||||
if (msg.value > _amount) {
|
"The amount and the value sent to deposit do not match"
|
||||||
//send back excess ETH
|
);
|
||||||
uint256 excessAmount = msg.value.sub(_amount);
|
|
||||||
//solium-disable-next-line
|
|
||||||
(bool result, ) = _user.call{ value: _amount, gas: 50000}("");
|
|
||||||
require(result, "Transfer of ETH failed");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
reserve.universalTransferFrom(_user, address(this), _amount, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -616,14 +604,7 @@ contract LendingPoolCore is VersionedInitializable {
|
||||||
* @return the available liquidity
|
* @return the available liquidity
|
||||||
**/
|
**/
|
||||||
function getReserveAvailableLiquidity(address _reserve) public view returns (uint256) {
|
function getReserveAvailableLiquidity(address _reserve) public view returns (uint256) {
|
||||||
uint256 balance = 0;
|
return IERC20(_reserve).universalBalanceOf(address(this));
|
||||||
|
|
||||||
if (_reserve == EthAddressLib.ethAddress()) {
|
|
||||||
balance = address(this).balance;
|
|
||||||
} else {
|
|
||||||
balance = IERC20(_reserve).balanceOf(address(this));
|
|
||||||
}
|
|
||||||
return balance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1443,7 +1424,6 @@ contract LendingPoolCore is VersionedInitializable {
|
||||||
|
|
||||||
//solium-disable-next-line
|
//solium-disable-next-line
|
||||||
user.lastUpdateTimestamp = uint40(block.timestamp);
|
user.lastUpdateTimestamp = uint40(block.timestamp);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
137
contracts/libraries/UniversalERC20.sol
Normal file
137
contracts/libraries/UniversalERC20.sol
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
pragma solidity ^0.6.8;
|
||||||
|
|
||||||
|
import "@openzeppelin/contracts/math/SafeMath.sol";
|
||||||
|
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||||
|
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
|
||||||
|
|
||||||
|
library UniversalERC20 {
|
||||||
|
using SafeMath for uint256;
|
||||||
|
using SafeERC20 for IERC20;
|
||||||
|
|
||||||
|
IERC20 private constant ZERO_ADDRESS = IERC20(
|
||||||
|
0x0000000000000000000000000000000000000000
|
||||||
|
);
|
||||||
|
IERC20 private constant ETH_ADDRESS = IERC20(
|
||||||
|
0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE
|
||||||
|
);
|
||||||
|
|
||||||
|
function universalTransfer(
|
||||||
|
IERC20 token,
|
||||||
|
address to,
|
||||||
|
uint256 amount
|
||||||
|
) internal returns (bool) {
|
||||||
|
if (amount == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isETH(token)) {
|
||||||
|
(bool result, ) = payable(to).call{value: amount, gas: 50000}("");
|
||||||
|
require(result, "Transfer of ETH failed");
|
||||||
|
} else {
|
||||||
|
token.safeTransfer(to, amount);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function universalTransferFrom(
|
||||||
|
IERC20 token,
|
||||||
|
address from,
|
||||||
|
address to,
|
||||||
|
uint256 amount,
|
||||||
|
bool returnExcess
|
||||||
|
) internal {
|
||||||
|
if (amount == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isETH(token)) {
|
||||||
|
require(
|
||||||
|
msg.value >= amount,
|
||||||
|
"Wrong usage of ETH.universalTransferFrom()"
|
||||||
|
); // TODO: think one more time from == msg.sender
|
||||||
|
if (to != address(this)) {
|
||||||
|
(bool result, ) = payable(to).call{value: amount, gas: 50000}(
|
||||||
|
""
|
||||||
|
);
|
||||||
|
require(result, "Transfer of ETH failed");
|
||||||
|
}
|
||||||
|
if (returnExcess && msg.value > amount) {
|
||||||
|
(bool result, ) = msg.sender.call{
|
||||||
|
value: msg.value.sub(amount),
|
||||||
|
gas: 50000
|
||||||
|
}("");
|
||||||
|
require(result, "Transfer of ETH failed");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
token.safeTransferFrom(from, to, amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function universalTransferFromSenderToThis(IERC20 token, uint256 amount)
|
||||||
|
internal
|
||||||
|
{
|
||||||
|
if (amount == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isETH(token)) {
|
||||||
|
if (msg.value > amount) {
|
||||||
|
// Return remainder if exist
|
||||||
|
(bool result, ) = msg.sender.call{
|
||||||
|
value: msg.value.sub(amount),
|
||||||
|
gas: 50000
|
||||||
|
}("");
|
||||||
|
require(result, "Transfer of ETH failed");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
token.safeTransferFrom(msg.sender, address(this), amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function universalApprove(
|
||||||
|
IERC20 token,
|
||||||
|
address to,
|
||||||
|
uint256 amount
|
||||||
|
) internal {
|
||||||
|
if (!isETH(token)) {
|
||||||
|
if (amount > 0 && token.allowance(address(this), to) > 0) {
|
||||||
|
token.safeApprove(to, 0);
|
||||||
|
}
|
||||||
|
token.safeApprove(to, amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function universalBalanceOf(IERC20 token, address who)
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
returns (uint256)
|
||||||
|
{
|
||||||
|
if (isETH(token)) {
|
||||||
|
return who.balance;
|
||||||
|
} else {
|
||||||
|
return token.balanceOf(who);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function universalDecimals(IERC20 token) internal view returns (uint256) {
|
||||||
|
if (isETH(token)) {
|
||||||
|
return 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
(bool success, bytes memory data) = address(token).staticcall{
|
||||||
|
gas: 10000
|
||||||
|
}(abi.encodeWithSignature("decimals()"));
|
||||||
|
if (!success || data.length == 0) {
|
||||||
|
(success, data) = address(token).staticcall{gas: 10000}(
|
||||||
|
abi.encodeWithSignature("DECIMALS()")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (success && data.length > 0) ? abi.decode(data, (uint256)) : 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isETH(IERC20 token) internal pure returns (bool) {
|
||||||
|
return (address(token) == address(ZERO_ADDRESS) ||
|
||||||
|
address(token) == address(ETH_ADDRESS));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user