2021-03-18 15:44:52 +00:00
|
|
|
// SPDX-License-Identifier: agpl-3.0
|
|
|
|
pragma solidity 0.6.12;
|
|
|
|
pragma experimental ABIEncoderV2;
|
|
|
|
|
|
|
|
import {BaseParaSwapSellAdapter} from './BaseParaSwapSellAdapter.sol';
|
|
|
|
import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol';
|
2021-05-20 22:25:51 +00:00
|
|
|
import {IParaSwapAugustusRegistry} from '../interfaces/IParaSwapAugustusRegistry.sol';
|
2021-05-20 15:50:20 +00:00
|
|
|
import {IERC20Detailed} from '../dependencies/openzeppelin/contracts/IERC20Detailed.sol';
|
|
|
|
import {IERC20WithPermit} from '../interfaces/IERC20WithPermit.sol';
|
|
|
|
import {IParaSwapAugustus} from '../interfaces/IParaSwapAugustus.sol';
|
2021-05-20 16:36:41 +00:00
|
|
|
import {ReentrancyGuard} from '../dependencies/openzeppelin/contracts/ReentrancyGuard.sol';
|
2021-03-18 15:44:52 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @title ParaSwapLiquiditySwapAdapter
|
|
|
|
* @notice Adapter to swap liquidity using ParaSwap.
|
|
|
|
* @author Jason Raymond Bell
|
|
|
|
*/
|
2021-05-20 16:36:41 +00:00
|
|
|
contract ParaSwapLiquiditySwapAdapter is BaseParaSwapSellAdapter, ReentrancyGuard {
|
2021-03-18 15:44:52 +00:00
|
|
|
constructor(
|
2021-05-20 22:25:51 +00:00
|
|
|
ILendingPoolAddressesProvider addressesProvider,
|
|
|
|
IParaSwapAugustusRegistry augustusRegistry
|
|
|
|
) public BaseParaSwapSellAdapter(addressesProvider, augustusRegistry) {
|
2021-05-20 14:41:59 +00:00
|
|
|
// This is only required to initialize BaseParaSwapSellAdapter
|
|
|
|
}
|
2021-03-18 15:44:52 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dev Swaps the received reserve amount from the flash loan into the asset specified in the params.
|
|
|
|
* The received funds from the swap are then deposited into the protocol on behalf of the user.
|
|
|
|
* The user should give this contract allowance to pull the ATokens in order to withdraw the underlying asset and repay the flash loan.
|
|
|
|
* @param assets Address of the underlying asset to be swapped from
|
|
|
|
* @param amounts Amount of the flash loan i.e. maximum amount to swap
|
|
|
|
* @param premiums Fee of the flash loan
|
|
|
|
* @param initiator Account that initiated the flash loan
|
|
|
|
* @param params Additional variadic field to include extra params. Expected parameters:
|
|
|
|
* address assetToSwapTo Address of the underlying asset to be swapped to and deposited
|
|
|
|
* uint256 minAmountToReceive Min amount to be received from the swap
|
|
|
|
* uint256 swapAllBalanceOffset Set to offset of fromAmount in Augustus calldata if wanting to swap all balance, otherwise 0
|
|
|
|
* bytes swapCalldata Calldata for ParaSwap's AugustusSwapper contract
|
|
|
|
* address augustus Address of ParaSwap's AugustusSwapper contract
|
|
|
|
* PermitSignature permitParams Struct containing the permit signatures, set to all zeroes if not used
|
|
|
|
*/
|
|
|
|
function executeOperation(
|
|
|
|
address[] calldata assets,
|
|
|
|
uint256[] calldata amounts,
|
|
|
|
uint256[] calldata premiums,
|
|
|
|
address initiator,
|
|
|
|
bytes calldata params
|
2021-05-20 16:36:41 +00:00
|
|
|
) external override nonReentrant returns (bool) {
|
2021-03-18 15:44:52 +00:00
|
|
|
require(msg.sender == address(LENDING_POOL), 'CALLER_MUST_BE_LENDING_POOL');
|
2021-05-20 14:00:22 +00:00
|
|
|
require(
|
|
|
|
assets.length == 1 && amounts.length == 1 && premiums.length == 1,
|
|
|
|
'FLASHLOAN_MULTIPLE_ASSETS_NOT_SUPPORTED'
|
|
|
|
);
|
2021-03-18 15:44:52 +00:00
|
|
|
|
|
|
|
uint256 flashLoanAmount = amounts[0];
|
|
|
|
uint256 premium = premiums[0];
|
|
|
|
address initiatorLocal = initiator;
|
2021-05-20 15:50:20 +00:00
|
|
|
IERC20Detailed assetToSwapFrom = IERC20Detailed(assets[0]);
|
2021-03-18 15:44:52 +00:00
|
|
|
(
|
2021-05-20 15:50:20 +00:00
|
|
|
IERC20Detailed assetToSwapTo,
|
2021-03-18 15:44:52 +00:00
|
|
|
uint256 minAmountToReceive,
|
|
|
|
uint256 swapAllBalanceOffset,
|
|
|
|
bytes memory swapCalldata,
|
2021-05-20 15:50:20 +00:00
|
|
|
IParaSwapAugustus augustus,
|
2021-03-18 15:44:52 +00:00
|
|
|
PermitSignature memory permitParams
|
2021-05-20 15:50:20 +00:00
|
|
|
) = abi.decode(params, (
|
|
|
|
IERC20Detailed,
|
|
|
|
uint256,
|
|
|
|
uint256,
|
|
|
|
bytes,
|
|
|
|
IParaSwapAugustus,
|
|
|
|
PermitSignature
|
|
|
|
));
|
2021-03-18 15:44:52 +00:00
|
|
|
|
|
|
|
_swapLiquidity(
|
|
|
|
swapAllBalanceOffset,
|
|
|
|
swapCalldata,
|
|
|
|
augustus,
|
|
|
|
permitParams,
|
|
|
|
flashLoanAmount,
|
|
|
|
premium,
|
|
|
|
initiatorLocal,
|
|
|
|
assetToSwapFrom,
|
|
|
|
assetToSwapTo,
|
|
|
|
minAmountToReceive
|
|
|
|
);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @dev Swaps an amount of an asset to another and deposits the new asset amount on behalf of the user without using a flash loan.
|
|
|
|
* This method can be used when the temporary transfer of the collateral asset to this contract does not affect the user position.
|
|
|
|
* The user should give this contract allowance to pull the ATokens in order to withdraw the underlying asset and perform the swap.
|
|
|
|
* @param assetToSwapFrom Address of the underlying asset to be swapped from
|
|
|
|
* @param assetToSwapTo Address of the underlying asset to be swapped to and deposited
|
|
|
|
* @param amountToSwap Amount to be swapped, or maximum amount when swapping all balance
|
|
|
|
* @param minAmountToReceive Minimum amount to be received from the swap
|
|
|
|
* @param swapAllBalanceOffset Set to offset of fromAmount in Augustus calldata if wanting to swap all balance, otherwise 0
|
|
|
|
* @param swapCalldata Calldata for ParaSwap's AugustusSwapper contract
|
|
|
|
* @param augustus Address of ParaSwap's AugustusSwapper contract
|
|
|
|
* @param permitParams Struct containing the permit signatures, set to all zeroes if not used
|
|
|
|
*/
|
|
|
|
function swapAndDeposit(
|
2021-05-20 15:50:20 +00:00
|
|
|
IERC20Detailed assetToSwapFrom,
|
|
|
|
IERC20Detailed assetToSwapTo,
|
2021-03-18 15:44:52 +00:00
|
|
|
uint256 amountToSwap,
|
|
|
|
uint256 minAmountToReceive,
|
|
|
|
uint256 swapAllBalanceOffset,
|
|
|
|
bytes calldata swapCalldata,
|
2021-05-20 15:50:20 +00:00
|
|
|
IParaSwapAugustus augustus,
|
2021-03-18 15:44:52 +00:00
|
|
|
PermitSignature calldata permitParams
|
2021-05-20 16:36:41 +00:00
|
|
|
) external nonReentrant {
|
2021-05-20 15:50:20 +00:00
|
|
|
IERC20WithPermit aToken =
|
|
|
|
IERC20WithPermit(_getReserveData(address(assetToSwapFrom)).aTokenAddress);
|
2021-03-18 15:44:52 +00:00
|
|
|
|
|
|
|
if (swapAllBalanceOffset != 0) {
|
2021-05-20 15:50:20 +00:00
|
|
|
uint256 balance = aToken.balanceOf(msg.sender);
|
2021-03-18 15:44:52 +00:00
|
|
|
require(balance <= amountToSwap, 'INSUFFICIENT_AMOUNT_TO_SWAP');
|
|
|
|
amountToSwap = balance;
|
|
|
|
}
|
|
|
|
|
2021-05-20 12:45:50 +00:00
|
|
|
_pullATokenAndWithdraw(
|
2021-05-20 15:50:20 +00:00
|
|
|
address(assetToSwapFrom),
|
2021-03-18 15:44:52 +00:00
|
|
|
aToken,
|
|
|
|
msg.sender,
|
|
|
|
amountToSwap,
|
|
|
|
permitParams
|
|
|
|
);
|
|
|
|
|
|
|
|
uint256 amountReceived = _sellOnParaSwap(
|
|
|
|
swapAllBalanceOffset,
|
|
|
|
swapCalldata,
|
|
|
|
augustus,
|
|
|
|
assetToSwapFrom,
|
|
|
|
assetToSwapTo,
|
|
|
|
amountToSwap,
|
|
|
|
minAmountToReceive
|
|
|
|
);
|
|
|
|
|
2021-05-20 15:50:20 +00:00
|
|
|
assetToSwapTo.safeApprove(address(LENDING_POOL), 0);
|
|
|
|
assetToSwapTo.safeApprove(address(LENDING_POOL), amountReceived);
|
|
|
|
LENDING_POOL.deposit(address(assetToSwapTo), amountReceived, msg.sender, 0);
|
2021-03-18 15:44:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @dev Swaps an amount of an asset to another and deposits the funds on behalf of the initiator.
|
|
|
|
* @param swapAllBalanceOffset Set to offset of fromAmount in Augustus calldata if wanting to swap all balance, otherwise 0
|
|
|
|
* @param swapCalldata Calldata for ParaSwap's AugustusSwapper contract
|
|
|
|
* @param augustus Address of ParaSwap's AugustusSwapper contract
|
|
|
|
* @param permitParams Struct containing the permit signatures, set to all zeroes if not used
|
|
|
|
* @param flashLoanAmount Amount of the flash loan i.e. maximum amount to swap
|
|
|
|
* @param premium Fee of the flash loan
|
|
|
|
* @param initiator Account that initiated the flash loan
|
|
|
|
* @param assetToSwapFrom Address of the underyling asset to be swapped from
|
|
|
|
* @param assetToSwapTo Address of the underlying asset to be swapped to and deposited
|
|
|
|
* @param minAmountToReceive Min amount to be received from the swap
|
|
|
|
*/
|
|
|
|
function _swapLiquidity (
|
|
|
|
uint256 swapAllBalanceOffset,
|
|
|
|
bytes memory swapCalldata,
|
2021-05-20 15:50:20 +00:00
|
|
|
IParaSwapAugustus augustus,
|
2021-03-18 15:44:52 +00:00
|
|
|
PermitSignature memory permitParams,
|
|
|
|
uint256 flashLoanAmount,
|
|
|
|
uint256 premium,
|
|
|
|
address initiator,
|
2021-05-20 15:50:20 +00:00
|
|
|
IERC20Detailed assetToSwapFrom,
|
|
|
|
IERC20Detailed assetToSwapTo,
|
2021-03-18 15:44:52 +00:00
|
|
|
uint256 minAmountToReceive
|
|
|
|
) internal {
|
2021-05-20 15:50:20 +00:00
|
|
|
IERC20WithPermit aToken =
|
|
|
|
IERC20WithPermit(_getReserveData(address(assetToSwapFrom)).aTokenAddress);
|
2021-03-18 15:44:52 +00:00
|
|
|
uint256 amountToSwap = flashLoanAmount;
|
|
|
|
|
2021-05-20 15:50:20 +00:00
|
|
|
uint256 balance = aToken.balanceOf(initiator);
|
2021-03-18 15:44:52 +00:00
|
|
|
if (swapAllBalanceOffset != 0) {
|
|
|
|
uint256 balanceToSwap = balance.sub(premium);
|
|
|
|
require(balanceToSwap <= amountToSwap, 'INSUFFICIENT_AMOUNT_TO_SWAP');
|
|
|
|
amountToSwap = balanceToSwap;
|
|
|
|
} else {
|
|
|
|
require(balance >= amountToSwap.add(premium), 'INSUFFICIENT_ATOKEN_BALANCE');
|
|
|
|
}
|
|
|
|
|
|
|
|
uint256 amountReceived = _sellOnParaSwap(
|
|
|
|
swapAllBalanceOffset,
|
|
|
|
swapCalldata,
|
|
|
|
augustus,
|
|
|
|
assetToSwapFrom,
|
|
|
|
assetToSwapTo,
|
|
|
|
amountToSwap,
|
|
|
|
minAmountToReceive
|
|
|
|
);
|
|
|
|
|
2021-05-20 15:50:20 +00:00
|
|
|
assetToSwapTo.safeApprove(address(LENDING_POOL), 0);
|
|
|
|
assetToSwapTo.safeApprove(address(LENDING_POOL), amountReceived);
|
|
|
|
LENDING_POOL.deposit(address(assetToSwapTo), amountReceived, initiator, 0);
|
2021-03-18 15:44:52 +00:00
|
|
|
|
2021-05-20 12:45:50 +00:00
|
|
|
_pullATokenAndWithdraw(
|
2021-05-20 15:50:20 +00:00
|
|
|
address(assetToSwapFrom),
|
2021-03-18 15:44:52 +00:00
|
|
|
aToken,
|
|
|
|
initiator,
|
|
|
|
amountToSwap.add(premium),
|
|
|
|
permitParams
|
|
|
|
);
|
|
|
|
|
|
|
|
// Repay flash loan
|
2021-05-20 15:50:20 +00:00
|
|
|
assetToSwapFrom.safeApprove(address(LENDING_POOL), 0);
|
|
|
|
assetToSwapFrom.safeApprove(address(LENDING_POOL), flashLoanAmount.add(premium));
|
2021-03-18 15:44:52 +00:00
|
|
|
}
|
|
|
|
}
|