2021-03-18 15:44:52 +00:00
|
|
|
// SPDX-License-Identifier: agpl-3.0
|
|
|
|
pragma solidity 0.6.12;
|
|
|
|
pragma experimental ABIEncoderV2;
|
|
|
|
|
|
|
|
import {SafeMath} from '../dependencies/openzeppelin/contracts/SafeMath.sol';
|
|
|
|
import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
|
|
|
|
import {IERC20Detailed} from '../dependencies/openzeppelin/contracts/IERC20Detailed.sol';
|
|
|
|
import {SafeERC20} from '../dependencies/openzeppelin/contracts/SafeERC20.sol';
|
|
|
|
import {Ownable} from '../dependencies/openzeppelin/contracts/Ownable.sol';
|
|
|
|
import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol';
|
|
|
|
import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
|
|
|
|
import {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol';
|
|
|
|
import {IERC20WithPermit} from '../interfaces/IERC20WithPermit.sol';
|
|
|
|
import {FlashLoanReceiverBase} from '../flashloan/base/FlashLoanReceiverBase.sol';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @title BaseParaSwapAdapter
|
|
|
|
* @notice Utility functions for adapters using ParaSwap
|
|
|
|
* @author Jason Raymond Bell
|
|
|
|
*/
|
|
|
|
abstract contract BaseParaSwapAdapter is FlashLoanReceiverBase, Ownable {
|
|
|
|
using SafeMath for uint256;
|
|
|
|
using SafeERC20 for IERC20;
|
2021-05-20 15:50:20 +00:00
|
|
|
using SafeERC20 for IERC20Detailed;
|
|
|
|
using SafeERC20 for IERC20WithPermit;
|
2021-03-18 15:44:52 +00:00
|
|
|
|
|
|
|
struct PermitSignature {
|
|
|
|
uint256 amount;
|
|
|
|
uint256 deadline;
|
|
|
|
uint8 v;
|
|
|
|
bytes32 r;
|
|
|
|
bytes32 s;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Max slippage percent allowed
|
|
|
|
uint256 public constant MAX_SLIPPAGE_PERCENT = 3000; // 30%
|
|
|
|
|
|
|
|
IPriceOracleGetter public immutable ORACLE;
|
|
|
|
|
|
|
|
event Swapped(address indexed fromAsset, address indexed toAsset, uint256 fromAmount, uint256 receivedAmount);
|
|
|
|
|
|
|
|
constructor(
|
|
|
|
ILendingPoolAddressesProvider addressesProvider
|
|
|
|
) public FlashLoanReceiverBase(addressesProvider) {
|
|
|
|
ORACLE = IPriceOracleGetter(addressesProvider.getPriceOracle());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @dev Get the price of the asset from the oracle denominated in eth
|
|
|
|
* @param asset address
|
|
|
|
* @return eth price for the asset
|
|
|
|
*/
|
|
|
|
function _getPrice(address asset) internal view returns (uint256) {
|
|
|
|
return ORACLE.getAssetPrice(asset);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @dev Get the decimals of an asset
|
|
|
|
* @return number of decimals of the asset
|
|
|
|
*/
|
2021-05-20 15:50:20 +00:00
|
|
|
function _getDecimals(IERC20Detailed asset) internal view returns (uint8) {
|
|
|
|
uint8 decimals = asset.decimals();
|
2021-05-20 13:14:51 +00:00
|
|
|
// Ensure 10**decimals won't overflow a uint256
|
|
|
|
require(decimals <= 77, 'TOO_MANY_DECIMALS_ON_TOKEN');
|
|
|
|
return decimals;
|
2021-03-18 15:44:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @dev Get the aToken associated to the asset
|
|
|
|
* @return address of the aToken
|
|
|
|
*/
|
|
|
|
function _getReserveData(address asset) internal view returns (DataTypes.ReserveData memory) {
|
|
|
|
return LENDING_POOL.getReserveData(asset);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @dev Pull the ATokens from the user
|
|
|
|
* @param reserve address of the asset
|
|
|
|
* @param reserveAToken address of the aToken of the reserve
|
|
|
|
* @param user address
|
|
|
|
* @param amount of tokens to be transferred to the contract
|
|
|
|
* @param permitSignature struct containing the permit signature
|
|
|
|
*/
|
2021-05-20 12:45:50 +00:00
|
|
|
function _pullATokenAndWithdraw(
|
2021-03-18 15:44:52 +00:00
|
|
|
address reserve,
|
2021-05-20 15:50:20 +00:00
|
|
|
IERC20WithPermit reserveAToken,
|
2021-03-18 15:44:52 +00:00
|
|
|
address user,
|
|
|
|
uint256 amount,
|
|
|
|
PermitSignature memory permitSignature
|
|
|
|
) internal {
|
2021-05-20 13:47:10 +00:00
|
|
|
// If deadline is set to zero, assume there is no signature for permit
|
|
|
|
if (permitSignature.deadline != 0) {
|
2021-05-20 15:50:20 +00:00
|
|
|
reserveAToken.permit(
|
2021-03-18 15:44:52 +00:00
|
|
|
user,
|
|
|
|
address(this),
|
|
|
|
permitSignature.amount,
|
|
|
|
permitSignature.deadline,
|
|
|
|
permitSignature.v,
|
|
|
|
permitSignature.r,
|
|
|
|
permitSignature.s
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// transfer from user to adapter
|
2021-05-20 15:50:20 +00:00
|
|
|
reserveAToken.safeTransferFrom(user, address(this), amount);
|
2021-03-18 15:44:52 +00:00
|
|
|
|
|
|
|
// withdraw reserve
|
2021-05-20 13:38:24 +00:00
|
|
|
require(
|
|
|
|
LENDING_POOL.withdraw(reserve, amount, address(this)) == amount,
|
|
|
|
'UNEXPECTED_AMOUNT_WITHDRAWN'
|
|
|
|
);
|
2021-03-18 15:44:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @dev Emergency rescue for token stucked on this contract, as failsafe mechanism
|
|
|
|
* - Funds should never remain in this contract more time than during transactions
|
|
|
|
* - Only callable by the owner
|
|
|
|
*/
|
|
|
|
function rescueTokens(IERC20 token) external onlyOwner {
|
2021-05-20 12:40:55 +00:00
|
|
|
token.safeTransfer(owner(), token.balanceOf(address(this)));
|
2021-03-18 15:44:52 +00:00
|
|
|
}
|
|
|
|
}
|