mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
Add swapAllBalance parameter for liquidity swap
This commit is contained in:
parent
48b9a603a7
commit
20bbae88d3
|
@ -124,7 +124,7 @@ contract BaseUniswapAdapter {
|
|||
* @param minAmountOut the min amount of `assetToSwapTo` to be received from the swap
|
||||
* @return the amount received from the swap
|
||||
*/
|
||||
function swapExactTokensForTokens(
|
||||
function _swapExactTokensForTokens(
|
||||
address assetToSwapFrom,
|
||||
address assetToSwapTo,
|
||||
uint256 amountToSwap,
|
||||
|
@ -167,7 +167,7 @@ contract BaseUniswapAdapter {
|
|||
* @param amountToReceive Exact amount of `assetToSwapTo` to receive
|
||||
* @return the amount swapped
|
||||
*/
|
||||
function swapTokensForExactTokens(
|
||||
function _swapTokensForExactTokens(
|
||||
address assetToSwapFrom,
|
||||
address assetToSwapTo,
|
||||
uint256 maxAmountToSwap,
|
||||
|
@ -222,7 +222,7 @@ contract BaseUniswapAdapter {
|
|||
* @dev Get the aToken associated to the asset
|
||||
* @return address of the aToken
|
||||
*/
|
||||
function getAToken(address asset) internal view returns (address) {
|
||||
function _getAToken(address asset) internal view returns (address) {
|
||||
ReserveLogic.ReserveData memory reserve = POOL.getReserveData(asset);
|
||||
return reserve.aTokenAddress;
|
||||
}
|
||||
|
@ -236,7 +236,7 @@ contract BaseUniswapAdapter {
|
|||
* (1) Direct transfer to user
|
||||
* @param user address
|
||||
*/
|
||||
function sendLeftovers(address asset, uint256 reservedAmount, LeftoverAction 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);
|
||||
|
||||
|
@ -253,18 +253,18 @@ contract BaseUniswapAdapter {
|
|||
/**
|
||||
* @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
|
||||
*/
|
||||
function pullAToken(
|
||||
function _pullAToken(
|
||||
address reserve,
|
||||
address reserveAToken,
|
||||
address user,
|
||||
uint256 amount,
|
||||
PermitSignature memory permitSignature
|
||||
) internal {
|
||||
address reserveAToken = getAToken(reserve);
|
||||
|
||||
if (_usePermit(permitSignature)) {
|
||||
IERC20WithPermit(reserveAToken).permit(
|
||||
user,
|
||||
|
@ -284,25 +284,6 @@ contract BaseUniswapAdapter {
|
|||
POOL.withdraw(reserve, amount, address(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Pull the ATokens from the user and use them to repay the flashloan
|
||||
* @param reserve address of the asset
|
||||
* @param user address
|
||||
* @param flashLoanDebt need to be repaid
|
||||
* @param permitSignature struct containing the permit signature
|
||||
*/
|
||||
function pullATokenAndRepayFlashLoan(
|
||||
address reserve,
|
||||
address user,
|
||||
uint256 flashLoanDebt,
|
||||
PermitSignature memory permitSignature
|
||||
) internal {
|
||||
pullAToken(reserve, user, flashLoanDebt, permitSignature);
|
||||
|
||||
// Repay flashloan
|
||||
IERC20(reserve).approve(address(POOL), flashLoanDebt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tells if the permit method should be called by inspecting if there is a valid signature.
|
||||
* If signature params are set to 0, then permit won't be called.
|
||||
|
|
|
@ -18,6 +18,7 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
struct SwapParams {
|
||||
address[] assetToSwapToList;
|
||||
uint256[] minAmountsToReceive;
|
||||
bool[] swapAllBalance;
|
||||
PermitParams permitParams;
|
||||
}
|
||||
|
||||
|
@ -41,6 +42,7 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
* @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
|
||||
* bool[] swapAllBalance Flag indicating if all the user balance should be swapped
|
||||
* 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
|
||||
|
@ -60,6 +62,7 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
require(
|
||||
assets.length == decodedParams.assetToSwapToList.length
|
||||
&& assets.length == decodedParams.minAmountsToReceive.length
|
||||
&& assets.length == decodedParams.swapAllBalance.length
|
||||
&& assets.length == decodedParams.permitParams.deadline.length
|
||||
&& assets.length == decodedParams.permitParams.v.length
|
||||
&& assets.length == decodedParams.permitParams.r.length
|
||||
|
@ -68,22 +71,14 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
);
|
||||
|
||||
for (uint256 i = 0; i < assets.length; i++) {
|
||||
uint256 receivedAmount = swapExactTokensForTokens(
|
||||
_swapLiquidity(
|
||||
assets[i],
|
||||
decodedParams.assetToSwapToList[i],
|
||||
amounts[i],
|
||||
decodedParams.minAmountsToReceive[i]
|
||||
);
|
||||
|
||||
// Deposit new reserve
|
||||
IERC20(decodedParams.assetToSwapToList[i]).approve(address(POOL), receivedAmount);
|
||||
POOL.deposit(decodedParams.assetToSwapToList[i], receivedAmount, initiator, 0);
|
||||
|
||||
uint256 flashLoanDebt = amounts[i].add(premiums[i]);
|
||||
pullATokenAndRepayFlashLoan(
|
||||
assets[i],
|
||||
premiums[i],
|
||||
initiator,
|
||||
flashLoanDebt,
|
||||
decodedParams.minAmountsToReceive[i],
|
||||
decodedParams.swapAllBalance[i],
|
||||
PermitSignature(
|
||||
decodedParams.permitParams.deadline[i],
|
||||
decodedParams.permitParams.v[i],
|
||||
|
@ -103,7 +98,7 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
* perform the swap.
|
||||
* @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 amountToSwapList List of amounts to be swapped. If the amount exceeds the balance, the total balance is used 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
|
||||
|
@ -127,17 +122,23 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
);
|
||||
|
||||
for (uint256 i = 0; i < assetToSwapFromList.length; i++) {
|
||||
pullAToken(
|
||||
address aToken = _getAToken(assetToSwapFromList[i]);
|
||||
|
||||
uint256 aTokenInitiatorBalance = IERC20(aToken).balanceOf(msg.sender);
|
||||
uint256 amountToSwap = amountToSwapList[i] > aTokenInitiatorBalance ? aTokenInitiatorBalance : amountToSwapList[i];
|
||||
|
||||
_pullAToken(
|
||||
assetToSwapFromList[i],
|
||||
aToken,
|
||||
msg.sender,
|
||||
amountToSwapList[i],
|
||||
amountToSwap,
|
||||
permitParams[i]
|
||||
);
|
||||
|
||||
uint256 receivedAmount = swapExactTokensForTokens(
|
||||
uint256 receivedAmount = _swapExactTokensForTokens(
|
||||
assetToSwapFromList[i],
|
||||
assetToSwapToList[i],
|
||||
amountToSwapList[i],
|
||||
amountToSwap,
|
||||
minAmountsToReceive[i]
|
||||
);
|
||||
|
||||
|
@ -147,12 +148,61 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Swaps an `amountToSwap` of an asset to another and deposits the funds on behalf of the initiator.
|
||||
* @param assetFrom Address of the underlying asset to be swap from
|
||||
* @param assetTo Address of the underlying asset to be swap to and deposited
|
||||
* @param amount Amount from flashloan
|
||||
* @param premium Premium of the flashloan
|
||||
* @param minAmountToReceive Min amount to be received from the swap
|
||||
* @param swapAllBalance Flag indicating if all the user balance should be swapped
|
||||
* @param permitSignature List of struct containing the permit signature
|
||||
*/
|
||||
function _swapLiquidity(
|
||||
address assetFrom,
|
||||
address assetTo,
|
||||
uint256 amount,
|
||||
uint256 premium,
|
||||
address initiator,
|
||||
uint256 minAmountToReceive,
|
||||
bool swapAllBalance,
|
||||
PermitSignature memory permitSignature
|
||||
) internal {
|
||||
address aToken = _getAToken(assetFrom);
|
||||
|
||||
uint256 aTokenInitiatorBalance = IERC20(aToken).balanceOf(initiator);
|
||||
uint256 amountToSwap = swapAllBalance ? aTokenInitiatorBalance.sub(premium) : amount;
|
||||
|
||||
uint256 receivedAmount = _swapExactTokensForTokens(
|
||||
assetFrom,
|
||||
assetTo,
|
||||
amountToSwap,
|
||||
minAmountToReceive
|
||||
);
|
||||
|
||||
// Deposit new reserve
|
||||
IERC20(assetTo).approve(address(POOL), receivedAmount);
|
||||
POOL.deposit(assetTo, receivedAmount, initiator, 0);
|
||||
|
||||
uint256 flashLoanDebt = amount.add(premium);
|
||||
uint256 amountToPull = swapAllBalance ? aTokenInitiatorBalance : flashLoanDebt;
|
||||
|
||||
_pullATokenAndRepayFlashLoan(
|
||||
assetFrom,
|
||||
aToken,
|
||||
initiator,
|
||||
amountToPull,
|
||||
flashLoanDebt,
|
||||
permitSignature
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
* uint256[] deadline List of deadlines for the permit signature
|
||||
* bool[] swapAllBalance Flag indicating if all the user balance should be swapped
|
||||
* 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
|
||||
|
@ -163,12 +213,36 @@ contract UniswapLiquiditySwapAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
(
|
||||
address[] memory assetToSwapToList,
|
||||
uint256[] memory minAmountsToReceive,
|
||||
bool[] memory swapAllBalance,
|
||||
uint256[] memory deadline,
|
||||
uint8[] memory v,
|
||||
bytes32[] memory r,
|
||||
bytes32[] memory s
|
||||
) = abi.decode(params, (address[], uint256[], uint256[], uint8[], bytes32[], bytes32[]));
|
||||
) = abi.decode(params, (address[], uint256[], bool[], uint256[], uint8[], bytes32[], bytes32[]));
|
||||
|
||||
return SwapParams(assetToSwapToList, minAmountsToReceive, PermitParams(deadline, v, r, s));
|
||||
return SwapParams(assetToSwapToList, minAmountsToReceive, swapAllBalance, PermitParams(deadline, v, r, s));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Pull the ATokens from the user and use them to repay the flashloan
|
||||
* @param reserve address of the asset
|
||||
* @param reserveAToken address of the aToken of the reserve
|
||||
* @param user address
|
||||
* @param amountToPull amount to be pulled from the user
|
||||
* @param flashLoanDebt need to be repaid
|
||||
* @param permitSignature struct containing the permit signature
|
||||
*/
|
||||
function _pullATokenAndRepayFlashLoan(
|
||||
address reserve,
|
||||
address reserveAToken,
|
||||
address user,
|
||||
uint256 amountToPull,
|
||||
uint256 flashLoanDebt,
|
||||
PermitSignature memory permitSignature
|
||||
) internal {
|
||||
_pullAToken(reserve, reserveAToken, user, amountToPull, permitSignature);
|
||||
|
||||
// Repay flashloan
|
||||
IERC20(reserve).approve(address(POOL), flashLoanDebt);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,17 +119,17 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
uint256 premium,
|
||||
PermitSignature memory permitSignature
|
||||
) internal {
|
||||
swapTokensForExactTokens(assetFrom, assetTo, amount, repayAmount);
|
||||
_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, permitSignature);
|
||||
_pullATokenAndRepayFlashLoan(assetFrom, initiator, flashLoanDebt, permitSignature);
|
||||
|
||||
// Take care of reserve leftover from the swap
|
||||
sendLeftovers(assetFrom, flashLoanDebt, leftOverAction, initiator);
|
||||
_sendLeftovers(assetFrom, flashLoanDebt, leftOverAction, initiator);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -161,15 +161,35 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
|
||||
return RepayParams(
|
||||
assetToSwapToList,
|
||||
leftOverAction,
|
||||
repayAmounts,
|
||||
rateModes,
|
||||
PermitParams(
|
||||
deadline,
|
||||
v,
|
||||
r,
|
||||
s
|
||||
)
|
||||
leftOverAction,
|
||||
repayAmounts,
|
||||
rateModes,
|
||||
PermitParams(
|
||||
deadline,
|
||||
v,
|
||||
r,
|
||||
s
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Pull the ATokens from the user and use them to repay the flashloan
|
||||
* @param reserve address of the asset
|
||||
* @param user address
|
||||
* @param flashLoanDebt need to be repaid
|
||||
* @param permitSignature struct containing the permit signature
|
||||
*/
|
||||
function _pullATokenAndRepayFlashLoan(
|
||||
address reserve,
|
||||
address user,
|
||||
uint256 flashLoanDebt,
|
||||
PermitSignature memory permitSignature
|
||||
) internal {
|
||||
address reserveAToken = _getAToken(reserve);
|
||||
_pullAToken(reserve, reserveAToken, user, flashLoanDebt, permitSignature);
|
||||
|
||||
// Repay flashloan
|
||||
IERC20(reserve).approve(address(POOL), flashLoanDebt);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -301,12 +301,13 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0);
|
||||
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
['address[]', 'uint256[]', 'bool[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
[
|
||||
[dai.address],
|
||||
[expectedDaiAmount],
|
||||
[0],
|
||||
[0],
|
||||
[0],
|
||||
['0x0000000000000000000000000000000000000000000000000000000000000000'],
|
||||
['0x0000000000000000000000000000000000000000000000000000000000000000'],
|
||||
]
|
||||
|
@ -411,12 +412,13 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
.toFixed(0);
|
||||
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
['address[]', 'uint256[]', 'bool[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
[
|
||||
[dai.address, dai.address],
|
||||
[expectedDaiAmountForEth, expectedDaiAmountForUsdc],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[
|
||||
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
||||
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
||||
|
@ -572,10 +574,11 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
);
|
||||
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
['address[]', 'uint256[]', 'bool[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
[
|
||||
[dai.address, dai.address],
|
||||
[expectedDaiAmountForEth, expectedDaiAmountForUsdc],
|
||||
[0, 0],
|
||||
[deadline, deadline],
|
||||
[aWETHv, aUsdcv],
|
||||
[aWETHr, aUsdcr],
|
||||
|
@ -673,8 +676,8 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
const {v, r, s} = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
||||
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
[[dai.address], [expectedDaiAmount], [deadline], [v], [r], [s]]
|
||||
['address[]', 'uint256[]', 'bool[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
[[dai.address], [expectedDaiAmount], [0], [deadline], [v], [r], [s]]
|
||||
);
|
||||
|
||||
await expect(
|
||||
|
@ -738,12 +741,13 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0);
|
||||
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
['address[]', 'uint256[]', 'bool[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
[
|
||||
[dai.address, weth.address],
|
||||
[expectedDaiAmount],
|
||||
[0],
|
||||
[0],
|
||||
[0],
|
||||
['0x0000000000000000000000000000000000000000000000000000000000000000'],
|
||||
['0x0000000000000000000000000000000000000000000000000000000000000000'],
|
||||
]
|
||||
|
@ -764,11 +768,12 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
).to.be.revertedWith('INCONSISTENT_PARAMS');
|
||||
|
||||
const params2 = ethers.utils.defaultAbiCoder.encode(
|
||||
['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
['address[]', 'uint256[]', 'bool[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
[
|
||||
[dai.address, weth.address],
|
||||
[expectedDaiAmount],
|
||||
[0, 0],
|
||||
[0, 0],
|
||||
[0],
|
||||
['0x0000000000000000000000000000000000000000000000000000000000000000'],
|
||||
['0x0000000000000000000000000000000000000000000000000000000000000000'],
|
||||
|
@ -790,10 +795,11 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
).to.be.revertedWith('INCONSISTENT_PARAMS');
|
||||
|
||||
const params3 = ethers.utils.defaultAbiCoder.encode(
|
||||
['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
['address[]', 'uint256[]', 'bool[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
[
|
||||
[dai.address, weth.address],
|
||||
[expectedDaiAmount],
|
||||
[0, 0],
|
||||
[0],
|
||||
[0, 0],
|
||||
['0x0000000000000000000000000000000000000000000000000000000000000000'],
|
||||
|
@ -816,12 +822,13 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
).to.be.revertedWith('INCONSISTENT_PARAMS');
|
||||
|
||||
const params4 = ethers.utils.defaultAbiCoder.encode(
|
||||
['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
['address[]', 'uint256[]', 'bool[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
[
|
||||
[dai.address, weth.address],
|
||||
[expectedDaiAmount],
|
||||
[0],
|
||||
[0],
|
||||
[0],
|
||||
[
|
||||
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
||||
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
||||
|
@ -845,12 +852,13 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
).to.be.revertedWith('INCONSISTENT_PARAMS');
|
||||
|
||||
const params5 = ethers.utils.defaultAbiCoder.encode(
|
||||
['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
['address[]', 'uint256[]', 'bool[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
[
|
||||
[dai.address, weth.address],
|
||||
[expectedDaiAmount],
|
||||
[0],
|
||||
[0],
|
||||
[0],
|
||||
['0x0000000000000000000000000000000000000000000000000000000000000000'],
|
||||
[
|
||||
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
||||
|
@ -874,12 +882,13 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
).to.be.revertedWith('INCONSISTENT_PARAMS');
|
||||
|
||||
const params6 = ethers.utils.defaultAbiCoder.encode(
|
||||
['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
['address[]', 'uint256[]', 'bool[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
[
|
||||
[dai.address, weth.address],
|
||||
[expectedDaiAmount, expectedDaiAmount],
|
||||
[0],
|
||||
[0],
|
||||
[0],
|
||||
['0x0000000000000000000000000000000000000000000000000000000000000000'],
|
||||
['0x0000000000000000000000000000000000000000000000000000000000000000'],
|
||||
]
|
||||
|
@ -898,6 +907,33 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
0
|
||||
)
|
||||
).to.be.revertedWith('INCONSISTENT_PARAMS');
|
||||
|
||||
const params7 = ethers.utils.defaultAbiCoder.encode(
|
||||
['address[]', 'uint256[]', 'bool[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
[
|
||||
[dai.address],
|
||||
[expectedDaiAmount],
|
||||
[0, 0],
|
||||
[0],
|
||||
[0],
|
||||
['0x0000000000000000000000000000000000000000000000000000000000000000'],
|
||||
['0x0000000000000000000000000000000000000000000000000000000000000000'],
|
||||
]
|
||||
);
|
||||
|
||||
await expect(
|
||||
pool
|
||||
.connect(user)
|
||||
.flashLoan(
|
||||
uniswapLiquiditySwapAdapter.address,
|
||||
[weth.address],
|
||||
[flashloanAmount.toString()],
|
||||
[0],
|
||||
userAddress,
|
||||
params7,
|
||||
0
|
||||
)
|
||||
).to.be.revertedWith('INCONSISTENT_PARAMS');
|
||||
});
|
||||
|
||||
it('should revert if caller not lending pool', async () => {
|
||||
|
@ -923,12 +959,13 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0);
|
||||
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
['address[]', 'uint256[]', 'bool[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
[
|
||||
[dai.address],
|
||||
[expectedDaiAmount],
|
||||
[0],
|
||||
[0],
|
||||
[0],
|
||||
['0x0000000000000000000000000000000000000000000000000000000000000000'],
|
||||
['0x0000000000000000000000000000000000000000000000000000000000000000'],
|
||||
]
|
||||
|
@ -1003,12 +1040,13 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
const flashloanAmount = new BigNumber(amountUSDCtoSwap.toString()).div(1.0009).toFixed(0);
|
||||
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
['address[]', 'uint256[]', 'bool[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
[
|
||||
[dai.address],
|
||||
[expectedDaiAmount],
|
||||
[0],
|
||||
[0],
|
||||
[0],
|
||||
['0x0000000000000000000000000000000000000000000000000000000000000000'],
|
||||
['0x0000000000000000000000000000000000000000000000000000000000000000'],
|
||||
]
|
||||
|
@ -1068,12 +1106,13 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0);
|
||||
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address[]', 'uint256[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
['address[]', 'uint256[]', 'bool[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
[
|
||||
[dai.address],
|
||||
[smallExpectedDaiAmount],
|
||||
[0],
|
||||
[0],
|
||||
[0],
|
||||
['0x0000000000000000000000000000000000000000000000000000000000000000'],
|
||||
['0x0000000000000000000000000000000000000000000000000000000000000000'],
|
||||
]
|
||||
|
@ -1093,6 +1132,81 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
)
|
||||
).to.be.revertedWith('minAmountOut exceed max slippage');
|
||||
});
|
||||
|
||||
it('should correctly swap tokens all the balance', async () => {
|
||||
const {users, weth, oracle, dai, aDai, 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(weth.address, expectedDaiAmount);
|
||||
|
||||
// Remove other balance
|
||||
await aWETH.connect(user).transfer(users[1].address, parseEther('90'));
|
||||
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
|
||||
|
||||
// User will swap liquidity 10 aEth to aDai
|
||||
const liquidityToSwap = parseEther('10');
|
||||
expect(userAEthBalanceBefore).to.be.eq(liquidityToSwap);
|
||||
await aWETH.connect(user).approve(uniswapLiquiditySwapAdapter.address, liquidityToSwap);
|
||||
|
||||
const params = ethers.utils.defaultAbiCoder.encode(
|
||||
['address[]', 'uint256[]', 'bool[]', 'uint256[]', 'uint8[]', 'bytes32[]', 'bytes32[]'],
|
||||
[
|
||||
[dai.address],
|
||||
[expectedDaiAmount],
|
||||
[1],
|
||||
[0],
|
||||
[0],
|
||||
['0x0000000000000000000000000000000000000000000000000000000000000000'],
|
||||
['0x0000000000000000000000000000000000000000000000000000000000000000'],
|
||||
]
|
||||
);
|
||||
|
||||
// Flashloan + premium > aToken balance. Then it will only swap the balance
|
||||
const flashloanFee = liquidityToSwap.mul(9).div(10000);
|
||||
const swappedAmount = liquidityToSwap.sub(flashloanFee);
|
||||
|
||||
await expect(
|
||||
pool
|
||||
.connect(user)
|
||||
.flashLoan(
|
||||
uniswapLiquiditySwapAdapter.address,
|
||||
[weth.address],
|
||||
[liquidityToSwap.toString()],
|
||||
[0],
|
||||
userAddress,
|
||||
params,
|
||||
0
|
||||
)
|
||||
)
|
||||
.to.emit(uniswapLiquiditySwapAdapter, 'Swapped')
|
||||
.withArgs(weth.address, dai.address, swappedAmount.toString(), expectedDaiAmount);
|
||||
|
||||
const adapterWethBalance = await weth.balanceOf(uniswapLiquiditySwapAdapter.address);
|
||||
const adapterDaiBalance = await dai.balanceOf(uniswapLiquiditySwapAdapter.address);
|
||||
const adapterDaiAllowance = await dai.allowance(
|
||||
uniswapLiquiditySwapAdapter.address,
|
||||
userAddress
|
||||
);
|
||||
const userADaiBalance = await aDai.balanceOf(userAddress);
|
||||
const userAEthBalance = await aWETH.balanceOf(userAddress);
|
||||
const adapterAEthBalance = await aWETH.balanceOf(uniswapLiquiditySwapAdapter.address);
|
||||
|
||||
expect(adapterWethBalance).to.be.eq(Zero);
|
||||
expect(adapterDaiBalance).to.be.eq(Zero);
|
||||
expect(adapterDaiAllowance).to.be.eq(Zero);
|
||||
expect(userADaiBalance).to.be.eq(expectedDaiAmount);
|
||||
expect(userAEthBalance).to.be.eq(Zero);
|
||||
expect(adapterAEthBalance).to.be.eq(Zero);
|
||||
});
|
||||
});
|
||||
|
||||
describe('swapAndDeposit', () => {
|
||||
|
@ -1607,6 +1721,72 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
expect(userAUsdcBalance).to.be.lt(userAUsdcBalanceBefore);
|
||||
expect(userAUsdcBalance).to.be.gte(userAUsdcBalanceBefore.sub(amountUSDCtoSwap));
|
||||
});
|
||||
|
||||
it('should correctly swap all the balance when using a bigger amount', async () => {
|
||||
const {users, weth, oracle, dai, aDai, 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(weth.address, expectedDaiAmount);
|
||||
|
||||
// Remove other balance
|
||||
await aWETH.connect(user).transfer(users[1].address, parseEther('90'));
|
||||
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
|
||||
|
||||
// User will swap liquidity 10 aEth to aDai
|
||||
const liquidityToSwap = parseEther('10');
|
||||
expect(userAEthBalanceBefore).to.be.eq(liquidityToSwap);
|
||||
|
||||
// User will swap liquidity 10 aEth to aDai
|
||||
await aWETH.connect(user).approve(uniswapLiquiditySwapAdapter.address, liquidityToSwap);
|
||||
|
||||
// Only has 10 atokens, so all the balance will be swapped
|
||||
const bigAmountToSwap = parseEther('100');
|
||||
|
||||
await expect(
|
||||
uniswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
|
||||
[weth.address],
|
||||
[dai.address],
|
||||
[bigAmountToSwap],
|
||||
[expectedDaiAmount],
|
||||
[
|
||||
{
|
||||
deadline: 0,
|
||||
v: 0,
|
||||
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
||||
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
||||
},
|
||||
]
|
||||
)
|
||||
)
|
||||
.to.emit(uniswapLiquiditySwapAdapter, 'Swapped')
|
||||
.withArgs(weth.address, dai.address, amountWETHtoSwap.toString(), expectedDaiAmount);
|
||||
|
||||
const adapterWethBalance = await weth.balanceOf(uniswapLiquiditySwapAdapter.address);
|
||||
const adapterDaiBalance = await dai.balanceOf(uniswapLiquiditySwapAdapter.address);
|
||||
const adapterDaiAllowance = await dai.allowance(
|
||||
uniswapLiquiditySwapAdapter.address,
|
||||
userAddress
|
||||
);
|
||||
const userADaiBalance = await aDai.balanceOf(userAddress);
|
||||
const userAEthBalance = await aWETH.balanceOf(userAddress);
|
||||
const adapterAEthBalance = await aWETH.balanceOf(uniswapLiquiditySwapAdapter.address);
|
||||
|
||||
expect(adapterWethBalance).to.be.eq(Zero);
|
||||
expect(adapterDaiBalance).to.be.eq(Zero);
|
||||
expect(adapterDaiAllowance).to.be.eq(Zero);
|
||||
expect(userADaiBalance).to.be.eq(expectedDaiAmount);
|
||||
expect(userAEthBalance).to.be.eq(Zero);
|
||||
expect(adapterAEthBalance).to.be.eq(Zero);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user