mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
4fe36c8fa4
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.
2394 lines
90 KiB
TypeScript
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);
|
|
});
|
|
});
|
|
});
|
|
});
|