mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
Apply feedback fixes
This commit is contained in:
parent
8278d2e6d8
commit
0eddff4933
|
@ -5,15 +5,14 @@ pragma experimental ABIEncoderV2;
|
|||
import {PercentageMath} from '../libraries/math/PercentageMath.sol';
|
||||
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 {ILendingPoolAddressesProvider} from '../interfaces/ILendingPoolAddressesProvider.sol';
|
||||
import {ILendingPool} from '../interfaces/ILendingPool.sol';
|
||||
import {ReserveLogic} from '../libraries/logic/ReserveLogic.sol';
|
||||
import {ReserveConfiguration} from '../libraries/configuration/ReserveConfiguration.sol';
|
||||
import {IUniswapV2Router02} from '../interfaces/IUniswapV2Router02.sol';
|
||||
import {IPriceOracleGetter} from '../interfaces/IPriceOracleGetter.sol';
|
||||
|
||||
|
||||
/**
|
||||
* @title BaseUniswapAdapter
|
||||
* @notice Implements the logic for performing assets swaps in Uniswap V2
|
||||
|
@ -23,23 +22,24 @@ contract BaseUniswapAdapter {
|
|||
using SafeMath for uint256;
|
||||
using PercentageMath for uint256;
|
||||
using SafeERC20 for IERC20;
|
||||
using ReserveConfiguration for ReserveConfiguration.Map;
|
||||
|
||||
enum LeftoverAction {DEPOSIT, TRANSFER}
|
||||
|
||||
// Max slippage percent allow by param
|
||||
uint256 public constant MAX_SLIPPAGE_PERCENT = 3000; // 30%
|
||||
// Min slippage percent allow by param
|
||||
uint256 public constant MIN_SLIPPAGE_PERCENT = 10; // 0,1%
|
||||
|
||||
ILendingPoolAddressesProvider public immutable addressesProvider;
|
||||
IUniswapV2Router02 public immutable uniswapRouter;
|
||||
ILendingPool public immutable pool;
|
||||
ILendingPool public immutable POOL;
|
||||
IPriceOracleGetter public immutable ORACLE;
|
||||
IUniswapV2Router02 public immutable UNISWAP_ROUTER;
|
||||
|
||||
event Swapped(address fromAsset, address toAsset, uint256 fromAmount, uint256 receivedAmount);
|
||||
|
||||
constructor(ILendingPoolAddressesProvider _addressesProvider, IUniswapV2Router02 _uniswapRouter) public {
|
||||
addressesProvider = _addressesProvider;
|
||||
pool = ILendingPool(_addressesProvider.getLendingPool());
|
||||
uniswapRouter = _uniswapRouter;
|
||||
constructor(ILendingPoolAddressesProvider addressesProvider, IUniswapV2Router02 uniswapRouter) public {
|
||||
POOL = ILendingPool(addressesProvider.getLendingPool());
|
||||
ORACLE = IPriceOracleGetter(addressesProvider.getPriceOracle());
|
||||
UNISWAP_ROUTER = uniswapRouter;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,7 +58,7 @@ contract BaseUniswapAdapter {
|
|||
path[0] = reserveIn;
|
||||
path[1] = reserveOut;
|
||||
|
||||
uint256[] memory amounts = uniswapRouter.getAmountsOut(amountIn, path);
|
||||
uint256[] memory amounts = UNISWAP_ROUTER.getAmountsOut(amountIn, path);
|
||||
|
||||
return amounts[1];
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ contract BaseUniswapAdapter {
|
|||
path[0] = reserveIn;
|
||||
path[1] = reserveOut;
|
||||
|
||||
uint256[] memory amounts = uniswapRouter.getAmountsIn(amountOut, path);
|
||||
uint256[] memory amounts = UNISWAP_ROUTER.getAmountsIn(amountOut, path);
|
||||
|
||||
return amounts[0];
|
||||
}
|
||||
|
@ -101,24 +101,23 @@ contract BaseUniswapAdapter {
|
|||
internal
|
||||
returns (uint256)
|
||||
{
|
||||
uint256 fromAssetDecimals = getDecimals(assetToSwapFrom);
|
||||
uint256 toAssetDecimals = getDecimals(assetToSwapTo);
|
||||
uint256 fromAssetDecimals = _getDecimals(assetToSwapFrom);
|
||||
uint256 toAssetDecimals = _getDecimals(assetToSwapTo);
|
||||
|
||||
(uint256 fromAssetPrice, uint256 toAssetPrice) = getPrices(assetToSwapFrom, assetToSwapTo);
|
||||
uint256 fromAssetPrice = _getPrice(assetToSwapFrom);
|
||||
uint256 toAssetPrice = _getPrice(assetToSwapTo);
|
||||
|
||||
uint256 amountOutMin = amountToSwap
|
||||
.mul(fromAssetPrice.mul(10**toAssetDecimals))
|
||||
.div(toAssetPrice.mul(10**fromAssetDecimals))
|
||||
.percentMul(PercentageMath.PERCENTAGE_FACTOR.sub(slippage));
|
||||
|
||||
IERC20(assetToSwapFrom).approve(address(uniswapRouter), amountToSwap);
|
||||
IERC20(assetToSwapFrom).approve(address(UNISWAP_ROUTER), amountToSwap);
|
||||
|
||||
address[] memory path = new address[](2);
|
||||
path[0] = assetToSwapFrom;
|
||||
path[1] = assetToSwapTo;
|
||||
uint256[] memory amounts = uniswapRouter.swapExactTokensForTokens(amountToSwap, amountOutMin, path, address(this), block.timestamp);
|
||||
|
||||
require(amounts[1] >= amountOutMin, 'INSUFFICIENT_OUTPUT_AMOUNT');
|
||||
uint256[] memory amounts = UNISWAP_ROUTER.swapExactTokensForTokens(amountToSwap, amountOutMin, path, address(this), block.timestamp);
|
||||
|
||||
emit Swapped(assetToSwapFrom, assetToSwapTo, amounts[0], amounts[1]);
|
||||
|
||||
|
@ -143,10 +142,11 @@ contract BaseUniswapAdapter {
|
|||
internal
|
||||
returns (uint256)
|
||||
{
|
||||
uint256 fromAssetDecimals = getDecimals(assetToSwapFrom);
|
||||
uint256 toAssetDecimals = getDecimals(assetToSwapTo);
|
||||
uint256 fromAssetDecimals = _getDecimals(assetToSwapFrom);
|
||||
uint256 toAssetDecimals = _getDecimals(assetToSwapTo);
|
||||
|
||||
(uint256 fromAssetPrice, uint256 toAssetPrice) = getPrices(assetToSwapFrom, assetToSwapTo);
|
||||
uint256 fromAssetPrice = _getPrice(assetToSwapFrom);
|
||||
uint256 toAssetPrice = _getPrice(assetToSwapTo);
|
||||
|
||||
uint256 expectedMaxAmountToSwap = amountToReceive
|
||||
.mul(toAssetPrice.mul(10**fromAssetDecimals))
|
||||
|
@ -155,14 +155,12 @@ contract BaseUniswapAdapter {
|
|||
|
||||
require(maxAmountToSwap < expectedMaxAmountToSwap, 'maxAmountToSwap exceed max slippage');
|
||||
|
||||
IERC20(assetToSwapFrom).approve(address(uniswapRouter), maxAmountToSwap);
|
||||
IERC20(assetToSwapFrom).approve(address(UNISWAP_ROUTER), maxAmountToSwap);
|
||||
|
||||
address[] memory path = new address[](2);
|
||||
path[0] = assetToSwapFrom;
|
||||
path[1] = assetToSwapTo;
|
||||
uint256[] memory amounts = uniswapRouter.swapTokensForExactTokens(amountToReceive, maxAmountToSwap, path, address(this), block.timestamp);
|
||||
|
||||
require(amounts[1] >= amountToReceive, 'INSUFFICIENT_OUTPUT_AMOUNT');
|
||||
uint256[] memory amounts = UNISWAP_ROUTER.swapTokensForExactTokens(amountToReceive, maxAmountToSwap, path, address(this), block.timestamp);
|
||||
|
||||
emit Swapped(assetToSwapFrom, assetToSwapTo, amounts[0], amounts[1]);
|
||||
|
||||
|
@ -170,34 +168,20 @@ contract BaseUniswapAdapter {
|
|||
}
|
||||
|
||||
/**
|
||||
* @dev Get assets prices from the oracle denominated in eth
|
||||
* @param assetToSwapFrom first asset
|
||||
* @param assetToSwapTo second asset
|
||||
* @return fromAssetPrice eth price for the first asset
|
||||
* @return toAssetPrice eth price for the second asset
|
||||
* @dev Get the price of the asset from the oracle denominated in eth
|
||||
* @param asset address
|
||||
* @return eth price for the asset
|
||||
*/
|
||||
function getPrices(
|
||||
address assetToSwapFrom,
|
||||
address assetToSwapTo
|
||||
)
|
||||
internal
|
||||
view
|
||||
returns (uint256 fromAssetPrice, uint256 toAssetPrice)
|
||||
{
|
||||
IPriceOracleGetter oracle = IPriceOracleGetter(addressesProvider.getPriceOracle());
|
||||
fromAssetPrice = oracle.getAssetPrice(assetToSwapFrom);
|
||||
toAssetPrice = oracle.getAssetPrice(assetToSwapTo);
|
||||
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
|
||||
*/
|
||||
function getDecimals(address asset) internal view returns (uint256) {
|
||||
ReserveConfiguration.Map memory configuration = pool.getConfiguration(asset);
|
||||
(, , , uint256 decimals, ) = configuration.getParamsMemory();
|
||||
|
||||
return decimals;
|
||||
function _getDecimals(address asset) internal view returns (uint256) {
|
||||
return IERC20Detailed(asset).decimals();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -205,7 +189,7 @@ contract BaseUniswapAdapter {
|
|||
* @return address of the aToken
|
||||
*/
|
||||
function getAToken(address asset) internal view returns (address) {
|
||||
ReserveLogic.ReserveData memory reserve = pool.getReserveData(asset);
|
||||
ReserveLogic.ReserveData memory reserve = POOL.getReserveData(asset);
|
||||
return reserve.aTokenAddress;
|
||||
}
|
||||
|
||||
|
@ -213,19 +197,19 @@ contract BaseUniswapAdapter {
|
|||
* @dev Take action with the swap left overs as configured in the parameters
|
||||
* @param asset address of the asset
|
||||
* @param reservedAmount Amount reserved to be used by the contract to repay the flash loan
|
||||
* @param leftOverAction Flag indicating what to do with the left over balance from the swap:
|
||||
* @param leftOverAction enum indicating what to do with the left over balance from the swap:
|
||||
* (0) Deposit back
|
||||
* (1) Direct transfer to user
|
||||
* @param user address
|
||||
*/
|
||||
function sendLeftOver(address asset, uint256 reservedAmount, uint256 leftOverAction, address user) internal {
|
||||
function sendLeftovers(address asset, uint256 reservedAmount, LeftoverAction leftOverAction, address user) internal {
|
||||
uint256 balance = IERC20(asset).balanceOf(address(this));
|
||||
uint256 assetLeftOver = balance.sub(reservedAmount);
|
||||
|
||||
if (assetLeftOver > 0) {
|
||||
if (leftOverAction == 0) {
|
||||
IERC20(asset).approve(address(pool), balance);
|
||||
pool.deposit(asset, assetLeftOver, user, 0);
|
||||
if (leftOverAction == LeftoverAction.DEPOSIT) {
|
||||
IERC20(asset).approve(address(POOL), balance);
|
||||
POOL.deposit(asset, assetLeftOver, user, 0);
|
||||
} else {
|
||||
IERC20(asset).transfer(user, assetLeftOver);
|
||||
}
|
||||
|
@ -249,7 +233,7 @@ contract BaseUniswapAdapter {
|
|||
IERC20(reserveAToken).safeTransferFrom(user, address(this), amount);
|
||||
|
||||
// withdraw reserve
|
||||
pool.withdraw(reserve, amount);
|
||||
POOL.withdraw(reserve, amount, address(this));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -266,6 +250,6 @@ contract BaseUniswapAdapter {
|
|||
pullAToken(reserve, user, flashLoanDebt);
|
||||
|
||||
// Repay flashloan
|
||||
IERC20(reserve).approve(address(pool), flashLoanDebt);
|
||||
IERC20(reserve).approve(address(POOL), flashLoanDebt);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,11 +16,11 @@ import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
|
|||
contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
||||
|
||||
constructor(
|
||||
ILendingPoolAddressesProvider _addressesProvider,
|
||||
IUniswapV2Router02 _uniswapRouter
|
||||
ILendingPoolAddressesProvider addressesProvider,
|
||||
IUniswapV2Router02 uniswapRouter
|
||||
)
|
||||
public
|
||||
BaseUniswapAdapter(_addressesProvider, _uniswapRouter)
|
||||
BaseUniswapAdapter(addressesProvider, uniswapRouter)
|
||||
{}
|
||||
|
||||
/**
|
||||
|
@ -31,32 +31,34 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
* @param assets Address to be swapped
|
||||
* @param amounts Amount of the reserve to be swapped
|
||||
* @param premiums Fee of the flash loan
|
||||
* @param initiator Address of the user
|
||||
* @param params Additional variadic field to include extra params. Expected parameters:
|
||||
* address assetToSwapTo Address of the reserve to be swapped to and deposited
|
||||
* address user The address of the user
|
||||
* address[] assetToSwapToList List of the addresses of the reserve to be swapped to and deposited
|
||||
* uint256 slippage The max slippage percentage allowed for the swap
|
||||
*/
|
||||
function executeOperation(
|
||||
address[] calldata assets,
|
||||
uint256[] calldata amounts,
|
||||
uint256[] calldata premiums,
|
||||
address initiator,
|
||||
bytes calldata params
|
||||
) external override returns (bool) {
|
||||
(
|
||||
address assetToSwapTo,
|
||||
address user,
|
||||
uint256 slippage
|
||||
) = abi.decode(params, (address, address, uint256));
|
||||
require(msg.sender == address(POOL), "CALLER_MUST_BE_LENDING_POOL");
|
||||
|
||||
(address[] memory assetToSwapToList, uint256 slippage) = abi.decode(params, (address[], uint256));
|
||||
require(slippage < MAX_SLIPPAGE_PERCENT && slippage >= MIN_SLIPPAGE_PERCENT, 'SLIPPAGE_OUT_OF_RANGE');
|
||||
require(assetToSwapToList.length == assets.length, 'INCONSISTENT_PARAMS');
|
||||
|
||||
uint256 receivedAmount = swapExactTokensForTokens(assets[0], assetToSwapTo, amounts[0], slippage);
|
||||
for (uint256 i = 0; i < assets.length; i++) {
|
||||
uint256 receivedAmount = swapExactTokensForTokens(assets[i], assetToSwapToList[i], amounts[i], slippage);
|
||||
|
||||
// Deposit new reserve
|
||||
IERC20(assetToSwapTo).approve(address(pool), receivedAmount);
|
||||
pool.deposit(assetToSwapTo, receivedAmount, user, 0);
|
||||
// Deposit new reserve
|
||||
IERC20(assetToSwapToList[i]).approve(address(POOL), receivedAmount);
|
||||
POOL.deposit(assetToSwapToList[i], receivedAmount, initiator, 0);
|
||||
|
||||
uint256 flashLoanDebt = amounts[0].add(premiums[0]);
|
||||
pullATokenAndRepayFlashLoan(assets[0], user, flashLoanDebt);
|
||||
uint256 flashLoanDebt = amounts[i].add(premiums[i]);
|
||||
pullATokenAndRepayFlashLoan(assets[i], initiator, flashLoanDebt);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -66,25 +68,35 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
* 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.
|
||||
* @param assetToSwapFrom Address of the underlying asset to be swap from
|
||||
* @param assetToSwapTo Address of the underlying asset to be swap to and deposited
|
||||
* @param amountToSwap How much `assetToSwapFrom` needs to be swapped
|
||||
* @param user Address that will be pulling the swapped funds
|
||||
* @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 slippage The max slippage percentage allowed for the swap
|
||||
*/
|
||||
function swapAndDeposit(
|
||||
address assetToSwapFrom,
|
||||
address assetToSwapTo,
|
||||
uint256 amountToSwap,
|
||||
address user,
|
||||
address[] calldata assetToSwapFromList,
|
||||
address[] calldata assetToSwapToList,
|
||||
uint256[] calldata amountToSwapList,
|
||||
uint256 slippage
|
||||
) external {
|
||||
pullAToken(assetToSwapFrom, user, amountToSwap);
|
||||
require(
|
||||
assetToSwapFromList.length == assetToSwapToList.length && assetToSwapFromList.length == amountToSwapList.length,
|
||||
'INCONSISTENT_PARAMS'
|
||||
);
|
||||
|
||||
uint256 receivedAmount = swapExactTokensForTokens(assetToSwapFrom, assetToSwapTo, amountToSwap, slippage);
|
||||
for (uint256 i = 0; i < assetToSwapFromList.length; i++) {
|
||||
pullAToken(assetToSwapFromList[i], msg.sender, amountToSwapList[i]);
|
||||
|
||||
// Deposit new reserve
|
||||
IERC20(assetToSwapTo).approve(address(pool), receivedAmount);
|
||||
pool.deposit(assetToSwapTo, receivedAmount, user, 0);
|
||||
uint256 receivedAmount = swapExactTokensForTokens(
|
||||
assetToSwapFromList[i],
|
||||
assetToSwapToList[i],
|
||||
amountToSwapList[i],
|
||||
slippage
|
||||
);
|
||||
|
||||
// Deposit new reserve
|
||||
IERC20(assetToSwapToList[i]).approve(address(POOL), receivedAmount);
|
||||
POOL.deposit(assetToSwapToList[i], receivedAmount, msg.sender, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,12 +15,19 @@ import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
|
|||
**/
|
||||
contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
||||
|
||||
struct RepayParams {
|
||||
address[] assetToSwapToList;
|
||||
LeftoverAction leftOverAction;
|
||||
uint256[] repayAmounts;
|
||||
uint256[] rateModes;
|
||||
}
|
||||
|
||||
constructor(
|
||||
ILendingPoolAddressesProvider _addressesProvider,
|
||||
IUniswapV2Router02 _uniswapRouter
|
||||
ILendingPoolAddressesProvider addressesProvider,
|
||||
IUniswapV2Router02 uniswapRouter
|
||||
)
|
||||
public
|
||||
BaseUniswapAdapter(_addressesProvider, _uniswapRouter)
|
||||
BaseUniswapAdapter(addressesProvider, uniswapRouter)
|
||||
{}
|
||||
|
||||
/**
|
||||
|
@ -31,41 +38,102 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
* @param assets Address to be swapped
|
||||
* @param amounts Amount of the reserve to be swapped
|
||||
* @param premiums Fee of the flash loan
|
||||
* @param initiator Address of the user
|
||||
* @param params Additional variadic field to include extra params. Expected parameters:
|
||||
* address assetToSwapTo Address of the reserve to be swapped to and deposited
|
||||
* address user The address of the user
|
||||
* address[] assetToSwapToList List of the addresses of the reserve to be swapped to and repay
|
||||
* uint256 leftOverAction Flag indicating what to do with the left over balance from the swap:
|
||||
* (0) Deposit back
|
||||
* (1) Direct transfer to user
|
||||
* uint256 repayAmount Amount of debt to be repaid
|
||||
* uint256 rateMode The rate modes of the debt to be repaid
|
||||
* uint256[] repayAmounts List of amounts of debt to be repaid
|
||||
* uint256[] rateModes List of the rate modes of the debt to be repaid
|
||||
*/
|
||||
function executeOperation(
|
||||
address[] calldata assets,
|
||||
uint256[] calldata amounts,
|
||||
uint256[] calldata premiums,
|
||||
address initiator,
|
||||
bytes calldata params
|
||||
) external override returns (bool) {
|
||||
(
|
||||
address assetToSwapTo,
|
||||
address user,
|
||||
uint256 leftOverAction,
|
||||
uint256 repayAmount,
|
||||
uint256 rateMode
|
||||
) = abi.decode(params, (address, address, uint256, uint256, uint256));
|
||||
require(msg.sender == address(POOL), "CALLER_MUST_BE_LENDING_POOL");
|
||||
|
||||
swapTokensForExactTokens(assets[0], assetToSwapTo, amounts[0], repayAmount);
|
||||
RepayParams memory decodedParams = _decodeParams(params);
|
||||
|
||||
// Repay debt
|
||||
IERC20(assetToSwapTo).approve(address(pool), repayAmount);
|
||||
pool.repay(assetToSwapTo, repayAmount, rateMode, user);
|
||||
require(
|
||||
assets.length == decodedParams.assetToSwapToList.length
|
||||
&& assets.length == decodedParams.repayAmounts.length
|
||||
&& assets.length == decodedParams.rateModes.length,
|
||||
'INCONSISTENT_PARAMS');
|
||||
|
||||
uint256 flashLoanDebt = amounts[0].add(premiums[0]);
|
||||
pullATokenAndRepayFlashLoan(assets[0], user, flashLoanDebt);
|
||||
|
||||
// Take care of reserve leftover from the swap
|
||||
sendLeftOver(assets[0], flashLoanDebt, leftOverAction, user);
|
||||
for (uint256 i = 0; i < assets.length; i++) {
|
||||
_swapAndRepay(
|
||||
assets[i],
|
||||
decodedParams.assetToSwapToList[i],
|
||||
amounts[i],
|
||||
decodedParams.repayAmounts[i],
|
||||
decodedParams.rateModes[i],
|
||||
initiator,
|
||||
decodedParams.leftOverAction,
|
||||
premiums[i]
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Perform the swap, the repay of the debt and send back the left overs
|
||||
*
|
||||
* @param assetFrom Address of token to be swapped
|
||||
* @param assetTo Address of token to be received
|
||||
* @param amount Amount of the reserve to be swapped
|
||||
* @param repayAmount Amount of the debt to be repaid
|
||||
* @param rateMode Rate mode of the debt to be repaid
|
||||
* @param initiator Address of the user
|
||||
* @param leftOverAction enum indicating what to do with the left over balance from the swap
|
||||
* @param premium Fee of the flash loan
|
||||
*/
|
||||
function _swapAndRepay(
|
||||
address assetFrom,
|
||||
address assetTo,
|
||||
uint256 amount,
|
||||
uint256 repayAmount,
|
||||
uint256 rateMode,
|
||||
address initiator,
|
||||
LeftoverAction leftOverAction,
|
||||
uint256 premium
|
||||
) internal {
|
||||
swapTokensForExactTokens(assetFrom, assetTo, amount, repayAmount);
|
||||
|
||||
// Repay debt
|
||||
IERC20(assetTo).approve(address(POOL), repayAmount);
|
||||
POOL.repay(assetTo, repayAmount, rateMode, initiator);
|
||||
|
||||
uint256 flashLoanDebt = amount.add(premium);
|
||||
pullATokenAndRepayFlashLoan(assetFrom, initiator, flashLoanDebt);
|
||||
|
||||
// Take care of reserve leftover from the swap
|
||||
sendLeftovers(assetFrom, flashLoanDebt, leftOverAction, initiator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 repay
|
||||
* uint256 leftOverAction Flag indicating what to do with the left over balance from the swap:
|
||||
* (0) Deposit back
|
||||
* (1) Direct transfer to user
|
||||
* uint256[] repayAmounts List of amounts of debt to be repaid
|
||||
* uint256[] rateModes List of the rate modes of the debt to be repaid
|
||||
* @return RepayParams struct containing decoded params
|
||||
*/
|
||||
function _decodeParams(bytes memory params) internal returns (RepayParams memory) {
|
||||
(
|
||||
address[] memory assetToSwapToList,
|
||||
LeftoverAction leftOverAction,
|
||||
uint256[] memory repayAmounts,
|
||||
uint256[] memory rateModes
|
||||
) = abi.decode(params, (address[], LeftoverAction, uint256[], uint256[]));
|
||||
|
||||
return RepayParams(assetToSwapToList, leftOverAction, repayAmounts, rateModes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -121,8 +121,8 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
|
||||
// 0,5% slippage
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address', 'address', 'uint256'],
|
||||
[dai.address, userAddress, 50]
|
||||
['address[]', 'uint256'],
|
||||
[[dai.address], 50]
|
||||
);
|
||||
|
||||
await expect(
|
||||
|
@ -132,7 +132,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
uniswapLiquiditySwapAdapter.address,
|
||||
[weth.address],
|
||||
[flashloanAmount.toString()],
|
||||
0,
|
||||
[0],
|
||||
userAddress,
|
||||
params,
|
||||
0
|
||||
|
@ -158,6 +158,90 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap));
|
||||
});
|
||||
|
||||
it('should revert if inconsistent params', async () => {
|
||||
const {users, weth, oracle, dai, aWETH, pool, uniswapLiquiditySwapAdapter} = testEnv;
|
||||
const user = users[0].signer;
|
||||
const userAddress = users[0].address;
|
||||
|
||||
const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
|
||||
|
||||
const daiPrice = await oracle.getAssetPrice(dai.address);
|
||||
const expectedDaiAmount = await convertToCurrencyDecimals(
|
||||
dai.address,
|
||||
new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
|
||||
);
|
||||
|
||||
await mockUniswapRouter.setAmountToReturn(expectedDaiAmount);
|
||||
|
||||
// User will swap liquidity 10 aEth to aDai
|
||||
const liquidityToSwap = parseEther('10');
|
||||
await aWETH.connect(user).approve(uniswapLiquiditySwapAdapter.address, liquidityToSwap);
|
||||
|
||||
// Subtract the FL fee from the amount to be swapped 0,09%
|
||||
const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0);
|
||||
|
||||
// 0,5% slippage
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address[]', 'uint256'],
|
||||
[[dai.address, weth.address], 50]
|
||||
);
|
||||
|
||||
await expect(
|
||||
pool
|
||||
.connect(user)
|
||||
.flashLoan(
|
||||
uniswapLiquiditySwapAdapter.address,
|
||||
[weth.address],
|
||||
[flashloanAmount.toString()],
|
||||
[0],
|
||||
userAddress,
|
||||
params,
|
||||
0
|
||||
)
|
||||
).to.be.revertedWith('INCONSISTENT_PARAMS');
|
||||
});
|
||||
|
||||
it('should revert if caller not lending pool', async () => {
|
||||
const {users, weth, oracle, dai, aWETH, uniswapLiquiditySwapAdapter} = testEnv;
|
||||
const user = users[0].signer;
|
||||
const userAddress = users[0].address;
|
||||
|
||||
const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
|
||||
|
||||
const daiPrice = await oracle.getAssetPrice(dai.address);
|
||||
const expectedDaiAmount = await convertToCurrencyDecimals(
|
||||
dai.address,
|
||||
new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
|
||||
);
|
||||
|
||||
await mockUniswapRouter.setAmountToReturn(expectedDaiAmount);
|
||||
|
||||
// User will swap liquidity 10 aEth to aDai
|
||||
const liquidityToSwap = parseEther('10');
|
||||
await aWETH.connect(user).approve(uniswapLiquiditySwapAdapter.address, liquidityToSwap);
|
||||
|
||||
// Subtract the FL fee from the amount to be swapped 0,09%
|
||||
const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0);
|
||||
|
||||
// 0,5% slippage
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address[]', 'uint256'],
|
||||
[[dai.address, weth.address], 50]
|
||||
);
|
||||
|
||||
await expect(
|
||||
uniswapLiquiditySwapAdapter
|
||||
.connect(user)
|
||||
.executeOperation(
|
||||
[weth.address],
|
||||
[flashloanAmount.toString()],
|
||||
[0],
|
||||
userAddress,
|
||||
params
|
||||
)
|
||||
).to.be.revertedWith('CALLER_MUST_BE_LENDING_POOL');
|
||||
});
|
||||
|
||||
it('should work correctly with tokens of different decimals', async () => {
|
||||
const {
|
||||
users,
|
||||
|
@ -215,8 +299,8 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
|
||||
// 0,5% slippage
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address', 'address', 'uint256'],
|
||||
[dai.address, userAddress, 50]
|
||||
['address[]', 'uint256'],
|
||||
[[dai.address], 50]
|
||||
);
|
||||
|
||||
await expect(
|
||||
|
@ -226,7 +310,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
uniswapLiquiditySwapAdapter.address,
|
||||
[usdc.address],
|
||||
[flashloanAmount.toString()],
|
||||
0,
|
||||
[0],
|
||||
userAddress,
|
||||
params,
|
||||
0
|
||||
|
@ -275,14 +359,14 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
|
||||
// 30% slippage
|
||||
const params1 = ethers.utils.defaultAbiCoder.encode(
|
||||
['address', 'address', 'uint256'],
|
||||
[dai.address, userAddress, 3000]
|
||||
['address[]', 'uint256'],
|
||||
[[dai.address], 3000]
|
||||
);
|
||||
|
||||
// 0,05% slippage
|
||||
const params2 = ethers.utils.defaultAbiCoder.encode(
|
||||
['address', 'address', 'uint256'],
|
||||
[dai.address, userAddress, 5]
|
||||
['address[]', 'uint256'],
|
||||
[[dai.address], 5]
|
||||
);
|
||||
|
||||
await expect(
|
||||
|
@ -292,7 +376,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
uniswapLiquiditySwapAdapter.address,
|
||||
[weth.address],
|
||||
[flashloanAmount.toString()],
|
||||
0,
|
||||
[0],
|
||||
userAddress,
|
||||
params1,
|
||||
0
|
||||
|
@ -305,62 +389,13 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
uniswapLiquiditySwapAdapter.address,
|
||||
[weth.address],
|
||||
[flashloanAmount.toString()],
|
||||
0,
|
||||
[0],
|
||||
userAddress,
|
||||
params2,
|
||||
0
|
||||
)
|
||||
).to.be.revertedWith('SLIPPAGE_OUT_OF_RANGE');
|
||||
});
|
||||
|
||||
it('should revert when swap exceed slippage', async () => {
|
||||
const {users, weth, oracle, dai, aWETH, pool, uniswapLiquiditySwapAdapter} = testEnv;
|
||||
const user = users[0].signer;
|
||||
const userAddress = users[0].address;
|
||||
|
||||
const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
|
||||
|
||||
await weth.connect(user).mint(amountWETHtoSwap);
|
||||
await weth.connect(user).transfer(uniswapLiquiditySwapAdapter.address, amountWETHtoSwap);
|
||||
|
||||
const daiPrice = await oracle.getAssetPrice(dai.address);
|
||||
const expectedDaiAmount = await convertToCurrencyDecimals(
|
||||
dai.address,
|
||||
new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
|
||||
);
|
||||
|
||||
// 1,5% slippage
|
||||
const returnedDaiAmountWithBigSlippage = new BigNumber(expectedDaiAmount.toString())
|
||||
.multipliedBy(0.985)
|
||||
.toFixed(0);
|
||||
await mockUniswapRouter.connect(user).setAmountToReturn(returnedDaiAmountWithBigSlippage);
|
||||
|
||||
// User will swap liquidity 10 aEth to aDai
|
||||
const liquidityToSwap = parseEther('10');
|
||||
await aWETH.connect(user).approve(uniswapLiquiditySwapAdapter.address, liquidityToSwap);
|
||||
// Subtract the FL fee from the amount to be swapped 0,09%
|
||||
const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0);
|
||||
|
||||
// 0,5% slippage
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address', 'address', 'uint256'],
|
||||
[dai.address, userAddress, 50]
|
||||
);
|
||||
|
||||
await expect(
|
||||
pool
|
||||
.connect(user)
|
||||
.flashLoan(
|
||||
uniswapLiquiditySwapAdapter.address,
|
||||
[weth.address],
|
||||
[flashloanAmount.toString()],
|
||||
0,
|
||||
userAddress,
|
||||
params,
|
||||
0
|
||||
)
|
||||
).to.be.revertedWith('INSUFFICIENT_OUTPUT_AMOUNT');
|
||||
});
|
||||
});
|
||||
|
||||
describe('swapAndDeposit', () => {
|
||||
|
@ -400,13 +435,9 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
|
||||
|
||||
await expect(
|
||||
uniswapLiquiditySwapAdapter.swapAndDeposit(
|
||||
weth.address,
|
||||
dai.address,
|
||||
amountWETHtoSwap,
|
||||
userAddress,
|
||||
50
|
||||
)
|
||||
uniswapLiquiditySwapAdapter
|
||||
.connect(user)
|
||||
.swapAndDeposit([weth.address], [dai.address], [amountWETHtoSwap], 50)
|
||||
)
|
||||
.to.emit(uniswapLiquiditySwapAdapter, 'Swapped')
|
||||
.withArgs(weth.address, dai.address, amountWETHtoSwap.toString(), expectedDaiAmount);
|
||||
|
@ -427,6 +458,30 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
expect(userAEthBalance).to.be.lt(userAEthBalanceBefore);
|
||||
expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap));
|
||||
});
|
||||
it('should revert if inconsistent params', async () => {
|
||||
const {users, weth, dai, uniswapLiquiditySwapAdapter} = testEnv;
|
||||
const user = users[0].signer;
|
||||
|
||||
const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
|
||||
|
||||
await expect(
|
||||
uniswapLiquiditySwapAdapter
|
||||
.connect(user)
|
||||
.swapAndDeposit([weth.address, dai.address], [dai.address], [amountWETHtoSwap], 50)
|
||||
).to.be.revertedWith('INCONSISTENT_PARAMS');
|
||||
|
||||
await expect(
|
||||
uniswapLiquiditySwapAdapter
|
||||
.connect(user)
|
||||
.swapAndDeposit([weth.address], [dai.address, weth.address], [amountWETHtoSwap], 50)
|
||||
).to.be.revertedWith('INCONSISTENT_PARAMS');
|
||||
|
||||
await expect(
|
||||
uniswapLiquiditySwapAdapter
|
||||
.connect(user)
|
||||
.swapAndDeposit([weth.address], [dai.address], [amountWETHtoSwap, amountWETHtoSwap], 50)
|
||||
).to.be.revertedWith('INCONSISTENT_PARAMS');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -506,8 +561,8 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
await mockUniswapRouter.connect(user).setAmountToReturn(expectedDaiAmount);
|
||||
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address', 'address', 'uint256', 'uint256', 'uint256'],
|
||||
[dai.address, userAddress, 0, expectedDaiAmount, 1]
|
||||
['address[]', 'uint256', 'uint256[]', 'uint256[]'],
|
||||
[[dai.address], 0, [expectedDaiAmount], [1]]
|
||||
);
|
||||
|
||||
await expect(
|
||||
|
@ -517,7 +572,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
uniswapRepayAdapter.address,
|
||||
[weth.address],
|
||||
[flashloanAmount.toString()],
|
||||
0,
|
||||
[0],
|
||||
userAddress,
|
||||
params,
|
||||
0
|
||||
|
@ -539,6 +594,132 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap));
|
||||
});
|
||||
|
||||
it('should revert if inconsistent params', async () => {
|
||||
const {users, pool, weth, aWETH, oracle, dai, uniswapRepayAdapter} = testEnv;
|
||||
const user = users[0].signer;
|
||||
const userAddress = users[0].address;
|
||||
|
||||
const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
|
||||
|
||||
const daiPrice = await oracle.getAssetPrice(dai.address);
|
||||
const expectedDaiAmount = await convertToCurrencyDecimals(
|
||||
dai.address,
|
||||
new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
|
||||
);
|
||||
|
||||
// Open user Debt
|
||||
await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress);
|
||||
|
||||
const liquidityToSwap = amountWETHtoSwap;
|
||||
await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap);
|
||||
|
||||
// Subtract the FL fee from the amount to be swapped 0,09%
|
||||
const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0);
|
||||
|
||||
await mockUniswapRouter.connect(user).setAmountToSwap(flashloanAmount);
|
||||
await mockUniswapRouter.connect(user).setAmountToReturn(expectedDaiAmount);
|
||||
|
||||
const params1 = ethers.utils.defaultAbiCoder.encode(
|
||||
['address[]', 'uint256', 'uint256[]', 'uint256[]'],
|
||||
[[dai.address, weth.address], 0, [expectedDaiAmount], [1]]
|
||||
);
|
||||
|
||||
await expect(
|
||||
pool
|
||||
.connect(user)
|
||||
.flashLoan(
|
||||
uniswapRepayAdapter.address,
|
||||
[weth.address],
|
||||
[flashloanAmount.toString()],
|
||||
[0],
|
||||
userAddress,
|
||||
params1,
|
||||
0
|
||||
)
|
||||
).to.be.revertedWith('INCONSISTENT_PARAMS');
|
||||
|
||||
const params2 = ethers.utils.defaultAbiCoder.encode(
|
||||
['address[]', 'uint256', 'uint256[]', 'uint256[]'],
|
||||
[[dai.address], 0, [expectedDaiAmount, expectedDaiAmount], [1]]
|
||||
);
|
||||
|
||||
await expect(
|
||||
pool
|
||||
.connect(user)
|
||||
.flashLoan(
|
||||
uniswapRepayAdapter.address,
|
||||
[weth.address],
|
||||
[flashloanAmount.toString()],
|
||||
[0],
|
||||
userAddress,
|
||||
params2,
|
||||
0
|
||||
)
|
||||
).to.be.revertedWith('INCONSISTENT_PARAMS');
|
||||
|
||||
const params3 = ethers.utils.defaultAbiCoder.encode(
|
||||
['address[]', 'uint256', 'uint256[]', 'uint256[]'],
|
||||
[[dai.address], 0, [expectedDaiAmount], [1, 1]]
|
||||
);
|
||||
|
||||
await expect(
|
||||
pool
|
||||
.connect(user)
|
||||
.flashLoan(
|
||||
uniswapRepayAdapter.address,
|
||||
[weth.address],
|
||||
[flashloanAmount.toString()],
|
||||
[0],
|
||||
userAddress,
|
||||
params3,
|
||||
0
|
||||
)
|
||||
).to.be.revertedWith('INCONSISTENT_PARAMS');
|
||||
});
|
||||
|
||||
it('should revert if caller not lending pool', async () => {
|
||||
const {users, pool, weth, aWETH, oracle, dai, uniswapRepayAdapter} = testEnv;
|
||||
const user = users[0].signer;
|
||||
const userAddress = users[0].address;
|
||||
|
||||
const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
|
||||
|
||||
const daiPrice = await oracle.getAssetPrice(dai.address);
|
||||
const expectedDaiAmount = await convertToCurrencyDecimals(
|
||||
dai.address,
|
||||
new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
|
||||
);
|
||||
|
||||
// Open user Debt
|
||||
await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress);
|
||||
|
||||
const liquidityToSwap = amountWETHtoSwap;
|
||||
await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap);
|
||||
|
||||
// Subtract the FL fee from the amount to be swapped 0,09%
|
||||
const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0);
|
||||
|
||||
await mockUniswapRouter.connect(user).setAmountToSwap(flashloanAmount);
|
||||
await mockUniswapRouter.connect(user).setAmountToReturn(expectedDaiAmount);
|
||||
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address[]', 'uint256', 'uint256[]', 'uint256[]'],
|
||||
[[dai.address], 0, [expectedDaiAmount], [1]]
|
||||
);
|
||||
|
||||
await expect(
|
||||
uniswapRepayAdapter
|
||||
.connect(user)
|
||||
.executeOperation(
|
||||
[weth.address],
|
||||
[flashloanAmount.toString()],
|
||||
[0],
|
||||
userAddress,
|
||||
params
|
||||
)
|
||||
).to.be.revertedWith('CALLER_MUST_BE_LENDING_POOL');
|
||||
});
|
||||
|
||||
it('should revert if there is not debt to repay with the specified rate mode', async () => {
|
||||
const {users, pool, weth, oracle, dai, uniswapRepayAdapter, aWETH} = testEnv;
|
||||
const user = users[0].signer;
|
||||
|
@ -568,8 +749,8 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
await mockUniswapRouter.connect(user).setAmountToReturn(expectedDaiAmount);
|
||||
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address', 'address', 'uint256', 'uint256', 'uint256'],
|
||||
[dai.address, userAddress, 0, expectedDaiAmount, 1]
|
||||
['address[]', 'uint256', 'uint256[]', 'uint256[]'],
|
||||
[[dai.address], 0, [expectedDaiAmount], [1]]
|
||||
);
|
||||
|
||||
await expect(
|
||||
|
@ -579,7 +760,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
uniswapRepayAdapter.address,
|
||||
[weth.address],
|
||||
[flashloanAmount.toString()],
|
||||
0,
|
||||
[0],
|
||||
userAddress,
|
||||
params,
|
||||
0
|
||||
|
@ -613,8 +794,8 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
await mockUniswapRouter.connect(user).setAmountToReturn(expectedDaiAmount);
|
||||
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address', 'address', 'uint256', 'uint256', 'uint256'],
|
||||
[dai.address, userAddress, 0, expectedDaiAmount, 1]
|
||||
['address[]', 'uint256', 'uint256[]', 'uint256[]'],
|
||||
[[dai.address], 0, [expectedDaiAmount], [1]]
|
||||
);
|
||||
|
||||
await expect(
|
||||
|
@ -624,7 +805,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
uniswapRepayAdapter.address,
|
||||
[weth.address],
|
||||
[flashloanAmount.toString()],
|
||||
0,
|
||||
[0],
|
||||
userAddress,
|
||||
params,
|
||||
0
|
||||
|
@ -632,55 +813,6 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
).to.be.reverted;
|
||||
});
|
||||
|
||||
it('should revert when the received amount is less than expected', async () => {
|
||||
const {users, pool, weth, oracle, dai, aWETH, uniswapRepayAdapter} = testEnv;
|
||||
const user = users[0].signer;
|
||||
const userAddress = users[0].address;
|
||||
|
||||
const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
|
||||
|
||||
const daiPrice = await oracle.getAssetPrice(dai.address);
|
||||
const expectedDaiAmount = await convertToCurrencyDecimals(
|
||||
dai.address,
|
||||
new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
|
||||
);
|
||||
|
||||
// Open user Debt
|
||||
await pool.connect(user).borrow(dai.address, expectedDaiAmount, 1, 0, userAddress);
|
||||
|
||||
const liquidityToSwap = amountWETHtoSwap;
|
||||
await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap);
|
||||
|
||||
// Subtract the FL fee from the amount to be swapped 0,09%
|
||||
const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0);
|
||||
|
||||
const insufficientOutput = new BigNumber(expectedDaiAmount.toString())
|
||||
.multipliedBy(0.985)
|
||||
.toFixed(0);
|
||||
|
||||
await mockUniswapRouter.connect(user).setAmountToSwap(flashloanAmount);
|
||||
await mockUniswapRouter.connect(user).setAmountToReturn(insufficientOutput);
|
||||
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address', 'address', 'uint256', 'uint256', 'uint256'],
|
||||
[dai.address, userAddress, 0, expectedDaiAmount, 1]
|
||||
);
|
||||
|
||||
await expect(
|
||||
pool
|
||||
.connect(user)
|
||||
.flashLoan(
|
||||
uniswapRepayAdapter.address,
|
||||
[weth.address],
|
||||
[flashloanAmount.toString()],
|
||||
0,
|
||||
userAddress,
|
||||
params,
|
||||
0
|
||||
)
|
||||
).to.be.revertedWith('INSUFFICIENT_OUTPUT_AMOUNT');
|
||||
});
|
||||
|
||||
it('should revert when max amount allowed to swap is bigger than max slippage', async () => {
|
||||
const {users, pool, weth, oracle, dai, aWETH, uniswapRepayAdapter} = testEnv;
|
||||
const user = users[0].signer;
|
||||
|
@ -707,8 +839,8 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
await mockUniswapRouter.connect(user).setAmountToReturn(expectedDaiAmount);
|
||||
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address', 'address', 'uint256', 'uint256', 'uint256'],
|
||||
[dai.address, userAddress, 0, expectedDaiAmount, 1]
|
||||
['address[]', 'uint256', 'uint256[]', 'uint256[]'],
|
||||
[[dai.address], 0, [expectedDaiAmount], [1]]
|
||||
);
|
||||
|
||||
await expect(
|
||||
|
@ -718,7 +850,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
uniswapRepayAdapter.address,
|
||||
[weth.address],
|
||||
[flashloanAmount.toString()],
|
||||
0,
|
||||
[0],
|
||||
userAddress,
|
||||
params,
|
||||
0
|
||||
|
@ -779,8 +911,8 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
await mockUniswapRouter.connect(user).setAmountToReturn(expectedDaiAmount);
|
||||
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address', 'address', 'uint256', 'uint256', 'uint256'],
|
||||
[dai.address, userAddress, 0, expectedDaiAmount, 1]
|
||||
['address[]', 'uint256', 'uint256[]', 'uint256[]'],
|
||||
[[dai.address], 0, [expectedDaiAmount], [1]]
|
||||
);
|
||||
|
||||
await expect(
|
||||
|
@ -790,7 +922,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
uniswapRepayAdapter.address,
|
||||
[weth.address],
|
||||
[flashloanAmount.toString()],
|
||||
0,
|
||||
[0],
|
||||
userAddress,
|
||||
params,
|
||||
0
|
||||
|
@ -870,8 +1002,8 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
const wethBalanceBefore = await weth.balanceOf(userAddress);
|
||||
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address', 'address', 'uint256', 'uint256', 'uint256'],
|
||||
[dai.address, userAddress, 1, expectedDaiAmount, 1]
|
||||
['address[]', 'uint256', 'uint256[]', 'uint256[]'],
|
||||
[[dai.address], 1, [expectedDaiAmount], [1]]
|
||||
);
|
||||
|
||||
await expect(
|
||||
|
@ -881,7 +1013,7 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
uniswapRepayAdapter.address,
|
||||
[weth.address],
|
||||
[flashloanAmount.toString()],
|
||||
0,
|
||||
[0],
|
||||
userAddress,
|
||||
params,
|
||||
0
|
||||
|
|
Loading…
Reference in New Issue
Block a user