Update liquidity swap adapter params to include min amount to receive

This commit is contained in:
Gerardo Nardelli 2020-11-03 12:22:15 -03:00
parent fa7fa9f948
commit 94a6a8688c
3 changed files with 188 additions and 118 deletions

View File

@ -40,10 +40,8 @@ contract BaseUniswapAdapter {
bytes32 s; bytes32 s;
} }
// Max slippage percent allow by param // Max slippage percent allowed
uint256 public constant MAX_SLIPPAGE_PERCENT = 3000; // 30% uint256 public constant MAX_SLIPPAGE_PERCENT = 3000; // 30%
// Min slippage percent allow by param
uint256 public constant MIN_SLIPPAGE_PERCENT = 10; // 0,1%
ILendingPool public immutable POOL; ILendingPool public immutable POOL;
IPriceOracleGetter public immutable ORACLE; IPriceOracleGetter public immutable ORACLE;
@ -100,18 +98,18 @@ contract BaseUniswapAdapter {
} }
/** /**
* @dev Swaps an `amountToSwap` of an asset to another * @dev Swaps an exact `amountToSwap` of an asset to another
* @param assetToSwapFrom Origin asset * @param assetToSwapFrom Origin asset
* @param assetToSwapTo Destination asset * @param assetToSwapTo Destination asset
* @param amountToSwap Exact amount of `assetToSwapFrom` to be swapped * @param amountToSwap Exact amount of `assetToSwapFrom` to be swapped
* @param slippage the max slippage percentage allowed for the swap * @param minAmountOut the min amount of `assetToSwapTo` to be received from the swap
* @return the amount received from the swap * @return the amount received from the swap
*/ */
function swapExactTokensForTokens( function swapExactTokensForTokens(
address assetToSwapFrom, address assetToSwapFrom,
address assetToSwapTo, address assetToSwapTo,
uint256 amountToSwap, uint256 amountToSwap,
uint256 slippage uint256 minAmountOut
) )
internal internal
returns (uint256) returns (uint256)
@ -122,17 +120,19 @@ contract BaseUniswapAdapter {
uint256 fromAssetPrice = _getPrice(assetToSwapFrom); uint256 fromAssetPrice = _getPrice(assetToSwapFrom);
uint256 toAssetPrice = _getPrice(assetToSwapTo); uint256 toAssetPrice = _getPrice(assetToSwapTo);
uint256 amountOutMin = amountToSwap uint256 expectedMinAmountOut = amountToSwap
.mul(fromAssetPrice.mul(10**toAssetDecimals)) .mul(fromAssetPrice.mul(10**toAssetDecimals))
.div(toAssetPrice.mul(10**fromAssetDecimals)) .div(toAssetPrice.mul(10**fromAssetDecimals))
.percentMul(PercentageMath.PERCENTAGE_FACTOR.sub(slippage)); .percentMul(PercentageMath.PERCENTAGE_FACTOR.sub(MAX_SLIPPAGE_PERCENT));
require(expectedMinAmountOut < minAmountOut, 'minAmountOut exceed max slippage');
IERC20(assetToSwapFrom).approve(address(UNISWAP_ROUTER), amountToSwap); IERC20(assetToSwapFrom).approve(address(UNISWAP_ROUTER), amountToSwap);
address[] memory path = new address[](2); address[] memory path = new address[](2);
path[0] = assetToSwapFrom; path[0] = assetToSwapFrom;
path[1] = assetToSwapTo; path[1] = assetToSwapTo;
uint256[] memory amounts = UNISWAP_ROUTER.swapExactTokensForTokens(amountToSwap, amountOutMin, path, address(this), block.timestamp); uint256[] memory amounts = UNISWAP_ROUTER.swapExactTokensForTokens(amountToSwap, minAmountOut, path, address(this), block.timestamp);
emit Swapped(assetToSwapFrom, assetToSwapTo, amounts[0], amounts[1]); emit Swapped(assetToSwapFrom, assetToSwapTo, amounts[0], amounts[1]);
@ -146,7 +146,7 @@ contract BaseUniswapAdapter {
* @param assetToSwapTo Destination asset * @param assetToSwapTo Destination asset
* @param maxAmountToSwap Max amount of `assetToSwapFrom` allowed to be swapped * @param maxAmountToSwap Max amount of `assetToSwapFrom` allowed to be swapped
* @param amountToReceive Exact amount of `assetToSwapTo` to receive * @param amountToReceive Exact amount of `assetToSwapTo` to receive
* @return the amount received from the swap * @return the amount swapped
*/ */
function swapTokensForExactTokens( function swapTokensForExactTokens(
address assetToSwapFrom, address assetToSwapFrom,
@ -179,7 +179,7 @@ contract BaseUniswapAdapter {
emit Swapped(assetToSwapFrom, assetToSwapTo, amounts[0], amounts[1]); emit Swapped(assetToSwapFrom, assetToSwapTo, amounts[0], amounts[1]);
return amounts[1]; return amounts[0];
} }
/** /**

View File

@ -17,7 +17,7 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
struct SwapParams { struct SwapParams {
address[] assetToSwapToList; address[] assetToSwapToList;
uint256 slippage; uint256[] minAmountsToReceive;
PermitParams permitParams; PermitParams permitParams;
} }
@ -40,7 +40,7 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
* @param initiator Address of the user * @param initiator Address of the user
* @param params Additional variadic field to include extra params. Expected parameters: * @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 * 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 * uint256[] minAmountsToReceive List of min amounts to be received from the swap
* 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 * uint8[] v List of v param for the permit signature
* bytes32[] r List of r param for the permit signature * bytes32[] r List of r param for the permit signature
@ -58,12 +58,8 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
SwapParams memory decodedParams = _decodeParams(params); SwapParams memory decodedParams = _decodeParams(params);
require( require(
decodedParams.slippage < MAX_SLIPPAGE_PERCENT && decodedParams.slippage >= MIN_SLIPPAGE_PERCENT, assets.length == decodedParams.assetToSwapToList.length
'SLIPPAGE_OUT_OF_RANGE' && assets.length == decodedParams.minAmountsToReceive.length
);
require(
decodedParams.assetToSwapToList.length == assets.length
&& assets.length == decodedParams.permitParams.deadline.length && assets.length == decodedParams.permitParams.deadline.length
&& assets.length == decodedParams.permitParams.v.length && assets.length == decodedParams.permitParams.v.length
&& assets.length == decodedParams.permitParams.r.length && assets.length == decodedParams.permitParams.r.length
@ -76,7 +72,7 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
assets[i], assets[i],
decodedParams.assetToSwapToList[i], decodedParams.assetToSwapToList[i],
amounts[i], amounts[i],
decodedParams.slippage decodedParams.minAmountsToReceive[i]
); );
// Deposit new reserve // Deposit new reserve
@ -108,7 +104,8 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
* @param assetToSwapFromList List of addresses of the underlying asset to be swap from * @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 assetToSwapToList List of addresses of the underlying asset to be swap to and deposited
* @param amountToSwapList List of amounts to be swapped * @param amountToSwapList List of amounts to be swapped
* @param slippage The max slippage percentage allowed for the swap * @param minAmountsToReceive List of min amounts to be received from the swap
* @param permitParams List of struct containing the permit signatures
* 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 * uint8[] v List of v param for the permit signature
* bytes32[] r List of r param for the permit signature * bytes32[] r List of r param for the permit signature
@ -118,12 +115,13 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
address[] calldata assetToSwapFromList, address[] calldata assetToSwapFromList,
address[] calldata assetToSwapToList, address[] calldata assetToSwapToList,
uint256[] calldata amountToSwapList, uint256[] calldata amountToSwapList,
uint256 slippage, uint256[] calldata minAmountsToReceive,
PermitSignature[] calldata permitParams PermitSignature[] calldata permitParams
) external { ) external {
require( require(
assetToSwapFromList.length == assetToSwapToList.length assetToSwapFromList.length == assetToSwapToList.length
&& assetToSwapFromList.length == amountToSwapList.length && assetToSwapFromList.length == amountToSwapList.length
&& assetToSwapFromList.length == minAmountsToReceive.length
&& assetToSwapFromList.length == permitParams.length, && assetToSwapFromList.length == permitParams.length,
'INCONSISTENT_PARAMS' 'INCONSISTENT_PARAMS'
); );
@ -140,7 +138,7 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
assetToSwapFromList[i], assetToSwapFromList[i],
assetToSwapToList[i], assetToSwapToList[i],
amountToSwapList[i], amountToSwapList[i],
slippage minAmountsToReceive[i]
); );
// Deposit new reserve // Deposit new reserve
@ -153,7 +151,7 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
* @dev Decodes debt information encoded in flashloan params * @dev Decodes debt information encoded in flashloan params
* @param params Additional variadic field to include extra params. Expected parameters: * @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 * 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 * uint256[] minAmountsToReceive List of min amounts to be received from the swap
* uint256[] deadline List of deadlines for the permit signature * uint256[] deadline List of deadlines for the permit signature
* 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 * uint8[] v List of v param for the permit signature
@ -164,13 +162,13 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
function _decodeParams(bytes memory params) internal returns (SwapParams memory) { function _decodeParams(bytes memory params) internal returns (SwapParams memory) {
( (
address[] memory assetToSwapToList, address[] memory assetToSwapToList,
uint256 slippage, uint256[] memory minAmountsToReceive,
uint256[] memory deadline, uint256[] memory deadline,
uint8[] memory v, uint8[] memory v,
bytes32[] memory r, bytes32[] memory r,
bytes32[] memory s bytes32[] memory s
) = abi.decode(params, (address[], uint256, uint256[], uint8[], bytes32[], bytes32[])); ) = abi.decode(params, (address[], uint256[], uint256[], uint8[], bytes32[], bytes32[]));
return SwapParams(assetToSwapToList, slippage, PermitParams(deadline, v, r, s)); return SwapParams(assetToSwapToList, minAmountsToReceive, PermitParams(deadline, v, r, s));
} }
} }

View File

@ -126,12 +126,11 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
// Subtract the FL fee from the amount to be swapped 0,09% // Subtract the FL fee from the amount to be swapped 0,09%
const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0); const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0);
// 0,5% slippage
const params = ethers.utils.defaultAbiCoder.encode( const params = ethers.utils.defaultAbiCoder.encode(
['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], ['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
[ [
[dai.address], [dai.address],
50, [expectedDaiAmount],
[0], [0],
[0], [0],
['0x0000000000000000000000000000000000000000000000000000000000000000'], ['0x0000000000000000000000000000000000000000000000000000000000000000'],
@ -224,10 +223,9 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
const {v, r, s} = getSignatureFromTypedData(ownerPrivateKey, msgParams); const {v, r, s} = getSignatureFromTypedData(ownerPrivateKey, msgParams);
// 0,5% slippage
const params = ethers.utils.defaultAbiCoder.encode( const params = ethers.utils.defaultAbiCoder.encode(
['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], ['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
[[dai.address], 50, [deadline], [v], [r], [s]] [[dai.address], [expectedDaiAmount], [deadline], [v], [r], [s]]
); );
await expect( await expect(
@ -290,12 +288,11 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
// Subtract the FL fee from the amount to be swapped 0,09% // Subtract the FL fee from the amount to be swapped 0,09%
const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0); const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0);
// 0,5% slippage
const params = ethers.utils.defaultAbiCoder.encode( const params = ethers.utils.defaultAbiCoder.encode(
['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], ['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
[ [
[dai.address, weth.address], [dai.address, weth.address],
50, [expectedDaiAmount],
[0], [0],
[0], [0],
['0x0000000000000000000000000000000000000000000000000000000000000000'], ['0x0000000000000000000000000000000000000000000000000000000000000000'],
@ -318,10 +315,10 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
).to.be.revertedWith('INCONSISTENT_PARAMS'); ).to.be.revertedWith('INCONSISTENT_PARAMS');
const params2 = ethers.utils.defaultAbiCoder.encode( const params2 = ethers.utils.defaultAbiCoder.encode(
['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], ['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
[ [
[dai.address, weth.address], [dai.address, weth.address],
50, [expectedDaiAmount],
[0, 0], [0, 0],
[0], [0],
['0x0000000000000000000000000000000000000000000000000000000000000000'], ['0x0000000000000000000000000000000000000000000000000000000000000000'],
@ -344,10 +341,10 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
).to.be.revertedWith('INCONSISTENT_PARAMS'); ).to.be.revertedWith('INCONSISTENT_PARAMS');
const params3 = ethers.utils.defaultAbiCoder.encode( const params3 = ethers.utils.defaultAbiCoder.encode(
['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], ['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
[ [
[dai.address, weth.address], [dai.address, weth.address],
50, [expectedDaiAmount],
[0], [0],
[0, 0], [0, 0],
['0x0000000000000000000000000000000000000000000000000000000000000000'], ['0x0000000000000000000000000000000000000000000000000000000000000000'],
@ -370,10 +367,10 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
).to.be.revertedWith('INCONSISTENT_PARAMS'); ).to.be.revertedWith('INCONSISTENT_PARAMS');
const params4 = ethers.utils.defaultAbiCoder.encode( const params4 = ethers.utils.defaultAbiCoder.encode(
['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], ['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
[ [
[dai.address, weth.address], [dai.address, weth.address],
50, [expectedDaiAmount],
[0], [0],
[0], [0],
[ [
@ -399,10 +396,10 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
).to.be.revertedWith('INCONSISTENT_PARAMS'); ).to.be.revertedWith('INCONSISTENT_PARAMS');
const params5 = ethers.utils.defaultAbiCoder.encode( const params5 = ethers.utils.defaultAbiCoder.encode(
['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], ['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
[ [
[dai.address, weth.address], [dai.address, weth.address],
50, [expectedDaiAmount],
[0], [0],
[0], [0],
['0x0000000000000000000000000000000000000000000000000000000000000000'], ['0x0000000000000000000000000000000000000000000000000000000000000000'],
@ -426,6 +423,32 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
0 0
) )
).to.be.revertedWith('INCONSISTENT_PARAMS'); ).to.be.revertedWith('INCONSISTENT_PARAMS');
const params6 = ethers.utils.defaultAbiCoder.encode(
['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
[
[dai.address, weth.address],
[expectedDaiAmount, expectedDaiAmount],
[0],
[0],
['0x0000000000000000000000000000000000000000000000000000000000000000'],
['0x0000000000000000000000000000000000000000000000000000000000000000'],
]
);
await expect(
pool
.connect(user)
.flashLoan(
uniswapLiquiditySwapAdapter.address,
[weth.address],
[flashloanAmount.toString()],
[0],
userAddress,
params6,
0
)
).to.be.revertedWith('INCONSISTENT_PARAMS');
}); });
it('should revert if caller not lending pool', async () => { it('should revert if caller not lending pool', async () => {
@ -450,12 +473,11 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
// Subtract the FL fee from the amount to be swapped 0,09% // Subtract the FL fee from the amount to be swapped 0,09%
const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0); const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0);
// 0,5% slippage
const params = ethers.utils.defaultAbiCoder.encode( const params = ethers.utils.defaultAbiCoder.encode(
['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], ['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
[ [
[dai.address], [dai.address],
50, [expectedDaiAmount],
[0], [0],
[0], [0],
['0x0000000000000000000000000000000000000000000000000000000000000000'], ['0x0000000000000000000000000000000000000000000000000000000000000000'],
@ -531,12 +553,11 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
// Subtract the FL fee from the amount to be swapped 0,09% // Subtract the FL fee from the amount to be swapped 0,09%
const flashloanAmount = new BigNumber(amountUSDCtoSwap.toString()).div(1.0009).toFixed(0); const flashloanAmount = new BigNumber(amountUSDCtoSwap.toString()).div(1.0009).toFixed(0);
// 0,5% slippage
const params = ethers.utils.defaultAbiCoder.encode( const params = ethers.utils.defaultAbiCoder.encode(
['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'], ['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
[ [
[dai.address], [dai.address],
50, [expectedDaiAmount],
[0], [0],
[0], [0],
['0x0000000000000000000000000000000000000000000000000000000000000000'], ['0x0000000000000000000000000000000000000000000000000000000000000000'],
@ -574,49 +595,34 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
expect(aDaiBalance).to.be.eq(expectedDaiAmount); expect(aDaiBalance).to.be.eq(expectedDaiAmount);
}); });
it('should revert if slippage param is not inside limits', async () => { it('should revert when min amount to receive exceeds the max slippage amount', async () => {
const {users, pool, weth, oracle, dai, aWETH, uniswapLiquiditySwapAdapter} = testEnv; const {users, weth, oracle, dai, aWETH, pool, uniswapLiquiditySwapAdapter} = testEnv;
const user = users[0].signer; const user = users[0].signer;
const userAddress = users[0].address; const userAddress = users[0].address;
const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); 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 daiPrice = await oracle.getAssetPrice(dai.address);
const expectedDaiAmount = await convertToCurrencyDecimals( const expectedDaiAmount = await convertToCurrencyDecimals(
dai.address, dai.address,
new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0) new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
); );
await mockUniswapRouter.connect(user).setAmountToReturn(expectedDaiAmount); await mockUniswapRouter.setAmountToReturn(expectedDaiAmount);
const smallExpectedDaiAmount = expectedDaiAmount.div(2);
// User will swap liquidity 10 aEth to aDai // User will swap liquidity 10 aEth to aDai
const liquidityToSwap = parseEther('10'); const liquidityToSwap = parseEther('10');
await aWETH.connect(user).approve(uniswapLiquiditySwapAdapter.address, liquidityToSwap); await aWETH.connect(user).approve(uniswapLiquiditySwapAdapter.address, liquidityToSwap);
// Subtract the FL fee from the amount to be swapped 0,09% // Subtract the FL fee from the amount to be swapped 0,09%
const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0); const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0);
// 30% slippage const params = ethers.utils.defaultAbiCoder.encode(
const params1 = ethers.utils.defaultAbiCoder.encode( ['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
[ [
[dai.address], [dai.address],
3000, [smallExpectedDaiAmount],
[0],
[0],
['0x0000000000000000000000000000000000000000000000000000000000000000'],
['0x0000000000000000000000000000000000000000000000000000000000000000'],
]
);
// 0,05% slippage
const params2 = ethers.utils.defaultAbiCoder.encode(
['address[]', 'uint256', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
[
[dai.address],
5,
[0], [0],
[0], [0],
['0x0000000000000000000000000000000000000000000000000000000000000000'], ['0x0000000000000000000000000000000000000000000000000000000000000000'],
@ -633,23 +639,10 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
[flashloanAmount.toString()], [flashloanAmount.toString()],
[0], [0],
userAddress, userAddress,
params1, params,
0 0
) )
).to.be.revertedWith('SLIPPAGE_OUT_OF_RANGE'); ).to.be.revertedWith('minAmountOut exceed max slippage');
await expect(
pool
.connect(user)
.flashLoan(
uniswapLiquiditySwapAdapter.address,
[weth.address],
[flashloanAmount.toString()],
[0],
userAddress,
params2,
0
)
).to.be.revertedWith('SLIPPAGE_OUT_OF_RANGE');
}); });
}); });
@ -690,16 +683,20 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress); const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
await expect( await expect(
uniswapLiquiditySwapAdapter uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
.connect(user) [weth.address],
.swapAndDeposit([weth.address], [dai.address], [amountWETHtoSwap], 50, [ [dai.address],
[amountWETHtoSwap],
[expectedDaiAmount],
[
{ {
deadline: 0, deadline: 0,
v: 0, v: 0,
r: '0x0000000000000000000000000000000000000000000000000000000000000000', r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000', s: '0x0000000000000000000000000000000000000000000000000000000000000000',
}, },
]) ]
)
) )
.to.emit(uniswapLiquiditySwapAdapter, 'Swapped') .to.emit(uniswapLiquiditySwapAdapter, 'Swapped')
.withArgs(weth.address, dai.address, amountWETHtoSwap.toString(), expectedDaiAmount); .withArgs(weth.address, dai.address, amountWETHtoSwap.toString(), expectedDaiAmount);
@ -763,16 +760,20 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
const {v, r, s} = getSignatureFromTypedData(ownerPrivateKey, msgParams); const {v, r, s} = getSignatureFromTypedData(ownerPrivateKey, msgParams);
await expect( await expect(
uniswapLiquiditySwapAdapter uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
.connect(user) [weth.address],
.swapAndDeposit([weth.address], [dai.address], [amountWETHtoSwap], 50, [ [dai.address],
[amountWETHtoSwap],
[expectedDaiAmount],
[
{ {
deadline, deadline,
v, v,
r, r,
s, s,
}, },
]) ]
)
) )
.to.emit(uniswapLiquiditySwapAdapter, 'Swapped') .to.emit(uniswapLiquiditySwapAdapter, 'Swapped')
.withArgs(weth.address, dai.address, amountWETHtoSwap.toString(), expectedDaiAmount); .withArgs(weth.address, dai.address, amountWETHtoSwap.toString(), expectedDaiAmount);
@ -795,35 +796,65 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
}); });
it('should revert if inconsistent params', async () => { it('should revert if inconsistent params', async () => {
const {users, weth, dai, uniswapLiquiditySwapAdapter} = testEnv; const {users, weth, dai, uniswapLiquiditySwapAdapter, oracle} = testEnv;
const user = users[0].signer; const user = users[0].signer;
const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10'); 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 expect( await expect(
uniswapLiquiditySwapAdapter uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
.connect(user) [weth.address, dai.address],
.swapAndDeposit([weth.address, dai.address], [dai.address], [amountWETHtoSwap], 50, [ [dai.address],
[amountWETHtoSwap],
[expectedDaiAmount],
[
{ {
deadline: 0, deadline: 0,
v: 0, v: 0,
r: '0x0000000000000000000000000000000000000000000000000000000000000000', r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000', s: '0x0000000000000000000000000000000000000000000000000000000000000000',
}, },
]) ]
)
).to.be.revertedWith('INCONSISTENT_PARAMS'); ).to.be.revertedWith('INCONSISTENT_PARAMS');
await expect( await expect(
uniswapLiquiditySwapAdapter uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
.connect(user) [weth.address],
.swapAndDeposit([weth.address], [dai.address, weth.address], [amountWETHtoSwap], 50, [ [dai.address, weth.address],
[amountWETHtoSwap],
[expectedDaiAmount],
[
{ {
deadline: 0, deadline: 0,
v: 0, v: 0,
r: '0x0000000000000000000000000000000000000000000000000000000000000000', r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000', s: '0x0000000000000000000000000000000000000000000000000000000000000000',
}, },
]) ]
)
).to.be.revertedWith('INCONSISTENT_PARAMS');
await expect(
uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
[weth.address],
[dai.address],
[amountWETHtoSwap, amountWETHtoSwap],
[expectedDaiAmount],
[
{
deadline: 0,
v: 0,
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
},
]
)
).to.be.revertedWith('INCONSISTENT_PARAMS'); ).to.be.revertedWith('INCONSISTENT_PARAMS');
await expect( await expect(
@ -832,25 +863,66 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
.swapAndDeposit( .swapAndDeposit(
[weth.address], [weth.address],
[dai.address], [dai.address],
[amountWETHtoSwap, amountWETHtoSwap], [amountWETHtoSwap],
50, [expectedDaiAmount],
[ []
{
deadline: 0,
v: 0,
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
},
]
) )
).to.be.revertedWith('INCONSISTENT_PARAMS'); ).to.be.revertedWith('INCONSISTENT_PARAMS');
await expect( await expect(
uniswapLiquiditySwapAdapter uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
.connect(user) [weth.address],
.swapAndDeposit([weth.address], [dai.address], [amountWETHtoSwap], 50, []) [dai.address],
[amountWETHtoSwap],
[expectedDaiAmount, expectedDaiAmount],
[
{
deadline: 0,
v: 0,
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
},
]
)
).to.be.revertedWith('INCONSISTENT_PARAMS'); ).to.be.revertedWith('INCONSISTENT_PARAMS');
}); });
it('should revert when min amount to receive exceeds the max slippage amount', async () => {
const {users, weth, oracle, dai, aWETH, uniswapLiquiditySwapAdapter} = testEnv;
const user = users[0].signer;
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);
const smallExpectedDaiAmount = expectedDaiAmount.div(2);
// User will swap liquidity 10 aEth to aDai
const liquidityToSwap = parseEther('10');
await aWETH.connect(user).approve(uniswapLiquiditySwapAdapter.address, liquidityToSwap);
await expect(
uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
[weth.address],
[dai.address],
[amountWETHtoSwap],
[smallExpectedDaiAmount],
[
{
deadline: 0,
v: 0,
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
},
]
)
).to.be.revertedWith('minAmountOut exceed max slippage');
});
}); });
}); });