mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
1470 lines
53 KiB
TypeScript
1470 lines
53 KiB
TypeScript
import { makeSuite, TestEnv } from './helpers/make-suite';
|
|
import {
|
|
convertToCurrencyDecimals,
|
|
getContract,
|
|
buildPermitParams,
|
|
getSignatureFromTypedData,
|
|
buildRepayAdapterParams,
|
|
} from '../../helpers/contracts-helpers';
|
|
import { getMockUniswapRouter } from '../../helpers/contracts-getters';
|
|
import { deployUniswapRepayAdapter } from '../../helpers/contracts-deployments';
|
|
import { MockUniswapV2Router02 } from '../../types/MockUniswapV2Router02';
|
|
import { Zero } from '@ethersproject/constants';
|
|
import BigNumber from 'bignumber.js';
|
|
import { DRE, evmRevert, evmSnapshot } from '../../helpers/misc-utils';
|
|
import { ethers } from 'ethers';
|
|
import { eContractid } from '../../helpers/types';
|
|
import { StableDebtToken } from '../../types/StableDebtToken';
|
|
import { BUIDLEREVM_CHAINID } from '../../helpers/buidler-constants';
|
|
import { MAX_UINT_AMOUNT } from '../../helpers/constants';
|
|
import { VariableDebtToken } from '../../types';
|
|
const { parseEther } = ethers.utils;
|
|
|
|
const { expect } = require('chai');
|
|
|
|
makeSuite('Uniswap adapters', (testEnv: TestEnv) => {
|
|
let mockUniswapRouter: MockUniswapV2Router02;
|
|
let evmSnapshotId: string;
|
|
|
|
before(async () => {
|
|
mockUniswapRouter = await getMockUniswapRouter();
|
|
});
|
|
|
|
beforeEach(async () => {
|
|
evmSnapshotId = await evmSnapshot();
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await evmRevert(evmSnapshotId);
|
|
});
|
|
|
|
describe('UniswapRepayAdapter', () => {
|
|
beforeEach(async () => {
|
|
const { users, weth, dai, usdc, aave, pool, deployer } = testEnv;
|
|
const userAddress = users[0].address;
|
|
|
|
// Provide liquidity
|
|
await dai.mint(parseEther('20000'));
|
|
await dai.approve(pool.address, parseEther('20000'));
|
|
await pool.deposit(dai.address, parseEther('20000'), deployer.address, 0);
|
|
|
|
const usdcLiquidity = await convertToCurrencyDecimals(usdc.address, '2000000');
|
|
await usdc.mint(usdcLiquidity);
|
|
await usdc.approve(pool.address, usdcLiquidity);
|
|
await pool.deposit(usdc.address, usdcLiquidity, deployer.address, 0);
|
|
|
|
await weth.mint(parseEther('100'));
|
|
await weth.approve(pool.address, parseEther('100'));
|
|
await pool.deposit(weth.address, parseEther('100'), deployer.address, 0);
|
|
|
|
await aave.mint(parseEther('1000000'));
|
|
await aave.approve(pool.address, parseEther('1000000'));
|
|
await pool.deposit(aave.address, parseEther('1000000'), deployer.address, 0);
|
|
|
|
// Make a deposit for user
|
|
await weth.mint(parseEther('1000'));
|
|
await weth.approve(pool.address, parseEther('1000'));
|
|
await pool.deposit(weth.address, parseEther('1000'), userAddress, 0);
|
|
|
|
await aave.mint(parseEther('1000000'));
|
|
await aave.approve(pool.address, parseEther('1000000'));
|
|
await pool.deposit(aave.address, parseEther('1000000'), userAddress, 0);
|
|
|
|
await usdc.mint(usdcLiquidity);
|
|
await usdc.approve(pool.address, usdcLiquidity);
|
|
await pool.deposit(usdc.address, usdcLiquidity, userAddress, 0);
|
|
});
|
|
|
|
describe('constructor', () => {
|
|
it('should deploy with correct parameters', async () => {
|
|
const { addressesProvider, weth } = testEnv;
|
|
await deployUniswapRepayAdapter([
|
|
addressesProvider.address,
|
|
mockUniswapRouter.address,
|
|
weth.address,
|
|
]);
|
|
});
|
|
|
|
it('should revert if not valid addresses provider', async () => {
|
|
const { weth } = testEnv;
|
|
expect(
|
|
deployUniswapRepayAdapter([
|
|
mockUniswapRouter.address,
|
|
mockUniswapRouter.address,
|
|
weth.address,
|
|
])
|
|
).to.be.reverted;
|
|
});
|
|
});
|
|
|
|
describe('executeOperation', () => {
|
|
it('should correctly swap tokens and repay 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)
|
|
);
|
|
|
|
// Open user Debt
|
|
await pool.connect(user).borrow(dai.address, expectedDaiAmount, 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);
|
|
|
|
await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, liquidityToSwap);
|
|
|
|
const flashLoanDebt = new BigNumber(expectedDaiAmount.toString())
|
|
.multipliedBy(1.0009)
|
|
.toFixed(0);
|
|
|
|
await mockUniswapRouter.setAmountIn(
|
|
flashLoanDebt,
|
|
weth.address,
|
|
dai.address,
|
|
liquidityToSwap
|
|
);
|
|
|
|
const params = buildRepayAdapterParams(
|
|
weth.address,
|
|
liquidityToSwap,
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
false
|
|
);
|
|
|
|
await expect(
|
|
pool
|
|
.connect(user)
|
|
.flashLoan(
|
|
uniswapRepayAdapter.address,
|
|
[dai.address],
|
|
[expectedDaiAmount.toString()],
|
|
[0],
|
|
userAddress,
|
|
params,
|
|
0
|
|
)
|
|
)
|
|
.to.emit(uniswapRepayAdapter, 'Swapped')
|
|
.withArgs(weth.address, dai.address, liquidityToSwap.toString(), flashLoanDebt);
|
|
|
|
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);
|
|
|
|
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.lt(userAEthBalanceBefore);
|
|
expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap));
|
|
});
|
|
|
|
it('should correctly swap tokens and repay debt with permit', 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)
|
|
);
|
|
|
|
// Open user Debt
|
|
await pool.connect(user).borrow(dai.address, expectedDaiAmount, 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;
|
|
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
|
|
|
|
const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID;
|
|
const deadline = MAX_UINT_AMOUNT;
|
|
const nonce = (await aWETH._nonces(userAddress)).toNumber();
|
|
const msgParams = buildPermitParams(
|
|
chainId,
|
|
aWETH.address,
|
|
'1',
|
|
await aWETH.name(),
|
|
userAddress,
|
|
uniswapRepayAdapter.address,
|
|
nonce,
|
|
deadline,
|
|
liquidityToSwap.toString()
|
|
);
|
|
|
|
const ownerPrivateKey = require('../../test-wallets.js').accounts[1].secretKey;
|
|
if (!ownerPrivateKey) {
|
|
throw new Error('INVALID_OWNER_PK');
|
|
}
|
|
|
|
const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
|
|
|
await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, liquidityToSwap);
|
|
|
|
const flashLoanDebt = new BigNumber(expectedDaiAmount.toString())
|
|
.multipliedBy(1.0009)
|
|
.toFixed(0);
|
|
|
|
await mockUniswapRouter.setAmountIn(
|
|
flashLoanDebt,
|
|
weth.address,
|
|
dai.address,
|
|
liquidityToSwap
|
|
);
|
|
|
|
const params = buildRepayAdapterParams(
|
|
weth.address,
|
|
liquidityToSwap,
|
|
1,
|
|
liquidityToSwap,
|
|
deadline,
|
|
v,
|
|
r,
|
|
s,
|
|
false
|
|
);
|
|
|
|
await expect(
|
|
pool
|
|
.connect(user)
|
|
.flashLoan(
|
|
uniswapRepayAdapter.address,
|
|
[dai.address],
|
|
[expectedDaiAmount.toString()],
|
|
[0],
|
|
userAddress,
|
|
params,
|
|
0
|
|
)
|
|
)
|
|
.to.emit(uniswapRepayAdapter, 'Swapped')
|
|
.withArgs(weth.address, dai.address, liquidityToSwap.toString(), flashLoanDebt);
|
|
|
|
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);
|
|
|
|
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.lt(userAEthBalanceBefore);
|
|
expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap));
|
|
});
|
|
|
|
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);
|
|
|
|
await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, liquidityToSwap);
|
|
|
|
const params = buildRepayAdapterParams(
|
|
weth.address,
|
|
liquidityToSwap,
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
false
|
|
);
|
|
|
|
await expect(
|
|
uniswapRepayAdapter
|
|
.connect(user)
|
|
.executeOperation(
|
|
[dai.address],
|
|
[expectedDaiAmount.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;
|
|
const userAddress = users[0].address;
|
|
|
|
const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
|
|
|
|
await weth.connect(user).mint(amountWETHtoSwap);
|
|
await weth.connect(user).transfer(uniswapRepayAdapter.address, amountWETHtoSwap);
|
|
|
|
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, 2, 0, userAddress);
|
|
|
|
const liquidityToSwap = amountWETHtoSwap;
|
|
await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap);
|
|
|
|
await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, liquidityToSwap);
|
|
|
|
const params = buildRepayAdapterParams(
|
|
weth.address,
|
|
liquidityToSwap,
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
false
|
|
);
|
|
|
|
await expect(
|
|
pool
|
|
.connect(user)
|
|
.flashLoan(
|
|
uniswapRepayAdapter.address,
|
|
[dai.address],
|
|
[expectedDaiAmount.toString()],
|
|
[0],
|
|
userAddress,
|
|
params,
|
|
0
|
|
)
|
|
).to.be.reverted;
|
|
});
|
|
|
|
it('should revert if there is not debt to repay', async () => {
|
|
const { users, pool, weth, oracle, dai, uniswapRepayAdapter, aWETH } = 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(uniswapRepayAdapter.address, amountWETHtoSwap);
|
|
|
|
const daiPrice = await oracle.getAssetPrice(dai.address);
|
|
const expectedDaiAmount = await convertToCurrencyDecimals(
|
|
dai.address,
|
|
new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
|
|
);
|
|
|
|
const liquidityToSwap = amountWETHtoSwap;
|
|
await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap);
|
|
|
|
await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, liquidityToSwap);
|
|
|
|
const params = buildRepayAdapterParams(
|
|
weth.address,
|
|
liquidityToSwap,
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
false
|
|
);
|
|
|
|
await expect(
|
|
pool
|
|
.connect(user)
|
|
.flashLoan(
|
|
uniswapRepayAdapter.address,
|
|
[dai.address],
|
|
[expectedDaiAmount.toString()],
|
|
[0],
|
|
userAddress,
|
|
params,
|
|
0
|
|
)
|
|
).to.be.reverted;
|
|
});
|
|
|
|
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;
|
|
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 bigMaxAmountToSwap = amountWETHtoSwap.mul(2);
|
|
await aWETH.connect(user).approve(uniswapRepayAdapter.address, bigMaxAmountToSwap);
|
|
|
|
await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, bigMaxAmountToSwap);
|
|
|
|
const flashLoanDebt = new BigNumber(expectedDaiAmount.toString())
|
|
.multipliedBy(1.0009)
|
|
.toFixed(0);
|
|
|
|
await mockUniswapRouter.setAmountIn(
|
|
flashLoanDebt,
|
|
weth.address,
|
|
dai.address,
|
|
bigMaxAmountToSwap
|
|
);
|
|
|
|
const params = buildRepayAdapterParams(
|
|
weth.address,
|
|
bigMaxAmountToSwap,
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
false
|
|
);
|
|
|
|
await expect(
|
|
pool
|
|
.connect(user)
|
|
.flashLoan(
|
|
uniswapRepayAdapter.address,
|
|
[dai.address],
|
|
[expectedDaiAmount.toString()],
|
|
[0],
|
|
userAddress,
|
|
params,
|
|
0
|
|
)
|
|
).to.be.revertedWith('maxAmountToSwap exceed max slippage');
|
|
});
|
|
|
|
it('should swap, repay debt and pull the needed ATokens leaving no leftovers', 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)
|
|
);
|
|
|
|
// Open user Debt
|
|
await pool.connect(user).borrow(dai.address, expectedDaiAmount, 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);
|
|
const userWethBalanceBefore = await weth.balanceOf(userAddress);
|
|
|
|
const actualWEthSwapped = new BigNumber(liquidityToSwap.toString())
|
|
.multipliedBy(0.995)
|
|
.toFixed(0);
|
|
|
|
await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, actualWEthSwapped);
|
|
|
|
const flashLoanDebt = new BigNumber(expectedDaiAmount.toString())
|
|
.multipliedBy(1.0009)
|
|
.toFixed(0);
|
|
|
|
await mockUniswapRouter.setAmountIn(
|
|
flashLoanDebt,
|
|
weth.address,
|
|
dai.address,
|
|
actualWEthSwapped
|
|
);
|
|
|
|
const params = buildRepayAdapterParams(
|
|
weth.address,
|
|
liquidityToSwap,
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
false
|
|
);
|
|
|
|
await expect(
|
|
pool
|
|
.connect(user)
|
|
.flashLoan(
|
|
uniswapRepayAdapter.address,
|
|
[dai.address],
|
|
[expectedDaiAmount.toString()],
|
|
[0],
|
|
userAddress,
|
|
params,
|
|
0
|
|
)
|
|
)
|
|
.to.emit(uniswapRepayAdapter, 'Swapped')
|
|
.withArgs(weth.address, dai.address, actualWEthSwapped.toString(), flashLoanDebt);
|
|
|
|
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);
|
|
const userWethBalance = await weth.balanceOf(userAddress);
|
|
|
|
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.lt(userAEthBalanceBefore);
|
|
expect(userAEthBalance).to.be.eq(userAEthBalanceBefore.sub(actualWEthSwapped));
|
|
expect(userWethBalance).to.be.eq(userWethBalanceBefore);
|
|
});
|
|
|
|
it('should correctly swap tokens and repay the whole stable 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)
|
|
);
|
|
|
|
// Open user Debt
|
|
await pool.connect(user).borrow(dai.address, expectedDaiAmount, 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);
|
|
|
|
// Add a % to repay on top of the debt
|
|
const liquidityToSwap = new BigNumber(amountWETHtoSwap.toString())
|
|
.multipliedBy(1.1)
|
|
.toFixed(0);
|
|
|
|
await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap);
|
|
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
|
|
|
|
// Add a % to repay on top of the debt
|
|
const amountToRepay = new BigNumber(expectedDaiAmount.toString())
|
|
.multipliedBy(1.1)
|
|
.toFixed(0);
|
|
|
|
await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, amountWETHtoSwap);
|
|
await mockUniswapRouter.setDefaultMockValue(amountWETHtoSwap);
|
|
|
|
const params = buildRepayAdapterParams(
|
|
weth.address,
|
|
liquidityToSwap,
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
false
|
|
);
|
|
|
|
await pool
|
|
.connect(user)
|
|
.flashLoan(
|
|
uniswapRepayAdapter.address,
|
|
[dai.address],
|
|
[amountToRepay.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.eq(Zero);
|
|
expect(userAEthBalance).to.be.lt(userAEthBalanceBefore);
|
|
expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap));
|
|
});
|
|
|
|
it('should correctly swap tokens and repay the whole variable 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)
|
|
);
|
|
|
|
// Open user Debt
|
|
await pool.connect(user).borrow(dai.address, expectedDaiAmount, 2, 0, userAddress);
|
|
|
|
const daiStableVariableTokenAddress = (
|
|
await helpersContract.getReserveTokensAddresses(dai.address)
|
|
).variableDebtTokenAddress;
|
|
|
|
const daiVariableDebtContract = await getContract<StableDebtToken>(
|
|
eContractid.VariableDebtToken,
|
|
daiStableVariableTokenAddress
|
|
);
|
|
|
|
const userDaiVariableDebtAmountBefore = await daiVariableDebtContract.balanceOf(
|
|
userAddress
|
|
);
|
|
|
|
// Add a % to repay on top of the debt
|
|
const liquidityToSwap = new BigNumber(amountWETHtoSwap.toString())
|
|
.multipliedBy(1.1)
|
|
.toFixed(0);
|
|
|
|
await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap);
|
|
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
|
|
|
|
// Add a % to repay on top of the debt
|
|
const amountToRepay = new BigNumber(expectedDaiAmount.toString())
|
|
.multipliedBy(1.1)
|
|
.toFixed(0);
|
|
|
|
await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, amountWETHtoSwap);
|
|
await mockUniswapRouter.setDefaultMockValue(amountWETHtoSwap);
|
|
|
|
const params = buildRepayAdapterParams(
|
|
weth.address,
|
|
liquidityToSwap,
|
|
2,
|
|
0,
|
|
0,
|
|
0,
|
|
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
false
|
|
);
|
|
|
|
await pool
|
|
.connect(user)
|
|
.flashLoan(
|
|
uniswapRepayAdapter.address,
|
|
[dai.address],
|
|
[amountToRepay.toString()],
|
|
[0],
|
|
userAddress,
|
|
params,
|
|
0
|
|
);
|
|
|
|
const adapterWethBalance = await weth.balanceOf(uniswapRepayAdapter.address);
|
|
const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address);
|
|
const userDaiVariableDebtAmount = await daiVariableDebtContract.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(userDaiVariableDebtAmountBefore).to.be.gte(expectedDaiAmount);
|
|
expect(userDaiVariableDebtAmount).to.be.eq(Zero);
|
|
expect(userAEthBalance).to.be.lt(userAEthBalanceBefore);
|
|
expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap));
|
|
});
|
|
|
|
it('should correctly repay debt via flash loan using the same asset as collateral', async () => {
|
|
const { users, pool, aDai, dai, uniswapRepayAdapter, helpersContract } = testEnv;
|
|
const user = users[0].signer;
|
|
const userAddress = users[0].address;
|
|
|
|
// Add deposit for user
|
|
await dai.mint(parseEther('30'));
|
|
await dai.approve(pool.address, parseEther('30'));
|
|
await pool.deposit(dai.address, parseEther('30'), userAddress, 0);
|
|
|
|
const amountCollateralToSwap = parseEther('10');
|
|
const debtAmount = parseEther('10');
|
|
|
|
// Open user Debt
|
|
await pool.connect(user).borrow(dai.address, debtAmount, 2, 0, userAddress);
|
|
|
|
const daiVariableDebtTokenAddress = (
|
|
await helpersContract.getReserveTokensAddresses(dai.address)
|
|
).variableDebtTokenAddress;
|
|
|
|
const daiVariableDebtContract = await getContract<VariableDebtToken>(
|
|
eContractid.VariableDebtToken,
|
|
daiVariableDebtTokenAddress
|
|
);
|
|
|
|
const userDaiVariableDebtAmountBefore = await daiVariableDebtContract.balanceOf(
|
|
userAddress
|
|
);
|
|
|
|
const flashLoanDebt = new BigNumber(amountCollateralToSwap.toString())
|
|
.multipliedBy(1.0009)
|
|
.toFixed(0);
|
|
|
|
await aDai.connect(user).approve(uniswapRepayAdapter.address, flashLoanDebt);
|
|
const userADaiBalanceBefore = await aDai.balanceOf(userAddress);
|
|
const userDaiBalanceBefore = await dai.balanceOf(userAddress);
|
|
|
|
const params = buildRepayAdapterParams(
|
|
dai.address,
|
|
amountCollateralToSwap,
|
|
2,
|
|
0,
|
|
0,
|
|
0,
|
|
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
'0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
false
|
|
);
|
|
|
|
await pool
|
|
.connect(user)
|
|
.flashLoan(
|
|
uniswapRepayAdapter.address,
|
|
[dai.address],
|
|
[amountCollateralToSwap.toString()],
|
|
[0],
|
|
userAddress,
|
|
params,
|
|
0
|
|
);
|
|
|
|
const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address);
|
|
const userDaiVariableDebtAmount = await daiVariableDebtContract.balanceOf(userAddress);
|
|
const userADaiBalance = await aDai.balanceOf(userAddress);
|
|
const adapterADaiBalance = await aDai.balanceOf(uniswapRepayAdapter.address);
|
|
const userDaiBalance = await dai.balanceOf(userAddress);
|
|
|
|
expect(adapterADaiBalance).to.be.eq(Zero, 'adapter aDAI balance should be zero');
|
|
expect(adapterDaiBalance).to.be.eq(Zero, 'adapter DAI balance should be zero');
|
|
expect(userDaiVariableDebtAmountBefore).to.be.gte(
|
|
debtAmount,
|
|
' user DAI variable debt before should be gte debtAmount'
|
|
);
|
|
expect(userDaiVariableDebtAmount).to.be.lt(
|
|
debtAmount,
|
|
'user dai variable debt amount should be lt debt amount'
|
|
);
|
|
expect(userADaiBalance).to.be.lt(
|
|
userADaiBalanceBefore,
|
|
'user aDAI balance should be lt aDAI prior balance'
|
|
);
|
|
expect(userADaiBalance).to.be.gte(
|
|
userADaiBalanceBefore.sub(flashLoanDebt),
|
|
'user aDAI balance should be gte aDAI prior balance sub flash loan debt'
|
|
);
|
|
expect(userDaiBalance).to.be.eq(userDaiBalanceBefore, 'user dai balance eq prior balance');
|
|
});
|
|
});
|
|
|
|
describe('swapAndRepay', () => {
|
|
it('should correctly swap tokens and repay 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)
|
|
);
|
|
|
|
// Open user Debt
|
|
await pool.connect(user).borrow(dai.address, expectedDaiAmount, 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);
|
|
|
|
await mockUniswapRouter.setAmountToSwap(weth.address, liquidityToSwap);
|
|
|
|
await mockUniswapRouter.setDefaultMockValue(liquidityToSwap);
|
|
|
|
await uniswapRepayAdapter.connect(user).swapAndRepay(
|
|
weth.address,
|
|
dai.address,
|
|
liquidityToSwap,
|
|
expectedDaiAmount,
|
|
1,
|
|
{
|
|
amount: 0,
|
|
deadline: 0,
|
|
v: 0,
|
|
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
},
|
|
false
|
|
);
|
|
|
|
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);
|
|
|
|
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.lt(userAEthBalanceBefore);
|
|
expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap));
|
|
});
|
|
|
|
it('should correctly swap tokens and repay debt with permit', 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)
|
|
);
|
|
|
|
// Open user Debt
|
|
await pool.connect(user).borrow(dai.address, expectedDaiAmount, 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;
|
|
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
|
|
|
|
await mockUniswapRouter.setAmountToSwap(weth.address, liquidityToSwap);
|
|
|
|
await mockUniswapRouter.setDefaultMockValue(liquidityToSwap);
|
|
|
|
const chainId = DRE.network.config.chainId || BUIDLEREVM_CHAINID;
|
|
const deadline = MAX_UINT_AMOUNT;
|
|
const nonce = (await aWETH._nonces(userAddress)).toNumber();
|
|
const msgParams = buildPermitParams(
|
|
chainId,
|
|
aWETH.address,
|
|
'1',
|
|
await aWETH.name(),
|
|
userAddress,
|
|
uniswapRepayAdapter.address,
|
|
nonce,
|
|
deadline,
|
|
liquidityToSwap.toString()
|
|
);
|
|
|
|
const ownerPrivateKey = require('../../test-wallets.js').accounts[1].secretKey;
|
|
if (!ownerPrivateKey) {
|
|
throw new Error('INVALID_OWNER_PK');
|
|
}
|
|
|
|
const { v, r, s } = getSignatureFromTypedData(ownerPrivateKey, msgParams);
|
|
|
|
await uniswapRepayAdapter.connect(user).swapAndRepay(
|
|
weth.address,
|
|
dai.address,
|
|
liquidityToSwap,
|
|
expectedDaiAmount,
|
|
1,
|
|
{
|
|
amount: liquidityToSwap,
|
|
deadline,
|
|
v,
|
|
r,
|
|
s,
|
|
},
|
|
false
|
|
);
|
|
|
|
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);
|
|
|
|
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.lt(userAEthBalanceBefore);
|
|
expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap));
|
|
});
|
|
|
|
it('should revert if there is not debt to repay', async () => {
|
|
const { users, weth, aWETH, oracle, dai, uniswapRepayAdapter } = 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)
|
|
);
|
|
|
|
const liquidityToSwap = amountWETHtoSwap;
|
|
await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap);
|
|
|
|
await mockUniswapRouter.setAmountToSwap(weth.address, liquidityToSwap);
|
|
|
|
await mockUniswapRouter.setDefaultMockValue(liquidityToSwap);
|
|
|
|
await expect(
|
|
uniswapRepayAdapter.connect(user).swapAndRepay(
|
|
weth.address,
|
|
dai.address,
|
|
liquidityToSwap,
|
|
expectedDaiAmount,
|
|
1,
|
|
{
|
|
amount: 0,
|
|
deadline: 0,
|
|
v: 0,
|
|
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
},
|
|
false
|
|
)
|
|
).to.be.reverted;
|
|
});
|
|
|
|
it('should revert when max amount allowed to swap is bigger than max slippage', 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 bigMaxAmountToSwap = amountWETHtoSwap.mul(2);
|
|
await aWETH.connect(user).approve(uniswapRepayAdapter.address, bigMaxAmountToSwap);
|
|
|
|
await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, bigMaxAmountToSwap);
|
|
|
|
await mockUniswapRouter.setDefaultMockValue(bigMaxAmountToSwap);
|
|
|
|
await expect(
|
|
uniswapRepayAdapter.connect(user).swapAndRepay(
|
|
weth.address,
|
|
dai.address,
|
|
bigMaxAmountToSwap,
|
|
expectedDaiAmount,
|
|
1,
|
|
{
|
|
amount: 0,
|
|
deadline: 0,
|
|
v: 0,
|
|
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
},
|
|
false
|
|
)
|
|
).to.be.revertedWith('maxAmountToSwap exceed max slippage');
|
|
});
|
|
|
|
it('should swap, repay debt and pull the needed ATokens leaving no leftovers', 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)
|
|
);
|
|
|
|
// Open user Debt
|
|
await pool.connect(user).borrow(dai.address, expectedDaiAmount, 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);
|
|
const userWethBalanceBefore = await weth.balanceOf(userAddress);
|
|
|
|
const actualWEthSwapped = new BigNumber(liquidityToSwap.toString())
|
|
.multipliedBy(0.995)
|
|
.toFixed(0);
|
|
|
|
await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, actualWEthSwapped);
|
|
|
|
await mockUniswapRouter.setDefaultMockValue(actualWEthSwapped);
|
|
|
|
await uniswapRepayAdapter.connect(user).swapAndRepay(
|
|
weth.address,
|
|
dai.address,
|
|
liquidityToSwap,
|
|
expectedDaiAmount,
|
|
1,
|
|
{
|
|
amount: 0,
|
|
deadline: 0,
|
|
v: 0,
|
|
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
},
|
|
false
|
|
);
|
|
|
|
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);
|
|
const userWethBalance = await weth.balanceOf(userAddress);
|
|
|
|
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.lt(userAEthBalanceBefore);
|
|
expect(userAEthBalance).to.be.eq(userAEthBalanceBefore.sub(actualWEthSwapped));
|
|
expect(userWethBalance).to.be.eq(userWethBalanceBefore);
|
|
});
|
|
|
|
it('should correctly swap tokens and repay the whole stable 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)
|
|
);
|
|
|
|
// Open user Debt
|
|
await pool.connect(user).borrow(dai.address, expectedDaiAmount, 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);
|
|
|
|
// Add a % to repay on top of the debt
|
|
const liquidityToSwap = new BigNumber(amountWETHtoSwap.toString())
|
|
.multipliedBy(1.1)
|
|
.toFixed(0);
|
|
|
|
await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap);
|
|
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
|
|
|
|
// Add a % to repay on top of the debt
|
|
const amountToRepay = new BigNumber(expectedDaiAmount.toString())
|
|
.multipliedBy(1.1)
|
|
.toFixed(0);
|
|
|
|
await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, amountWETHtoSwap);
|
|
await mockUniswapRouter.setDefaultMockValue(amountWETHtoSwap);
|
|
|
|
await uniswapRepayAdapter.connect(user).swapAndRepay(
|
|
weth.address,
|
|
dai.address,
|
|
liquidityToSwap,
|
|
amountToRepay,
|
|
1,
|
|
{
|
|
amount: 0,
|
|
deadline: 0,
|
|
v: 0,
|
|
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
},
|
|
false
|
|
);
|
|
|
|
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.eq(Zero);
|
|
expect(userAEthBalance).to.be.lt(userAEthBalanceBefore);
|
|
expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap));
|
|
});
|
|
|
|
it('should correctly swap tokens and repay the whole variable 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)
|
|
);
|
|
|
|
// Open user Debt
|
|
await pool.connect(user).borrow(dai.address, expectedDaiAmount, 2, 0, userAddress);
|
|
|
|
const daiStableVariableTokenAddress = (
|
|
await helpersContract.getReserveTokensAddresses(dai.address)
|
|
).variableDebtTokenAddress;
|
|
|
|
const daiVariableDebtContract = await getContract<StableDebtToken>(
|
|
eContractid.VariableDebtToken,
|
|
daiStableVariableTokenAddress
|
|
);
|
|
|
|
const userDaiVariableDebtAmountBefore = await daiVariableDebtContract.balanceOf(
|
|
userAddress
|
|
);
|
|
|
|
// Add a % to repay on top of the debt
|
|
const liquidityToSwap = new BigNumber(amountWETHtoSwap.toString())
|
|
.multipliedBy(1.1)
|
|
.toFixed(0);
|
|
|
|
await aWETH.connect(user).approve(uniswapRepayAdapter.address, liquidityToSwap);
|
|
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
|
|
|
|
// Add a % to repay on top of the debt
|
|
const amountToRepay = new BigNumber(expectedDaiAmount.toString())
|
|
.multipliedBy(1.1)
|
|
.toFixed(0);
|
|
|
|
await mockUniswapRouter.connect(user).setAmountToSwap(weth.address, amountWETHtoSwap);
|
|
await mockUniswapRouter.setDefaultMockValue(amountWETHtoSwap);
|
|
|
|
await uniswapRepayAdapter.connect(user).swapAndRepay(
|
|
weth.address,
|
|
dai.address,
|
|
liquidityToSwap,
|
|
amountToRepay,
|
|
2,
|
|
{
|
|
amount: 0,
|
|
deadline: 0,
|
|
v: 0,
|
|
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
},
|
|
false
|
|
);
|
|
|
|
const adapterWethBalance = await weth.balanceOf(uniswapRepayAdapter.address);
|
|
const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address);
|
|
const userDaiVariableDebtAmount = await daiVariableDebtContract.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(userDaiVariableDebtAmountBefore).to.be.gte(expectedDaiAmount);
|
|
expect(userDaiVariableDebtAmount).to.be.eq(Zero);
|
|
expect(userAEthBalance).to.be.lt(userAEthBalanceBefore);
|
|
expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(liquidityToSwap));
|
|
});
|
|
|
|
it('should correctly repay debt using the same asset as collateral', async () => {
|
|
const { users, pool, dai, uniswapRepayAdapter, helpersContract, aDai } = testEnv;
|
|
const user = users[0].signer;
|
|
const userAddress = users[0].address;
|
|
|
|
// Add deposit for user
|
|
await dai.mint(parseEther('30'));
|
|
await dai.approve(pool.address, parseEther('30'));
|
|
await pool.deposit(dai.address, parseEther('30'), userAddress, 0);
|
|
|
|
const amountCollateralToSwap = parseEther('4');
|
|
|
|
const debtAmount = parseEther('3');
|
|
|
|
// Open user Debt
|
|
await pool.connect(user).borrow(dai.address, debtAmount, 2, 0, userAddress);
|
|
|
|
const daiVariableDebtTokenAddress = (
|
|
await helpersContract.getReserveTokensAddresses(dai.address)
|
|
).variableDebtTokenAddress;
|
|
|
|
const daiVariableDebtContract = await getContract<StableDebtToken>(
|
|
eContractid.StableDebtToken,
|
|
daiVariableDebtTokenAddress
|
|
);
|
|
|
|
const userDaiVariableDebtAmountBefore = await daiVariableDebtContract.balanceOf(
|
|
userAddress
|
|
);
|
|
|
|
await aDai.connect(user).approve(uniswapRepayAdapter.address, amountCollateralToSwap);
|
|
const userADaiBalanceBefore = await aDai.balanceOf(userAddress);
|
|
const userDaiBalanceBefore = await dai.balanceOf(userAddress);
|
|
|
|
await uniswapRepayAdapter.connect(user).swapAndRepay(
|
|
dai.address,
|
|
dai.address,
|
|
amountCollateralToSwap,
|
|
amountCollateralToSwap,
|
|
2,
|
|
{
|
|
amount: 0,
|
|
deadline: 0,
|
|
v: 0,
|
|
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
|
},
|
|
false
|
|
);
|
|
|
|
const adapterDaiBalance = await dai.balanceOf(uniswapRepayAdapter.address);
|
|
const userDaiVariableDebtAmount = await daiVariableDebtContract.balanceOf(userAddress);
|
|
const userADaiBalance = await aDai.balanceOf(userAddress);
|
|
const adapterADaiBalance = await aDai.balanceOf(uniswapRepayAdapter.address);
|
|
const userDaiBalance = await dai.balanceOf(userAddress);
|
|
|
|
expect(adapterADaiBalance).to.be.eq(Zero, 'adapter aADAI should be zero');
|
|
expect(adapterDaiBalance).to.be.eq(Zero, 'adapter DAI should be zero');
|
|
expect(userDaiVariableDebtAmountBefore).to.be.gte(
|
|
debtAmount,
|
|
'user dai variable debt before should be gte debtAmount'
|
|
);
|
|
expect(userDaiVariableDebtAmount).to.be.lt(
|
|
debtAmount,
|
|
'current user dai variable debt amount should be less than debtAmount'
|
|
);
|
|
expect(userADaiBalance).to.be.lt(
|
|
userADaiBalanceBefore,
|
|
'current user aDAI balance should be less than prior balance'
|
|
);
|
|
expect(userADaiBalance).to.be.gte(
|
|
userADaiBalanceBefore.sub(amountCollateralToSwap),
|
|
'current user aDAI balance should be gte user balance sub swapped collateral'
|
|
);
|
|
expect(userDaiBalance).to.be.eq(
|
|
userDaiBalanceBefore,
|
|
'user DAI balance should remain equal'
|
|
);
|
|
});
|
|
});
|
|
});
|
|
});
|