mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
Support using all the collateral for a debt repay
This commit is contained in:
parent
8a303c6195
commit
b48b50208a
|
@ -109,7 +109,16 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
PermitSignature memory permitSignature
|
||||
) internal {
|
||||
uint256 debtRepayAmount;
|
||||
uint256 amountSwapped;
|
||||
|
||||
ReserveLogic.ReserveData memory reserveData = _getReserveData(assetFrom);
|
||||
|
||||
if (repayMode == RepayMode.ALL_COLLATERAL) {
|
||||
uint256 aTokenInitiatorBalance = IERC20(reserveData.aTokenAddress).balanceOf(initiator);
|
||||
amountSwapped = aTokenInitiatorBalance.sub(premium);
|
||||
|
||||
debtRepayAmount = _swapExactTokensForTokens(assetFrom, assetTo, amountSwapped, repayAmount);
|
||||
} else {
|
||||
if (repayMode == RepayMode.ALL_DEBT) {
|
||||
ReserveLogic.ReserveData memory reserveDebtData = _getReserveData(assetTo);
|
||||
|
||||
|
@ -122,16 +131,18 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
debtRepayAmount = repayAmount;
|
||||
}
|
||||
|
||||
uint256 amountSwapped = _swapTokensForExactTokens(assetFrom, assetTo, amount, debtRepayAmount);
|
||||
amountSwapped = _swapTokensForExactTokens(assetFrom, assetTo, amount, debtRepayAmount);
|
||||
}
|
||||
|
||||
// Repay debt
|
||||
IERC20(assetTo).approve(address(POOL), debtRepayAmount);
|
||||
POOL.repay(assetTo, debtRepayAmount, rateMode, initiator);
|
||||
// In the case the repay amount provided exceeded the actual debt, send the leftovers to the user
|
||||
_sendRepayLeftovers(assetTo, initiator);
|
||||
|
||||
uint256 flashLoanDebt = amount.add(premium);
|
||||
uint256 amountToPull = amountSwapped.add(premium);
|
||||
|
||||
ReserveLogic.ReserveData memory reserveData = _getReserveData(assetFrom);
|
||||
_pullAToken(assetFrom, reserveData.aTokenAddress, initiator, amountToPull, permitSignature);
|
||||
|
||||
// Repay flashloan
|
||||
|
@ -179,4 +190,17 @@ contract UniswapRepayAdapter is BaseUniswapAdapter, IFlashLoanReceiver {
|
|||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Transfers the balance of the adapter to the user, as there shouldn't be any leftover in the adapter
|
||||
* @param asset address of the asset
|
||||
* @param user address
|
||||
*/
|
||||
function _sendRepayLeftovers(address asset, address user) internal {
|
||||
uint256 assetLeftover = IERC20(asset).balanceOf(address(this));
|
||||
|
||||
if (assetLeftover > 0) {
|
||||
IERC20(asset).transfer(user, assetLeftover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -262,7 +262,7 @@ export const buildRepayAdapterParams = (
|
|||
assetToSwapTo: tEthereumAddress,
|
||||
repayAmount: BigNumberish,
|
||||
rateMode: BigNumberish,
|
||||
repayAllDebt: BigNumberish,
|
||||
repayMode: BigNumberish,
|
||||
permitAmount: BigNumberish,
|
||||
deadline: BigNumberish,
|
||||
v: BigNumberish,
|
||||
|
@ -270,7 +270,17 @@ export const buildRepayAdapterParams = (
|
|||
s: string | Buffer
|
||||
) => {
|
||||
return ethers.utils.defaultAbiCoder.encode(
|
||||
['address', 'uint256', 'uint256', 'bool', 'uint256', 'uint256', 'uint8', 'bytes32', 'bytes32'],
|
||||
[assetToSwapTo, repayAmount, rateMode, repayAllDebt, permitAmount, deadline, v, r, s]
|
||||
[
|
||||
'address',
|
||||
'uint256',
|
||||
'uint256',
|
||||
'uint256',
|
||||
'uint256',
|
||||
'uint256',
|
||||
'uint8',
|
||||
'bytes32',
|
||||
'bytes32',
|
||||
],
|
||||
[assetToSwapTo, repayAmount, rateMode, repayMode, permitAmount, deadline, v, r, s]
|
||||
);
|
||||
};
|
||||
|
|
|
@ -280,7 +280,16 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
});
|
||||
|
||||
it('should correctly swap tokens and deposit the out tokens in the pool', async () => {
|
||||
const {users, weth, oracle, dai, aDai, aWETH, pool, uniswapLiquiditySwapAdapter} = testEnv;
|
||||
const {
|
||||
users,
|
||||
weth,
|
||||
oracle,
|
||||
dai,
|
||||
aDai,
|
||||
aWETH,
|
||||
pool,
|
||||
uniswapLiquiditySwapAdapter,
|
||||
} = testEnv;
|
||||
const user = users[0].signer;
|
||||
const userAddress = users[0].address;
|
||||
|
||||
|
@ -607,7 +616,16 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
});
|
||||
|
||||
it('should correctly swap tokens with permit', async () => {
|
||||
const {users, weth, oracle, dai, aDai, aWETH, pool, uniswapLiquiditySwapAdapter} = testEnv;
|
||||
const {
|
||||
users,
|
||||
weth,
|
||||
oracle,
|
||||
dai,
|
||||
aDai,
|
||||
aWETH,
|
||||
pool,
|
||||
uniswapLiquiditySwapAdapter,
|
||||
} = testEnv;
|
||||
const user = users[0].signer;
|
||||
const userAddress = users[0].address;
|
||||
|
||||
|
@ -1115,7 +1133,16 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
});
|
||||
|
||||
it('should correctly swap tokens all the balance', async () => {
|
||||
const {users, weth, oracle, dai, aDai, aWETH, pool, uniswapLiquiditySwapAdapter} = testEnv;
|
||||
const {
|
||||
users,
|
||||
weth,
|
||||
oracle,
|
||||
dai,
|
||||
aDai,
|
||||
aWETH,
|
||||
pool,
|
||||
uniswapLiquiditySwapAdapter,
|
||||
} = testEnv;
|
||||
const user = users[0].signer;
|
||||
const userAddress = users[0].address;
|
||||
|
||||
|
@ -1188,7 +1215,16 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
});
|
||||
|
||||
it('should correctly swap tokens all the balance using permit', async () => {
|
||||
const {users, weth, oracle, dai, aDai, aWETH, pool, uniswapLiquiditySwapAdapter} = testEnv;
|
||||
const {
|
||||
users,
|
||||
weth,
|
||||
oracle,
|
||||
dai,
|
||||
aDai,
|
||||
aWETH,
|
||||
pool,
|
||||
uniswapLiquiditySwapAdapter,
|
||||
} = testEnv;
|
||||
const user = users[0].signer;
|
||||
const userAddress = users[0].address;
|
||||
|
||||
|
@ -2681,6 +2717,192 @@ makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|||
expect(userAEthBalance).to.be.lt(userAEthBalanceBefore);
|
||||
expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap));
|
||||
});
|
||||
|
||||
it('should swap and repay debt using all the collateral for a bigger debt', async () => {
|
||||
const {
|
||||
users,
|
||||
pool,
|
||||
weth,
|
||||
aWETH,
|
||||
oracle,
|
||||
dai,
|
||||
uniswapRepayAdapter,
|
||||
helpersContract,
|
||||
} = 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)
|
||||
);
|
||||
|
||||
const userDebt = new BigNumber(expectedDaiAmount.toString()).multipliedBy(1.1).toFixed(0);
|
||||
// Open user Debt
|
||||
await pool.connect(user).borrow(dai.address, userDebt, 1, 0, userAddress);
|
||||
|
||||
const daiStableDebtTokenAddress = (
|
||||
await helpersContract.getReserveTokensAddresses(dai.address)
|
||||
).stableDebtTokenAddress;
|
||||
|
||||
const daiStableDebtContract = await getContract<StableDebtToken>(
|
||||
eContractid.StableDebtToken,
|
||||
daiStableDebtTokenAddress
|
||||
);
|
||||
|
||||
const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress);
|
||||
|
||||
const liquidityToSwap = amountWETHtoSwap;
|
||||
await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap);
|
||||
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
|
||||
|
||||
// Subtract the FL fee from the amount to be swapped 0,09%
|
||||
const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0);
|
||||
|
||||
const actualWEthSwapped = new BigNumber(flashloanAmount.toString())
|
||||
.multipliedBy(0.995)
|
||||
.toFixed(0);
|
||||
|
||||
// Remove other balance
|
||||
await aWETH
|
||||
.connect(user)
|
||||
.transfer(users[1].address, userAEthBalanceBefore.sub(actualWEthSwapped));
|
||||
|
||||
await mockUniswapRouter.connect(user).setAmountToReturn(weth.address, expectedDaiAmount);
|
||||
|
||||
const params = buildRepayAdapterParams(
|
||||
dai.address,
|
||||
expectedDaiAmount,
|
||||
1,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
||||
'0x0000000000000000000000000000000000000000000000000000000000000000'
|
||||
);
|
||||
|
||||
await pool
|
||||
.connect(user)
|
||||
.flashLoan(
|
||||
uniswapRepayAdapter.address,
|
||||
[weth.address],
|
||||
[flashloanAmount.toString()],
|
||||
[0],
|
||||
userAddress,
|
||||
params,
|
||||
0
|
||||
);
|
||||
|
||||
const adapterWethBalance = await weth.balanceOf(uniswapRepayAdapter.address);
|
||||
const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address);
|
||||
const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress);
|
||||
const userAEthBalance = await aWETH.balanceOf(userAddress);
|
||||
const adapterAEthBalance = await aWETH.balanceOf(uniswapRepayAdapter.address);
|
||||
|
||||
expect(adapterAEthBalance).to.be.eq(Zero);
|
||||
expect(adapterWethBalance).to.be.eq(Zero);
|
||||
expect(adapterDaiBalance).to.be.eq(Zero);
|
||||
expect(userDaiStableDebtAmountBefore).to.be.gte(expectedDaiAmount);
|
||||
expect(userDaiStableDebtAmount).to.be.lt(expectedDaiAmount);
|
||||
expect(userAEthBalance).to.be.eq(Zero);
|
||||
});
|
||||
|
||||
it('should swap and repay debt using all the collateral for a smaller debt', async () => {
|
||||
const {
|
||||
users,
|
||||
pool,
|
||||
weth,
|
||||
aWETH,
|
||||
oracle,
|
||||
dai,
|
||||
uniswapRepayAdapter,
|
||||
helpersContract,
|
||||
} = 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)
|
||||
);
|
||||
|
||||
const userDebt = new BigNumber(expectedDaiAmount.toString()).multipliedBy(0.9).toFixed(0);
|
||||
// Open user Debt
|
||||
await pool.connect(user).borrow(dai.address, userDebt, 1, 0, userAddress);
|
||||
|
||||
const daiStableDebtTokenAddress = (
|
||||
await helpersContract.getReserveTokensAddresses(dai.address)
|
||||
).stableDebtTokenAddress;
|
||||
|
||||
const daiStableDebtContract = await getContract<StableDebtToken>(
|
||||
eContractid.StableDebtToken,
|
||||
daiStableDebtTokenAddress
|
||||
);
|
||||
|
||||
const userDaiStableDebtAmountBefore = await daiStableDebtContract.balanceOf(userAddress);
|
||||
|
||||
const liquidityToSwap = amountWETHtoSwap;
|
||||
await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap);
|
||||
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
|
||||
|
||||
// Subtract the FL fee from the amount to be swapped 0,09%
|
||||
const flashloanAmount = new BigNumber(liquidityToSwap.toString()).div(1.0009).toFixed(0);
|
||||
|
||||
const actualWEthSwapped = new BigNumber(flashloanAmount.toString())
|
||||
.multipliedBy(0.995)
|
||||
.toFixed(0);
|
||||
|
||||
// Remove other balance
|
||||
await aWETH
|
||||
.connect(user)
|
||||
.transfer(users[1].address, userAEthBalanceBefore.sub(actualWEthSwapped));
|
||||
|
||||
await mockUniswapRouter.connect(user).setAmountToReturn(weth.address, expectedDaiAmount);
|
||||
|
||||
const params = buildRepayAdapterParams(
|
||||
dai.address,
|
||||
expectedDaiAmount,
|
||||
1,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
||||
'0x0000000000000000000000000000000000000000000000000000000000000000'
|
||||
);
|
||||
|
||||
await pool
|
||||
.connect(user)
|
||||
.flashLoan(
|
||||
uniswapRepayAdapter.address,
|
||||
[weth.address],
|
||||
[flashloanAmount.toString()],
|
||||
[0],
|
||||
userAddress,
|
||||
params,
|
||||
0
|
||||
);
|
||||
|
||||
const adapterWethBalance = await weth.balanceOf(uniswapRepayAdapter.address);
|
||||
const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address);
|
||||
const userDaiStableDebtAmount = await daiStableDebtContract.balanceOf(userAddress);
|
||||
const userAEthBalance = await aWETH.balanceOf(userAddress);
|
||||
const adapterAEthBalance = await aWETH.balanceOf(uniswapRepayAdapter.address);
|
||||
|
||||
expect(adapterAEthBalance).to.be.eq(Zero);
|
||||
expect(adapterWethBalance).to.be.eq(Zero);
|
||||
expect(adapterDaiBalance).to.be.eq(Zero); // Validate there are no leftovers
|
||||
expect(userDaiStableDebtAmountBefore).to.be.gte(userDebt);
|
||||
expect(userDaiStableDebtAmount).to.be.eq(Zero);
|
||||
expect(userAEthBalance).to.be.eq(Zero);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user