aave-protocol-v2/contracts/adapters/UniswapLiquiditySwapAdapter.sol

175 lines
6.9 KiB
Solidity
Raw Normal View History

// SPDX-License-Identifier: agpl-3.0
pragma solidity ^0.6.8;
pragma experimental ABIEncoderV2;
import {BaseUniswapAdapter} from './BaseUniswapAdapter.sol';
import {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol';
import {IUniswapV2Router02} from '../interfaces/IUniswapV2Router02.sol';
import {IFlashLoanReceiver} from '../flashloan/interfaces/IFlashLoanReceiver.sol';
import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
/**
* @title UniswapLiquiditySwapAdapter
* @notice Uniswap V2 Adapter to swap liquidity using a flash loan.
* @author Aave
**/
contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
2020-11-02 20:33:00 +00:00
struct SwapParams {
address[] assetToSwapToList;
uint256[] minAmountsToReceive;
2020-11-02 20:33:00 +00:00
PermitParams permitParams;
}
constructor(
2020-10-30 19:59:25 +00:00
ILendingPoolAddressesProvider addressesProvider,
IUniswapV2Router02 uniswapRouter
)
public
2020-10-30 19:59:25 +00:00
BaseUniswapAdapter(addressesProvider, uniswapRouter)
{}
/**
* @dev Swaps the received reserve amount from the flashloan 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 to be swapped
* @param amounts Amount of the reserve to be swapped
* @param premiums Fee of the flash loan
2020-10-30 19:59:25 +00:00
* @param initiator Address of the user
* @param params Additional variadic field to include extra params. Expected parameters:
2020-10-30 19:59:25 +00:00
* address[] assetToSwapToList List of the addresses of the reserve to be swapped to and deposited
* uint256[] minAmountsToReceive List of min amounts to be received from the swap
2020-11-02 20:33:00 +00:00
* uint256[] deadline List of deadlines for the permit signature
* uint8[] v List of v param for the permit signature
* bytes32[] r List of r param for the permit signature
* bytes32[] s List of s param for the permit signature
*/
function executeOperation(
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata premiums,
2020-10-30 19:59:25 +00:00
address initiator,
bytes calldata params
) external override returns (bool) {
2020-10-30 19:59:25 +00:00
require(msg.sender == address(POOL), "CALLER_MUST_BE_LENDING_POOL");
2020-11-02 20:33:00 +00:00
SwapParams memory decodedParams = _decodeParams(params);
require(
assets.length == decodedParams.assetToSwapToList.length
&& assets.length == decodedParams.minAmountsToReceive.length
2020-11-02 20:33:00 +00:00
&& assets.length == decodedParams.permitParams.deadline.length
&& assets.length == decodedParams.permitParams.v.length
&& assets.length == decodedParams.permitParams.r.length
&& assets.length == decodedParams.permitParams.s.length,
'INCONSISTENT_PARAMS'
);
2020-10-30 19:59:25 +00:00
for (uint256 i = 0; i < assets.length; i++) {
2020-11-02 20:33:00 +00:00
uint256 receivedAmount = swapExactTokensForTokens(
assets[i],
decodedParams.assetToSwapToList[i],
amounts[i],
decodedParams.minAmountsToReceive[i]
2020-11-02 20:33:00 +00:00
);
2020-10-30 19:59:25 +00:00
// Deposit new reserve
2020-11-02 20:33:00 +00:00
IERC20(decodedParams.assetToSwapToList[i]).approve(address(POOL), receivedAmount);
POOL.deposit(decodedParams.assetToSwapToList[i], receivedAmount, initiator, 0);
2020-10-30 19:59:25 +00:00
uint256 flashLoanDebt = amounts[i].add(premiums[i]);
2020-11-02 20:33:00 +00:00
pullATokenAndRepayFlashLoan(
assets[i],
initiator,
flashLoanDebt,
PermitSignature(
decodedParams.permitParams.deadline[i],
decodedParams.permitParams.v[i],
decodedParams.permitParams.r[i],
decodedParams.permitParams.s[i]
)
);
2020-10-30 19:59:25 +00:00
}
return true;
}
/**
* @dev Swaps an `amountToSwap` of an asset to another and deposits the funds on behalf of the user without using a flashloan.
* This method can be used when the user has no debts.
* The user should give this contract allowance to pull the ATokens in order to withdraw the underlying asset and
* perform the swap.
2020-10-30 19:59:25 +00:00
* @param assetToSwapFromList List of addresses of the underlying asset to be swap from
* @param assetToSwapToList List of addresses of the underlying asset to be swap to and deposited
* @param amountToSwapList List of amounts to be swapped
* @param minAmountsToReceive List of min amounts to be received from the swap
* @param permitParams List of struct containing the permit signatures
2020-11-02 20:33:00 +00:00
* uint256[] deadline List of deadlines for the permit signature
* uint8[] v List of v param for the permit signature
* bytes32[] r List of r param for the permit signature
* bytes32[] s List of s param for the permit signature
*/
function swapAndDeposit(
2020-10-30 19:59:25 +00:00
address[] calldata assetToSwapFromList,
address[] calldata assetToSwapToList,
uint256[] calldata amountToSwapList,
uint256[] calldata minAmountsToReceive,
2020-11-02 20:33:00 +00:00
PermitSignature[] calldata permitParams
) external {
2020-10-30 19:59:25 +00:00
require(
2020-11-02 20:33:00 +00:00
assetToSwapFromList.length == assetToSwapToList.length
&& assetToSwapFromList.length == amountToSwapList.length
&& assetToSwapFromList.length == minAmountsToReceive.length
2020-11-02 20:33:00 +00:00
&& assetToSwapFromList.length == permitParams.length,
2020-10-30 19:59:25 +00:00
'INCONSISTENT_PARAMS'
);
for (uint256 i = 0; i < assetToSwapFromList.length; i++) {
2020-11-02 20:33:00 +00:00
pullAToken(
assetToSwapFromList[i],
msg.sender,
amountToSwapList[i],
permitParams[i]
);
2020-10-30 19:59:25 +00:00
uint256 receivedAmount = swapExactTokensForTokens(
assetToSwapFromList[i],
assetToSwapToList[i],
amountToSwapList[i],
minAmountsToReceive[i]
2020-10-30 19:59:25 +00:00
);
2020-10-30 19:59:25 +00:00
// Deposit new reserve
IERC20(assetToSwapToList[i]).approve(address(POOL), receivedAmount);
POOL.deposit(assetToSwapToList[i], receivedAmount, msg.sender, 0);
}
}
2020-11-02 20:33:00 +00:00
/**
* @dev Decodes debt information encoded in flashloan params
* @param params Additional variadic field to include extra params. Expected parameters:
* address[] assetToSwapToList List of the addresses of the reserve to be swapped to and deposited
* uint256[] minAmountsToReceive List of min amounts to be received from the swap
2020-11-02 20:33:00 +00:00
* uint256[] deadline List of deadlines for the permit signature
* uint256[] deadline List of deadlines for the permit signature
* uint8[] v List of v param for the permit signature
* bytes32[] r List of r param for the permit signature
* bytes32[] s List of s param for the permit signature
* @return SwapParams struct containing decoded params
*/
function _decodeParams(bytes memory params) internal returns (SwapParams memory) {
(
address[] memory assetToSwapToList,
uint256[] memory minAmountsToReceive,
2020-11-02 20:33:00 +00:00
uint256[] memory deadline,
uint8[] memory v,
bytes32[] memory r,
bytes32[] memory s
) = abi.decode(params, (address[], uint256[], uint256[], uint8[], bytes32[], bytes32[]));
2020-11-02 20:33:00 +00:00
return SwapParams(assetToSwapToList, minAmountsToReceive, PermitParams(deadline, v, r, s));
2020-11-02 20:33:00 +00:00
}
}