aave-protocol-v2/test-suites/test-aave/paraswapAdapters.liquiditySwap.spec.ts
Jason Raymond Bell 4fe36c8fa4 Introduce registry of valid Augustus addresses
Set in constructor of BaseParaSwapSellAdapter and validates before swap.
Created mock registry that only validates one address.
Changed the test fixtures to accomodate registry and added two new tests.
Updated deployment script.
Registry address left as a placeholder in package.json since not known yet.

Fixes MixBytes Warning 1.
2021-05-20 23:25:51 +01:00

2394 lines
90 KiB
TypeScript

import { makeSuite, TestEnv } from './helpers/make-suite';
import {
convertToCurrencyDecimals,
getContract,
buildPermitParams,
getSignatureFromTypedData,
buildParaSwapLiquiditySwapParams,
} from '../../helpers/contracts-helpers';
import {
getMockParaSwapAugustus,
getMockParaSwapAugustusRegistry,
} from '../../helpers/contracts-getters';
import { deployParaSwapLiquiditySwapAdapter } from '../../helpers/contracts-deployments';
import { MockParaSwapAugustus } from '../../types/MockParaSwapAugustus';
import { MockParaSwapAugustusRegistry } from '../../types/MockParaSwapAugustusRegistry';
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 { AToken } from '../../types/AToken';
import { BUIDLEREVM_CHAINID } from '../../helpers/buidler-constants';
import { MAX_UINT_AMOUNT } from '../../helpers/constants';
const { parseEther } = ethers.utils;
const { expect } = require('chai');
makeSuite('ParaSwap adapters', (testEnv: TestEnv) => {
let mockAugustus: MockParaSwapAugustus;
let mockAugustusRegistry: MockParaSwapAugustusRegistry;
let evmSnapshotId: string;
before(async () => {
mockAugustus = await getMockParaSwapAugustus();
mockAugustusRegistry = await getMockParaSwapAugustusRegistry();
});
beforeEach(async () => {
evmSnapshotId = await evmSnapshot();
});
afterEach(async () => {
await evmRevert(evmSnapshotId);
});
describe('ParaSwapLiquiditySwapAdapter', () => {
describe('constructor', () => {
it('should deploy with correct parameters', async () => {
const { addressesProvider } = testEnv;
await deployParaSwapLiquiditySwapAdapter([
addressesProvider.address,
mockAugustusRegistry.address,
]);
});
it('should revert if not valid addresses provider', async () => {
await expect(
deployParaSwapLiquiditySwapAdapter([
mockAugustus.address, // any invalid contract can be used here
mockAugustusRegistry.address,
])
).to.be.reverted;
});
it('should revert if not valid augustus registry', async () => {
const { addressesProvider } = testEnv;
await expect(
deployParaSwapLiquiditySwapAdapter([
addressesProvider.address,
mockAugustus.address, // any invalid contract can be used here
])
).to.be.reverted;
});
});
describe('executeOperation', () => {
beforeEach(async () => {
const { users, weth, dai, 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);
await weth.mint(parseEther('10000'));
await weth.approve(pool.address, parseEther('10000'));
await pool.deposit(weth.address, parseEther('10000'), deployer.address, 0);
// Make a deposit for user
await weth.mint(parseEther('100'));
await weth.approve(pool.address, parseEther('100'));
await pool.deposit(weth.address, parseEther('100'), userAddress, 0);
});
it('should correctly swap tokens and deposit the out tokens in the pool', async () => {
const {
users,
weth,
oracle,
dai,
aDai,
aWETH,
pool,
paraswapLiquiditySwapAdapter,
} = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
const flashloanPremium = amountWETHtoSwap.mul(9).div(10000);
const flashloanTotal = amountWETHtoSwap.add(flashloanPremium);
// User will swap liquidity aEth to aDai
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount]
);
const params = buildParaSwapLiquiditySwapParams(
dai.address,
expectedDaiAmount,
0,
mockAugustusCalldata,
mockAugustus.address,
0,
0,
0,
'0x0000000000000000000000000000000000000000000000000000000000000000',
'0x0000000000000000000000000000000000000000000000000000000000000000'
);
await expect(
pool
.connect(user)
.flashLoan(
paraswapLiquiditySwapAdapter.address,
[weth.address],
[amountWETHtoSwap],
[0],
userAddress,
params,
0
)
)
.to.emit(paraswapLiquiditySwapAdapter, 'Swapped')
.withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount);
const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address);
const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address);
const userADaiBalance = await aDai.balanceOf(userAddress);
const userAEthBalance = await aWETH.balanceOf(userAddress);
// N.B. will get some portion of flashloan premium back from the pool
expect(adapterWethBalance).to.be.eq(Zero);
expect(adapterDaiBalance).to.be.eq(Zero);
expect(userADaiBalance).to.be.eq(expectedDaiAmount);
expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(flashloanTotal));
expect(userAEthBalance).to.be.lte(userAEthBalanceBefore.sub(amountWETHtoSwap));
});
it('should correctly swap tokens using permit', async () => {
const {
users,
weth,
oracle,
dai,
aDai,
aWETH,
pool,
paraswapLiquiditySwapAdapter,
} = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
const flashloanPremium = amountWETHtoSwap.mul(9).div(10000);
const flashloanTotal = amountWETHtoSwap.add(flashloanPremium);
// User will swap liquidity aEth to aDai
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,
paraswapLiquiditySwapAdapter.address,
nonce,
deadline,
flashloanTotal.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);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount]
);
const params = buildParaSwapLiquiditySwapParams(
dai.address,
expectedDaiAmount,
0,
mockAugustusCalldata,
mockAugustus.address,
flashloanTotal,
deadline,
v,
r,
s
);
await expect(
pool
.connect(user)
.flashLoan(
paraswapLiquiditySwapAdapter.address,
[weth.address],
[amountWETHtoSwap],
[0],
userAddress,
params,
0
)
)
.to.emit(paraswapLiquiditySwapAdapter, 'Swapped')
.withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount);
const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address);
const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address);
const userADaiBalance = await aDai.balanceOf(userAddress);
const userAEthBalance = await aWETH.balanceOf(userAddress);
// N.B. will get some portion of flashloan premium back from the pool
expect(adapterWethBalance).to.be.eq(Zero);
expect(adapterDaiBalance).to.be.eq(Zero);
expect(userADaiBalance).to.be.eq(expectedDaiAmount);
expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(flashloanTotal));
expect(userAEthBalance).to.be.lte(userAEthBalanceBefore.sub(amountWETHtoSwap));
});
it('should revert if caller not lending pool', async () => {
const {
users,
weth,
oracle,
dai,
aWETH,
paraswapLiquiditySwapAdapter,
} = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
const flashloanPremium = amountWETHtoSwap.mul(9).div(10000);
const flashloanTotal = amountWETHtoSwap.add(flashloanPremium);
// User will swap liquidity aEth to aDai
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount]
);
const params = buildParaSwapLiquiditySwapParams(
dai.address,
expectedDaiAmount,
0,
mockAugustusCalldata,
mockAugustus.address,
0,
0,
0,
'0x0000000000000000000000000000000000000000000000000000000000000000',
'0x0000000000000000000000000000000000000000000000000000000000000000'
);
await expect(
paraswapLiquiditySwapAdapter
.connect(user)
.executeOperation(
[weth.address],
[amountWETHtoSwap],
[0],
userAddress,
params
)
).to.be.revertedWith('CALLER_MUST_BE_LENDING_POOL');
});
it('should work correctly with tokens of different decimals', async () => {
const {
users,
usdc,
oracle,
dai,
aDai,
paraswapLiquiditySwapAdapter,
pool,
deployer,
} = testEnv;
const user = users[0].signer;
const userAddress = users[0].address;
const amountUSDCtoSwap = await convertToCurrencyDecimals(usdc.address, '10');
const liquidity = await convertToCurrencyDecimals(usdc.address, '20000');
const flashloanPremium = amountUSDCtoSwap.mul(9).div(10000);
const flashloanTotal = amountUSDCtoSwap.add(flashloanPremium);
// Provider liquidity
await usdc.mint(liquidity);
await usdc.approve(pool.address, liquidity);
await pool.deposit(usdc.address, liquidity, deployer.address, 0);
// Make a deposit for user
await usdc.connect(user).mint(flashloanTotal);
await usdc.connect(user).approve(pool.address, flashloanTotal);
await pool.connect(user).deposit(usdc.address, flashloanTotal, userAddress, 0);
const usdcPrice = await oracle.getAssetPrice(usdc.address);
const daiPrice = await oracle.getAssetPrice(dai.address);
const collateralDecimals = (await usdc.decimals()).toString();
const principalDecimals = (await dai.decimals()).toString();
const expectedDaiAmount = await convertToCurrencyDecimals(
dai.address,
new BigNumber(amountUSDCtoSwap.toString())
.times(
new BigNumber(usdcPrice.toString()).times(new BigNumber(10).pow(principalDecimals))
)
.div(
new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals))
)
.div(new BigNumber(10).pow(principalDecimals))
.toFixed(0)
);
await mockAugustus.expectSwap(usdc.address, dai.address, amountUSDCtoSwap, amountUSDCtoSwap, expectedDaiAmount);
const aUsdcData = await pool.getReserveData(usdc.address);
const aUsdc = await getContract<AToken>(eContractid.AToken, aUsdcData.aTokenAddress);
// User will swap liquidity aUsdc to aDai
const userAUsdcBalanceBefore = await aUsdc.balanceOf(userAddress);
await aUsdc.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[usdc.address, dai.address, amountUSDCtoSwap, expectedDaiAmount]
);
const params = buildParaSwapLiquiditySwapParams(
dai.address,
expectedDaiAmount,
0,
mockAugustusCalldata,
mockAugustus.address,
0,
0,
0,
'0x0000000000000000000000000000000000000000000000000000000000000000',
'0x0000000000000000000000000000000000000000000000000000000000000000'
);
await expect(
pool
.connect(user)
.flashLoan(
paraswapLiquiditySwapAdapter.address,
[usdc.address],
[amountUSDCtoSwap],
[0],
userAddress,
params,
0
)
)
.to.emit(paraswapLiquiditySwapAdapter, 'Swapped')
.withArgs(usdc.address, dai.address, amountUSDCtoSwap, expectedDaiAmount);
const adapterUsdcBalance = await usdc.balanceOf(paraswapLiquiditySwapAdapter.address);
const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address);
const userADaiBalance = await aDai.balanceOf(userAddress);
const userAUsdcBalance = await aUsdc.balanceOf(userAddress);
// N.B. will get some portion of flashloan premium back from the pool
expect(adapterUsdcBalance).to.be.eq(Zero);
expect(adapterDaiBalance).to.be.eq(Zero);
expect(userADaiBalance).to.be.eq(expectedDaiAmount);
expect(userAUsdcBalance).to.be.gte(userAUsdcBalanceBefore.sub(flashloanTotal));
expect(userAUsdcBalance).to.be.lte(userAUsdcBalanceBefore.sub(amountUSDCtoSwap));
});
it('should revert when min amount to receive exceeds the max slippage amount', async () => {
const {
users,
weth,
oracle,
dai,
aWETH,
pool,
paraswapLiquiditySwapAdapter,
} = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
const smallExpectedDaiAmount = expectedDaiAmount.div(2);
const flashloanPremium = amountWETHtoSwap.mul(9).div(10000);
const flashloanTotal = amountWETHtoSwap.add(flashloanPremium);
// User will swap liquidity aEth to aDai
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount]
);
const params = buildParaSwapLiquiditySwapParams(
dai.address,
smallExpectedDaiAmount,
0,
mockAugustusCalldata,
mockAugustus.address,
0,
0,
0,
'0x0000000000000000000000000000000000000000000000000000000000000000',
'0x0000000000000000000000000000000000000000000000000000000000000000'
);
await expect(
pool
.connect(user)
.flashLoan(
paraswapLiquiditySwapAdapter.address,
[weth.address],
[amountWETHtoSwap],
[0],
userAddress,
params,
0
)
).to.be.revertedWith('MIN_AMOUNT_EXCEEDS_MAX_SLIPPAGE');
});
it('should revert when min amount to receive exceeds the max slippage amount (with tokens of different decimals)', async () => {
const {
users,
usdc,
oracle,
dai,
paraswapLiquiditySwapAdapter,
pool,
deployer,
} = testEnv;
const user = users[0].signer;
const userAddress = users[0].address;
const amountUSDCtoSwap = await convertToCurrencyDecimals(usdc.address, '10');
const liquidity = await convertToCurrencyDecimals(usdc.address, '20000');
const flashloanPremium = amountUSDCtoSwap.mul(9).div(10000);
const flashloanTotal = amountUSDCtoSwap.add(flashloanPremium);
// Provider liquidity
await usdc.mint(liquidity);
await usdc.approve(pool.address, liquidity);
await pool.deposit(usdc.address, liquidity, deployer.address, 0);
// Make a deposit for user
await usdc.connect(user).mint(flashloanTotal);
await usdc.connect(user).approve(pool.address, flashloanTotal);
await pool.connect(user).deposit(usdc.address, flashloanTotal, userAddress, 0);
const usdcPrice = await oracle.getAssetPrice(usdc.address);
const daiPrice = await oracle.getAssetPrice(dai.address);
const collateralDecimals = (await usdc.decimals()).toString();
const principalDecimals = (await dai.decimals()).toString();
const expectedDaiAmount = await convertToCurrencyDecimals(
dai.address,
new BigNumber(amountUSDCtoSwap.toString())
.times(
new BigNumber(usdcPrice.toString()).times(new BigNumber(10).pow(principalDecimals))
)
.div(
new BigNumber(daiPrice.toString()).times(new BigNumber(10).pow(collateralDecimals))
)
.div(new BigNumber(10).pow(principalDecimals))
.toFixed(0)
);
await mockAugustus.expectSwap(usdc.address, dai.address, amountUSDCtoSwap, amountUSDCtoSwap, expectedDaiAmount);
const smallExpectedDaiAmount = expectedDaiAmount.div(2);
const aUsdcData = await pool.getReserveData(usdc.address);
const aUsdc = await getContract<AToken>(eContractid.AToken, aUsdcData.aTokenAddress);
// User will swap liquidity aUsdc to aDai
await aUsdc.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[usdc.address, dai.address, amountUSDCtoSwap, expectedDaiAmount]
);
const params = buildParaSwapLiquiditySwapParams(
dai.address,
smallExpectedDaiAmount,
0,
mockAugustusCalldata,
mockAugustus.address,
0,
0,
0,
'0x0000000000000000000000000000000000000000000000000000000000000000',
'0x0000000000000000000000000000000000000000000000000000000000000000'
);
await expect(
pool
.connect(user)
.flashLoan(
paraswapLiquiditySwapAdapter.address,
[usdc.address],
[amountUSDCtoSwap],
[0],
userAddress,
params,
0
)
).to.be.revertedWith('MIN_AMOUNT_EXCEEDS_MAX_SLIPPAGE');
});
it('should correctly swap tokens all the balance', async () => {
const {
users,
weth,
oracle,
dai,
aDai,
aWETH,
pool,
paraswapLiquiditySwapAdapter,
} = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
const bigAmountToSwap = parseEther('11');
const flashloanPremium = bigAmountToSwap.mul(9).div(10000);
const flashloanTotal = bigAmountToSwap.add(flashloanPremium);
// Remove other balance
await aWETH.connect(user).transfer(users[1].address, parseEther('90').sub(flashloanPremium));
// User will swap liquidity aEth to aDai
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
expect(userAEthBalanceBefore).to.be.eq(amountWETHtoSwap.add(flashloanPremium));
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, bigAmountToSwap, expectedDaiAmount]
);
const params = buildParaSwapLiquiditySwapParams(
dai.address,
expectedDaiAmount,
4 + 2*32,
mockAugustusCalldata,
mockAugustus.address,
0,
0,
0,
'0x0000000000000000000000000000000000000000000000000000000000000000',
'0x0000000000000000000000000000000000000000000000000000000000000000'
);
await expect(
pool
.connect(user)
.flashLoan(
paraswapLiquiditySwapAdapter.address,
[weth.address],
[bigAmountToSwap],
[0],
userAddress,
params,
0
)
)
.to.emit(paraswapLiquiditySwapAdapter, 'Swapped')
.withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount);
const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address);
const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address);
const userADaiBalance = await aDai.balanceOf(userAddress);
const userAEthBalance = await aWETH.balanceOf(userAddress);
expect(adapterWethBalance).to.be.eq(Zero);
expect(adapterDaiBalance).to.be.eq(Zero);
expect(userADaiBalance).to.be.eq(expectedDaiAmount);
expect(userAEthBalance).to.be.eq(Zero);
});
it('should correctly swap tokens all the balance using permit', async () => {
const {
users,
weth,
oracle,
dai,
aDai,
aWETH,
pool,
paraswapLiquiditySwapAdapter,
} = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
const bigAmountToSwap = parseEther('11');
const flashloanPremium = bigAmountToSwap.mul(9).div(10000);
const flashloanTotal = bigAmountToSwap.add(flashloanPremium);
// Remove other balance
await aWETH.connect(user).transfer(users[1].address, parseEther('90').sub(flashloanPremium));
// User will swap liquidity aEth to aDai
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
expect(userAEthBalanceBefore).to.be.eq(amountWETHtoSwap.add(flashloanPremium));
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,
paraswapLiquiditySwapAdapter.address,
nonce,
deadline,
flashloanTotal.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);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, bigAmountToSwap, expectedDaiAmount]
);
const params = buildParaSwapLiquiditySwapParams(
dai.address,
expectedDaiAmount,
4 + 2*32,
mockAugustusCalldata,
mockAugustus.address,
flashloanTotal,
deadline,
v,
r,
s
);
await expect(
pool
.connect(user)
.flashLoan(
paraswapLiquiditySwapAdapter.address,
[weth.address],
[bigAmountToSwap],
[0],
userAddress,
params,
0
)
)
.to.emit(paraswapLiquiditySwapAdapter, 'Swapped')
.withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount);
const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address);
const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address);
const userADaiBalance = await aDai.balanceOf(userAddress);
const userAEthBalance = await aWETH.balanceOf(userAddress);
expect(adapterWethBalance).to.be.eq(Zero);
expect(adapterDaiBalance).to.be.eq(Zero);
expect(userADaiBalance).to.be.eq(expectedDaiAmount);
expect(userAEthBalance).to.be.eq(Zero);
});
it('should revert trying to swap all the balance with insufficient amount', async () => {
const {
users,
weth,
oracle,
dai,
aWETH,
pool,
paraswapLiquiditySwapAdapter,
} = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
const smallAmountToSwap = parseEther('9');
const flashloanPremium = smallAmountToSwap.mul(9).div(10000);
const flashloanTotal = smallAmountToSwap.add(flashloanPremium);
// Remove other balance
await aWETH.connect(user).transfer(users[1].address, parseEther('90').sub(flashloanPremium));
// User will swap liquidity aEth to aDai
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
expect(userAEthBalanceBefore).to.be.eq(amountWETHtoSwap.add(flashloanPremium));
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, smallAmountToSwap, expectedDaiAmount]
);
const params = buildParaSwapLiquiditySwapParams(
dai.address,
expectedDaiAmount,
4 + 2*32,
mockAugustusCalldata,
mockAugustus.address,
0,
0,
0,
'0x0000000000000000000000000000000000000000000000000000000000000000',
'0x0000000000000000000000000000000000000000000000000000000000000000'
);
await expect(
pool
.connect(user)
.flashLoan(
paraswapLiquiditySwapAdapter.address,
[weth.address],
[smallAmountToSwap],
[0],
userAddress,
params,
0
)
).to.be.revertedWith('INSUFFICIENT_AMOUNT_TO_SWAP');
});
it('should revert trying to swap more than balance', async () => {
const {
users,
weth,
oracle,
dai,
aWETH,
pool,
paraswapLiquiditySwapAdapter,
} = testEnv;
const user = users[0].signer;
const userAddress = users[0].address;
const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '101');
const daiPrice = await oracle.getAssetPrice(dai.address);
const expectedDaiAmount = await convertToCurrencyDecimals(
dai.address,
new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
);
await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
const flashloanPremium = amountWETHtoSwap.mul(9).div(10000);
const flashloanTotal = amountWETHtoSwap.add(flashloanPremium);
// User will swap liquidity aEth to aDai
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount]
);
const params = buildParaSwapLiquiditySwapParams(
dai.address,
expectedDaiAmount,
0,
mockAugustusCalldata,
mockAugustus.address,
0,
0,
0,
'0x0000000000000000000000000000000000000000000000000000000000000000',
'0x0000000000000000000000000000000000000000000000000000000000000000'
);
await expect(
pool
.connect(user)
.flashLoan(
paraswapLiquiditySwapAdapter.address,
[weth.address],
[amountWETHtoSwap],
[0],
userAddress,
params,
0
)
).to.be.revertedWith('INSUFFICIENT_ATOKEN_BALANCE');
});
it('should not touch any token balance already in the adapter', async () => {
const {
users,
weth,
oracle,
dai,
aDai,
aWETH,
pool,
paraswapLiquiditySwapAdapter,
} = testEnv;
const user = users[0].signer;
const userAddress = users[0].address;
// Put token balances in the adapter
const adapterWethBalanceBefore = parseEther('123');
await weth.mint(adapterWethBalanceBefore);
await weth.transfer(paraswapLiquiditySwapAdapter.address, adapterWethBalanceBefore);
const adapterDaiBalanceBefore = parseEther('234');
await dai.mint(adapterDaiBalanceBefore);
await dai.transfer(paraswapLiquiditySwapAdapter.address, adapterDaiBalanceBefore);
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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
const flashloanPremium = amountWETHtoSwap.mul(9).div(10000);
const flashloanTotal = amountWETHtoSwap.add(flashloanPremium);
// User will swap liquidity aEth to aDai
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount]
);
const params = buildParaSwapLiquiditySwapParams(
dai.address,
expectedDaiAmount,
0,
mockAugustusCalldata,
mockAugustus.address,
0,
0,
0,
'0x0000000000000000000000000000000000000000000000000000000000000000',
'0x0000000000000000000000000000000000000000000000000000000000000000'
);
await expect(
pool
.connect(user)
.flashLoan(
paraswapLiquiditySwapAdapter.address,
[weth.address],
[amountWETHtoSwap],
[0],
userAddress,
params,
0
)
)
.to.emit(paraswapLiquiditySwapAdapter, 'Swapped')
.withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount);
const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address);
const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address);
const userADaiBalance = await aDai.balanceOf(userAddress);
const userAEthBalance = await aWETH.balanceOf(userAddress);
// N.B. will get some portion of flashloan premium back from the pool
expect(adapterWethBalance).to.be.eq(adapterWethBalanceBefore);
expect(adapterDaiBalance).to.be.eq(adapterDaiBalanceBefore);
expect(userADaiBalance).to.be.eq(expectedDaiAmount);
expect(userAEthBalance).to.be.gte(userAEthBalanceBefore.sub(flashloanTotal));
expect(userAEthBalance).to.be.lte(userAEthBalanceBefore.sub(amountWETHtoSwap));
});
});
describe('executeOperation with borrowing', () => {
beforeEach(async () => {
const { users, weth, dai, pool, deployer } = testEnv;
const userAddress = users[0].address;
const borrower = users[1].signer;
const borrowerAddress = users[1].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);
await weth.mint(parseEther('10000'));
await weth.approve(pool.address, parseEther('10000'));
await pool.deposit(weth.address, parseEther('10000'), deployer.address, 0);
// Make a deposit for user
await weth.mint(parseEther('100'));
await weth.approve(pool.address, parseEther('100'));
await pool.deposit(weth.address, parseEther('100'), userAddress, 0);
// Add borrowing
const collateralAmount = parseEther('10000000');
await dai.mint(collateralAmount);
await dai.approve(pool.address, collateralAmount);
await pool.deposit(dai.address, collateralAmount, borrowerAddress, 0);
await pool.connect(borrower).borrow(weth.address, parseEther('5000'), 2, 0, borrowerAddress);
});
it('should correctly swap tokens and deposit the out tokens in the pool', async () => {
const {
users,
weth,
oracle,
dai,
aDai,
aWETH,
pool,
paraswapLiquiditySwapAdapter,
} = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
const flashloanPremium = amountWETHtoSwap.mul(9).div(10000);
const flashloanTotal = amountWETHtoSwap.add(flashloanPremium);
// User will swap liquidity aEth to aDai
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount]
);
const params = buildParaSwapLiquiditySwapParams(
dai.address,
expectedDaiAmount,
0,
mockAugustusCalldata,
mockAugustus.address,
0,
0,
0,
'0x0000000000000000000000000000000000000000000000000000000000000000',
'0x0000000000000000000000000000000000000000000000000000000000000000'
);
await expect(
pool
.connect(user)
.flashLoan(
paraswapLiquiditySwapAdapter.address,
[weth.address],
[amountWETHtoSwap],
[0],
userAddress,
params,
0
)
)
.to.emit(paraswapLiquiditySwapAdapter, 'Swapped')
.withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount);
const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address);
const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address);
const userADaiBalance = await aDai.balanceOf(userAddress);
const userAEthBalance = await aWETH.balanceOf(userAddress);
// N.B. will get some portion of flashloan premium back from the pool
expect(adapterWethBalance).to.be.eq(Zero);
expect(adapterDaiBalance).to.be.eq(Zero);
expect(userADaiBalance).to.be.eq(expectedDaiAmount);
expect(userAEthBalance).to.be.gt(userAEthBalanceBefore.sub(flashloanTotal));
expect(userAEthBalance).to.be.lt(userAEthBalanceBefore.mul(10001).div(10000).sub(amountWETHtoSwap));
});
it('should correctly swap tokens using permit', async () => {
const {
users,
weth,
oracle,
dai,
aDai,
aWETH,
pool,
paraswapLiquiditySwapAdapter,
} = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
const flashloanPremium = amountWETHtoSwap.mul(9).div(10000);
const flashloanTotal = amountWETHtoSwap.add(flashloanPremium);
// User will swap liquidity aEth to aDai
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,
paraswapLiquiditySwapAdapter.address,
nonce,
deadline,
flashloanTotal.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);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount]
);
const params = buildParaSwapLiquiditySwapParams(
dai.address,
expectedDaiAmount,
0,
mockAugustusCalldata,
mockAugustus.address,
flashloanTotal,
deadline,
v,
r,
s
);
await expect(
pool
.connect(user)
.flashLoan(
paraswapLiquiditySwapAdapter.address,
[weth.address],
[amountWETHtoSwap],
[0],
userAddress,
params,
0
)
)
.to.emit(paraswapLiquiditySwapAdapter, 'Swapped')
.withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount);
const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address);
const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address);
const userADaiBalance = await aDai.balanceOf(userAddress);
const userAEthBalance = await aWETH.balanceOf(userAddress);
// N.B. will get some portion of flashloan premium back from the pool
expect(adapterWethBalance).to.be.eq(Zero);
expect(adapterDaiBalance).to.be.eq(Zero);
expect(userADaiBalance).to.be.eq(expectedDaiAmount);
expect(userAEthBalance).to.be.gt(userAEthBalanceBefore.sub(flashloanTotal));
expect(userAEthBalance).to.be.lt(userAEthBalanceBefore.mul(10001).div(10000).sub(amountWETHtoSwap));
});
it('should correctly swap tokens all the balance', async () => {
const {
users,
weth,
oracle,
dai,
aDai,
aWETH,
pool,
paraswapLiquiditySwapAdapter,
} = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap.add(1), amountWETHtoSwap.mul(10001).div(10000), expectedDaiAmount);
const bigAmountToSwap = parseEther('11');
const flashloanPremium = bigAmountToSwap.mul(9).div(10000);
const flashloanTotal = bigAmountToSwap.add(flashloanPremium);
// Remove other balance
await aWETH.connect(user).transfer(users[1].address, parseEther('90').sub(flashloanPremium));
// User will swap liquidity aEth to aDai
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, flashloanTotal);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, bigAmountToSwap, expectedDaiAmount]
);
const params = buildParaSwapLiquiditySwapParams(
dai.address,
expectedDaiAmount,
4 + 2*32,
mockAugustusCalldata,
mockAugustus.address,
0,
0,
0,
'0x0000000000000000000000000000000000000000000000000000000000000000',
'0x0000000000000000000000000000000000000000000000000000000000000000'
);
await expect(
pool
.connect(user)
.flashLoan(
paraswapLiquiditySwapAdapter.address,
[weth.address],
[bigAmountToSwap],
[0],
userAddress,
params,
0
)
).to.emit(paraswapLiquiditySwapAdapter, 'Swapped');
const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address);
const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address);
const userADaiBalance = await aDai.balanceOf(userAddress);
const userAEthBalance = await aWETH.balanceOf(userAddress);
expect(adapterWethBalance).to.be.eq(Zero);
expect(adapterDaiBalance).to.be.eq(Zero);
expect(userADaiBalance).to.be.eq(expectedDaiAmount);
expect(userAEthBalance).to.be.eq(Zero);
});
it('should correctly swap tokens all the balance using permit', async () => {
const {
users,
weth,
oracle,
dai,
aDai,
aWETH,
pool,
paraswapLiquiditySwapAdapter,
} = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap.add(1), amountWETHtoSwap.mul(10001).div(10000), expectedDaiAmount);
const bigAmountToSwap = parseEther('11');
const flashloanPremium = bigAmountToSwap.mul(9).div(10000);
const flashloanTotal = bigAmountToSwap.add(flashloanPremium);
// Remove other balance
await aWETH.connect(user).transfer(users[1].address, parseEther('90').sub(flashloanPremium));
// User will swap liquidity aEth to aDai
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,
paraswapLiquiditySwapAdapter.address,
nonce,
deadline,
flashloanTotal.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);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, bigAmountToSwap, expectedDaiAmount]
);
const params = buildParaSwapLiquiditySwapParams(
dai.address,
expectedDaiAmount,
4 + 2*32,
mockAugustusCalldata,
mockAugustus.address,
flashloanTotal,
deadline,
v,
r,
s
);
await expect(
pool
.connect(user)
.flashLoan(
paraswapLiquiditySwapAdapter.address,
[weth.address],
[bigAmountToSwap],
[0],
userAddress,
params,
0
)
).to.emit(paraswapLiquiditySwapAdapter, 'Swapped');
const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address);
const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address);
const userADaiBalance = await aDai.balanceOf(userAddress);
const userAEthBalance = await aWETH.balanceOf(userAddress);
expect(adapterWethBalance).to.be.eq(Zero);
expect(adapterDaiBalance).to.be.eq(Zero);
expect(userADaiBalance).to.be.eq(expectedDaiAmount);
expect(userAEthBalance).to.be.eq(Zero);
});
});
describe('swapAndDeposit', () => {
beforeEach(async () => {
const { users, weth, dai, 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);
await weth.mint(parseEther('10000'));
await weth.approve(pool.address, parseEther('10000'));
await pool.deposit(weth.address, parseEther('10000'), deployer.address, 0);
// Make a deposit for user
await weth.mint(parseEther('100'));
await weth.approve(pool.address, parseEther('100'));
await pool.deposit(weth.address, parseEther('100'), userAddress, 0);
});
it('should correctly swap tokens and deposit the out tokens in the pool', async () => {
const { users, weth, oracle, dai, aDai, aWETH, paraswapLiquiditySwapAdapter } = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
// User will swap liquidity aEth to aDai
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, amountWETHtoSwap);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount]
);
await expect(
paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
weth.address,
dai.address,
amountWETHtoSwap,
expectedDaiAmount,
0,
mockAugustusCalldata,
mockAugustus.address,
{
amount: 0,
deadline: 0,
v: 0,
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
}
)
)
.to.emit(paraswapLiquiditySwapAdapter, 'Swapped')
.withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount);
const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address);
const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address);
const userADaiBalance = await aDai.balanceOf(userAddress);
const userAEthBalance = await aWETH.balanceOf(userAddress);
expect(adapterWethBalance).to.be.eq(Zero);
expect(adapterDaiBalance).to.be.eq(Zero);
expect(userADaiBalance).to.be.eq(expectedDaiAmount);
expect(userAEthBalance).to.be.eq(userAEthBalanceBefore.sub(amountWETHtoSwap));
});
it('should correctly swap tokens using permit', async () => {
const { users, weth, oracle, dai, aDai, aWETH, paraswapLiquiditySwapAdapter } = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
// User will swap liquidity aEth to aDai
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,
paraswapLiquiditySwapAdapter.address,
nonce,
deadline,
amountWETHtoSwap.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);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount]
);
await expect(
paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
weth.address,
dai.address,
amountWETHtoSwap,
expectedDaiAmount,
0,
mockAugustusCalldata,
mockAugustus.address,
{
amount: amountWETHtoSwap,
deadline,
v,
r,
s,
}
)
)
.to.emit(paraswapLiquiditySwapAdapter, 'Swapped')
.withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount);
const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address);
const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address);
const userADaiBalance = await aDai.balanceOf(userAddress);
const userAEthBalance = await aWETH.balanceOf(userAddress);
expect(adapterWethBalance).to.be.eq(Zero);
expect(adapterDaiBalance).to.be.eq(Zero);
expect(userADaiBalance).to.be.eq(expectedDaiAmount);
expect(userAEthBalance).to.be.eq(userAEthBalanceBefore.sub(amountWETHtoSwap));
});
it('should revert when trying to swap more than balance', async () => {
const { users, weth, oracle, dai, aWETH, paraswapLiquiditySwapAdapter } = testEnv;
const user = users[0].signer;
const userAddress = users[0].address;
const amountWETHtoSwap = (await convertToCurrencyDecimals(weth.address, '100')).add(1);
const daiPrice = await oracle.getAssetPrice(dai.address);
const expectedDaiAmount = await convertToCurrencyDecimals(
dai.address,
new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
);
await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
// User will swap liquidity aEth to aDai
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, amountWETHtoSwap);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount]
);
await expect(
paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
weth.address,
dai.address,
amountWETHtoSwap,
expectedDaiAmount,
0,
mockAugustusCalldata,
mockAugustus.address,
{
amount: 0,
deadline: 0,
v: 0,
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
}
)
).to.be.revertedWith('SafeERC20: low-level call failed');
});
it('should revert when trying to swap more than allowance', async () => {
const { users, weth, oracle, dai, aWETH, paraswapLiquiditySwapAdapter } = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
// User will swap liquidity aEth to aDai
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, amountWETHtoSwap.sub(1));
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount]
);
await expect(
paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
weth.address,
dai.address,
amountWETHtoSwap,
expectedDaiAmount,
0,
mockAugustusCalldata,
mockAugustus.address,
{
amount: 0,
deadline: 0,
v: 0,
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
}
)
).to.be.revertedWith('SafeERC20: low-level call failed');
});
it('should revert when min amount to receive exceeds the max slippage amount', async () => {
const { users, weth, oracle, dai, aWETH, paraswapLiquiditySwapAdapter } = testEnv;
const user = users[0].signer;
const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
const daiPrice = await oracle.getAssetPrice(dai.address);
const expectedDaiAmount = await convertToCurrencyDecimals(
dai.address,
new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
);
await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
const smallExpectedDaiAmount = expectedDaiAmount.div(2);
// User will swap liquidity aEth to aDai
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, amountWETHtoSwap);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount]
);
await expect(
paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
weth.address,
dai.address,
amountWETHtoSwap,
smallExpectedDaiAmount,
0,
mockAugustusCalldata,
mockAugustus.address,
{
amount: 0,
deadline: 0,
v: 0,
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
}
)
).to.be.revertedWith('MIN_AMOUNT_EXCEEDS_MAX_SLIPPAGE');
});
it('should revert if wrong address used for Augustus', async () => {
const { users, weth, oracle, dai, aWETH, paraswapLiquiditySwapAdapter } = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
// User will swap liquidity aEth to aDai
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, amountWETHtoSwap);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount]
);
await expect(
paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
weth.address,
dai.address,
amountWETHtoSwap,
expectedDaiAmount,
0,
mockAugustusCalldata,
oracle.address, // using arbitrary contract instead of mock Augustus
{
amount: 0,
deadline: 0,
v: 0,
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
}
)
).to.be.revertedWith('INVALID_AUGUSTUS');
});
it('should bubble up errors from Augustus', async () => {
const { users, weth, oracle, dai, aWETH, paraswapLiquiditySwapAdapter } = testEnv;
const user = users[0].signer;
const amountWETHtoSwap = await convertToCurrencyDecimals(weth.address, '10');
const daiPrice = await oracle.getAssetPrice(dai.address);
const expectedDaiAmount = await convertToCurrencyDecimals(
dai.address,
new BigNumber(amountWETHtoSwap.toString()).div(daiPrice.toString()).toFixed(0)
);
await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
// User will swap liquidity aEth to aDai
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, amountWETHtoSwap);
// Add 1 to expected amount so it will fail
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount.add(1)]
);
await expect(
paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
weth.address,
dai.address,
amountWETHtoSwap,
expectedDaiAmount,
0,
mockAugustusCalldata,
mockAugustus.address,
{
amount: 0,
deadline: 0,
v: 0,
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
}
)
).to.be.revertedWith('Received amount of tokens are less than expected');
});
it('should revert if Augustus swaps for less than minimum to receive', async () => {
const { users, weth, oracle, dai, aWETH, paraswapLiquiditySwapAdapter } = 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 actualDaiAmount = expectedDaiAmount.sub(1);
await mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, actualDaiAmount);
// User will swap liquidity aEth to aDai
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, amountWETHtoSwap);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, amountWETHtoSwap, actualDaiAmount]
);
await expect(
paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
weth.address,
dai.address,
amountWETHtoSwap,
expectedDaiAmount,
0,
mockAugustusCalldata,
mockAugustus.address,
{
amount: 0,
deadline: 0,
v: 0,
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
}
)
).to.be.revertedWith('INSUFFICIENT_AMOUNT_RECEIVED');
});
it("should revert if Augustus doesn't swap correct amount", async () => {
const { users, weth, oracle, dai, aWETH, paraswapLiquiditySwapAdapter } = 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 augustusSwapAmount = amountWETHtoSwap.sub(1);
await mockAugustus.expectSwap(weth.address, dai.address, augustusSwapAmount, augustusSwapAmount, expectedDaiAmount);
// User will swap liquidity aEth to aDai
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, amountWETHtoSwap);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, augustusSwapAmount, expectedDaiAmount]
);
await expect(
paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
weth.address,
dai.address,
amountWETHtoSwap,
expectedDaiAmount,
0,
mockAugustusCalldata,
mockAugustus.address,
{
amount: 0,
deadline: 0,
v: 0,
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
}
)
).to.be.revertedWith('WRONG_BALANCE_AFTER_SWAP');
});
it('should correctly swap all the balance when using a bigger amount', async () => {
const { users, weth, oracle, dai, aDai, aWETH, paraswapLiquiditySwapAdapter } = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
// Remove other balance
await aWETH.connect(user).transfer(users[1].address, parseEther('90'));
// User will swap liquidity aEth to aDai
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
expect(userAEthBalanceBefore).to.be.eq(amountWETHtoSwap);
const bigAmountToSwap = parseEther('11');
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, bigAmountToSwap);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, bigAmountToSwap, expectedDaiAmount]
);
await expect(
paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
weth.address,
dai.address,
bigAmountToSwap,
expectedDaiAmount,
4 + 2*32,
mockAugustusCalldata,
mockAugustus.address,
{
amount: 0,
deadline: 0,
v: 0,
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
}
)
)
.to.emit(paraswapLiquiditySwapAdapter, 'Swapped')
.withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount);
const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address);
const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address);
const userADaiBalance = await aDai.balanceOf(userAddress);
const userAEthBalance = await aWETH.balanceOf(userAddress);
expect(adapterWethBalance).to.be.eq(Zero);
expect(adapterDaiBalance).to.be.eq(Zero);
expect(userADaiBalance).to.be.eq(expectedDaiAmount);
expect(userAEthBalance).to.be.eq(Zero);
});
it('should correctly swap all the balance when using permit', async () => {
const { users, weth, oracle, dai, aDai, aWETH, paraswapLiquiditySwapAdapter } = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
// Remove other balance
await aWETH.connect(user).transfer(users[1].address, parseEther('90'));
// User will swap liquidity aEth to aDai
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
expect(userAEthBalanceBefore).to.be.eq(amountWETHtoSwap);
const bigAmountToSwap = parseEther('11');
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,
paraswapLiquiditySwapAdapter.address,
nonce,
deadline,
bigAmountToSwap.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);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, bigAmountToSwap, expectedDaiAmount]
);
await expect(
paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
weth.address,
dai.address,
bigAmountToSwap,
expectedDaiAmount,
4 + 2*32,
mockAugustusCalldata,
mockAugustus.address,
{
amount: bigAmountToSwap,
deadline,
v,
r,
s,
}
)
)
.to.emit(paraswapLiquiditySwapAdapter, 'Swapped')
.withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount);
const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address);
const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address);
const userADaiBalance = await aDai.balanceOf(userAddress);
const userAEthBalance = await aWETH.balanceOf(userAddress);
expect(adapterWethBalance).to.be.eq(Zero);
expect(adapterDaiBalance).to.be.eq(Zero);
expect(userADaiBalance).to.be.eq(expectedDaiAmount);
expect(userAEthBalance).to.be.eq(Zero);
});
it('should revert trying to swap all the balance when using a smaller amount', async () => {
const { users, weth, oracle, dai, aWETH, paraswapLiquiditySwapAdapter } = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
// Remove other balance
await aWETH.connect(user).transfer(users[1].address, parseEther('90'));
// User will swap liquidity aEth to aDai
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
expect(userAEthBalanceBefore).to.be.eq(amountWETHtoSwap);
const smallAmountToSwap = parseEther('10').sub(1);
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, smallAmountToSwap);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, smallAmountToSwap, expectedDaiAmount]
);
await expect(
paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
weth.address,
dai.address,
smallAmountToSwap,
expectedDaiAmount,
4 + 2*32,
mockAugustusCalldata,
mockAugustus.address,
{
amount: 0,
deadline: 0,
v: 0,
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
}
)
).to.be.revertedWith('INSUFFICIENT_AMOUNT_TO_SWAP');
});
it('should not touch any token balance already in the adapter', async () => {
const { users, weth, oracle, dai, aDai, aWETH, paraswapLiquiditySwapAdapter } = testEnv;
const user = users[0].signer;
const userAddress = users[0].address;
// Put token balances in the adapter
const adapterWethBalanceBefore = parseEther('123');
await weth.mint(adapterWethBalanceBefore);
await weth.transfer(paraswapLiquiditySwapAdapter.address, adapterWethBalanceBefore);
const adapterDaiBalanceBefore = parseEther('234');
await dai.mint(adapterDaiBalanceBefore);
await dai.transfer(paraswapLiquiditySwapAdapter.address, adapterDaiBalanceBefore);
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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
// User will swap liquidity aEth to aDai
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, amountWETHtoSwap);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount]
);
await expect(
paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
weth.address,
dai.address,
amountWETHtoSwap,
expectedDaiAmount,
0,
mockAugustusCalldata,
mockAugustus.address,
{
amount: 0,
deadline: 0,
v: 0,
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
}
)
)
.to.emit(paraswapLiquiditySwapAdapter, 'Swapped')
.withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount);
const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address);
const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address);
const userADaiBalance = await aDai.balanceOf(userAddress);
const userAEthBalance = await aWETH.balanceOf(userAddress);
expect(adapterWethBalance).to.be.eq(adapterWethBalanceBefore);
expect(adapterDaiBalance).to.be.eq(adapterDaiBalanceBefore);
expect(userADaiBalance).to.be.eq(expectedDaiAmount);
expect(userAEthBalance).to.be.eq(userAEthBalanceBefore.sub(amountWETHtoSwap));
});
});
describe('swapAndDeposit with borrowing', () => {
beforeEach(async () => {
const { users, weth, dai, pool, deployer } = testEnv;
const userAddress = users[0].address;
const borrower = users[1].signer;
const borrowerAddress = users[1].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);
await weth.mint(parseEther('10000'));
await weth.approve(pool.address, parseEther('10000'));
await pool.deposit(weth.address, parseEther('10000'), deployer.address, 0);
// Make a deposit for user
await weth.mint(parseEther('100'));
await weth.approve(pool.address, parseEther('100'));
await pool.deposit(weth.address, parseEther('100'), userAddress, 0);
// Add borrowing
const collateralAmount = parseEther('10000000');
await dai.mint(collateralAmount);
await dai.approve(pool.address, collateralAmount);
await pool.deposit(dai.address, collateralAmount, borrowerAddress, 0);
await pool.connect(borrower).borrow(weth.address, parseEther('5000'), 2, 0, borrowerAddress);
});
it('should correctly swap tokens and deposit the out tokens in the pool', async () => {
const { users, weth, oracle, dai, aDai, aWETH, paraswapLiquiditySwapAdapter } = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
// User will swap liquidity aEth to aDai
const userAEthBalanceBefore = await aWETH.balanceOf(userAddress);
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, amountWETHtoSwap);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount]
);
await expect(
paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
weth.address,
dai.address,
amountWETHtoSwap,
expectedDaiAmount,
0,
mockAugustusCalldata,
mockAugustus.address,
{
amount: 0,
deadline: 0,
v: 0,
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
}
)
)
.to.emit(paraswapLiquiditySwapAdapter, 'Swapped')
.withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount);
const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address);
const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address);
const userADaiBalance = await aDai.balanceOf(userAddress);
const userAEthBalance = await aWETH.balanceOf(userAddress);
expect(adapterWethBalance).to.be.eq(Zero);
expect(adapterDaiBalance).to.be.eq(Zero);
expect(userADaiBalance).to.be.eq(expectedDaiAmount);
expect(userAEthBalance).to.be.gt(userAEthBalanceBefore.sub(amountWETHtoSwap));
expect(userAEthBalance).to.be.lt(userAEthBalanceBefore.mul(10001).div(10000).sub(amountWETHtoSwap));
});
it('should correctly swap tokens using permit', async () => {
const { users, weth, oracle, dai, aDai, aWETH, paraswapLiquiditySwapAdapter } = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap, amountWETHtoSwap, expectedDaiAmount);
// User will swap liquidity aEth to aDai
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,
paraswapLiquiditySwapAdapter.address,
nonce,
deadline,
amountWETHtoSwap.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);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount]
);
await expect(
paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
weth.address,
dai.address,
amountWETHtoSwap,
expectedDaiAmount,
0,
mockAugustusCalldata,
mockAugustus.address,
{
amount: amountWETHtoSwap,
deadline,
v,
r,
s,
}
)
)
.to.emit(paraswapLiquiditySwapAdapter, 'Swapped')
.withArgs(weth.address, dai.address, amountWETHtoSwap, expectedDaiAmount);
const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address);
const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address);
const userADaiBalance = await aDai.balanceOf(userAddress);
const userAEthBalance = await aWETH.balanceOf(userAddress);
expect(adapterWethBalance).to.be.eq(Zero);
expect(adapterDaiBalance).to.be.eq(Zero);
expect(userADaiBalance).to.be.eq(expectedDaiAmount);
expect(userAEthBalance).to.be.gt(userAEthBalanceBefore.sub(amountWETHtoSwap));
expect(userAEthBalance).to.be.lt(userAEthBalanceBefore.mul(10001).div(10000).sub(amountWETHtoSwap));
});
it('should correctly swap all the balance when using a bigger amount', async () => {
const { users, weth, oracle, dai, aDai, aWETH, paraswapLiquiditySwapAdapter } = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap.add(1), amountWETHtoSwap.mul(10001).div(10000), expectedDaiAmount);
// Remove other balance
await aWETH.connect(user).transfer(users[1].address, parseEther('90'));
// User will swap liquidity aEth to aDai
const bigAmountToSwap = parseEther('11');
await aWETH.connect(user).approve(paraswapLiquiditySwapAdapter.address, bigAmountToSwap);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, bigAmountToSwap, expectedDaiAmount]
);
await expect(
paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
weth.address,
dai.address,
bigAmountToSwap,
expectedDaiAmount,
4 + 2*32,
mockAugustusCalldata,
mockAugustus.address,
{
amount: 0,
deadline: 0,
v: 0,
r: '0x0000000000000000000000000000000000000000000000000000000000000000',
s: '0x0000000000000000000000000000000000000000000000000000000000000000',
}
)
).to.emit(paraswapLiquiditySwapAdapter, 'Swapped');
const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address);
const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address);
const userADaiBalance = await aDai.balanceOf(userAddress);
const userAEthBalance = await aWETH.balanceOf(userAddress);
expect(adapterWethBalance).to.be.eq(Zero);
expect(adapterDaiBalance).to.be.eq(Zero);
expect(userADaiBalance).to.be.eq(expectedDaiAmount);
expect(userAEthBalance).to.be.eq(Zero);
});
it('should correctly swap all the balance when using permit', async () => {
const { users, weth, oracle, dai, aDai, aWETH, paraswapLiquiditySwapAdapter } = 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 mockAugustus.expectSwap(weth.address, dai.address, amountWETHtoSwap.add(1), amountWETHtoSwap.mul(10001).div(10000), expectedDaiAmount);
// Remove other balance
await aWETH.connect(user).transfer(users[1].address, parseEther('90'));
// User will swap liquidity aEth to aDai
const bigAmountToSwap = parseEther('11');
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,
paraswapLiquiditySwapAdapter.address,
nonce,
deadline,
bigAmountToSwap.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);
const mockAugustusCalldata = mockAugustus.interface.encodeFunctionData(
'swap',
[weth.address, dai.address, bigAmountToSwap, expectedDaiAmount]
);
await expect(
paraswapLiquiditySwapAdapter.connect(user).swapAndDeposit(
weth.address,
dai.address,
bigAmountToSwap,
expectedDaiAmount,
4 + 2*32,
mockAugustusCalldata,
mockAugustus.address,
{
amount: bigAmountToSwap,
deadline,
v,
r,
s,
}
)
).to.emit(paraswapLiquiditySwapAdapter, 'Swapped');
const adapterWethBalance = await weth.balanceOf(paraswapLiquiditySwapAdapter.address);
const adapterDaiBalance = await dai.balanceOf(paraswapLiquiditySwapAdapter.address);
const userADaiBalance = await aDai.balanceOf(userAddress);
const userAEthBalance = await aWETH.balanceOf(userAddress);
expect(adapterWethBalance).to.be.eq(Zero);
expect(adapterDaiBalance).to.be.eq(Zero);
expect(userADaiBalance).to.be.eq(expectedDaiAmount);
expect(userAEthBalance).to.be.eq(Zero);
});
});
});
});