import { makeSuite, TestEnv } from './helpers/make-suite'; import { convertToCurrencyDecimals } from '../../helpers/contracts-helpers'; import { getMockUniswapRouter } from '../../helpers/contracts-getters'; import { MockUniswapV2Router02 } from '../../types/MockUniswapV2Router02'; import BigNumber from 'bignumber.js'; import { evmRevert, evmSnapshot } from '../../helpers/misc-utils'; import { ethers } from 'ethers'; import { USD_ADDRESS } from '../../helpers/constants'; const { parseEther } = ethers.utils; const { expect } = require('chai'); makeSuite('Uniswap adapters', (testEnv: TestEnv) => { let mockUniswapRouter: MockUniswapV2Router02; let evmSnapshotId: string; before(async () => { mockUniswapRouter = await getMockUniswapRouter(); }); beforeEach(async () => { evmSnapshotId = await evmSnapshot(); }); afterEach(async () => { await evmRevert(evmSnapshotId); }); describe('BaseUniswapAdapter', () => { describe('getAmountsOut', () => { it('should return the estimated amountOut and prices for the asset swap', async () => { const { weth, dai, uniswapLiquiditySwapAdapter, oracle } = testEnv; const amountIn = parseEther('1'); const flashloanPremium = amountIn.mul(9).div(10000); const amountToSwap = amountIn.sub(flashloanPremium); const wethPrice = await oracle.getAssetPrice(weth.address); const daiPrice = await oracle.getAssetPrice(dai.address); const usdPrice = await oracle.getAssetPrice(USD_ADDRESS); const expectedDaiAmount = await convertToCurrencyDecimals( dai.address, new BigNumber(amountToSwap.toString()).div(daiPrice.toString()).toFixed(0) ); const outPerInPrice = amountToSwap .mul(parseEther('1')) .mul(parseEther('1')) .div(expectedDaiAmount.mul(parseEther('1'))); const ethUsdValue = amountIn .mul(wethPrice) .div(parseEther('1')) .mul(usdPrice) .div(parseEther('1')); const daiUsdValue = expectedDaiAmount .mul(daiPrice) .div(parseEther('1')) .mul(usdPrice) .div(parseEther('1')); await mockUniswapRouter.setAmountOut( amountToSwap, weth.address, dai.address, expectedDaiAmount ); const result = await uniswapLiquiditySwapAdapter.getAmountsOut( amountIn, weth.address, dai.address ); expect(result['0']).to.be.eq(expectedDaiAmount); expect(result['1']).to.be.eq(outPerInPrice); expect(result['2']).to.be.eq(ethUsdValue); expect(result['3']).to.be.eq(daiUsdValue); }); it('should work correctly with different decimals', async () => { const { aave, usdc, uniswapLiquiditySwapAdapter, oracle } = testEnv; const amountIn = parseEther('10'); const flashloanPremium = amountIn.mul(9).div(10000); const amountToSwap = amountIn.sub(flashloanPremium); const aavePrice = await oracle.getAssetPrice(aave.address); const usdcPrice = await oracle.getAssetPrice(usdc.address); const usdPrice = await oracle.getAssetPrice(USD_ADDRESS); const expectedUSDCAmount = await convertToCurrencyDecimals( usdc.address, new BigNumber(amountToSwap.toString()).div(usdcPrice.toString()).toFixed(0) ); const outPerInPrice = amountToSwap .mul(parseEther('1')) .mul('1000000') // usdc 6 decimals .div(expectedUSDCAmount.mul(parseEther('1'))); const aaveUsdValue = amountIn .mul(aavePrice) .div(parseEther('1')) .mul(usdPrice) .div(parseEther('1')); const usdcUsdValue = expectedUSDCAmount .mul(usdcPrice) .div('1000000') // usdc 6 decimals .mul(usdPrice) .div(parseEther('1')); await mockUniswapRouter.setAmountOut( amountToSwap, aave.address, usdc.address, expectedUSDCAmount ); const result = await uniswapLiquiditySwapAdapter.getAmountsOut( amountIn, aave.address, usdc.address ); expect(result['0']).to.be.eq(expectedUSDCAmount); expect(result['1']).to.be.eq(outPerInPrice); expect(result['2']).to.be.eq(aaveUsdValue); expect(result['3']).to.be.eq(usdcUsdValue); }); }); describe('getAmountsIn', () => { it('should return the estimated required amountIn for the asset swap', async () => { const { weth, dai, uniswapLiquiditySwapAdapter, oracle } = testEnv; const amountIn = parseEther('1'); const flashloanPremium = amountIn.mul(9).div(10000); const amountToSwap = amountIn.add(flashloanPremium); const wethPrice = await oracle.getAssetPrice(weth.address); const daiPrice = await oracle.getAssetPrice(dai.address); const usdPrice = await oracle.getAssetPrice(USD_ADDRESS); const amountOut = await convertToCurrencyDecimals( dai.address, new BigNumber(amountIn.toString()).div(daiPrice.toString()).toFixed(0) ); const inPerOutPrice = amountOut .mul(parseEther('1')) .mul(parseEther('1')) .div(amountToSwap.mul(parseEther('1'))); const ethUsdValue = amountToSwap .mul(wethPrice) .div(parseEther('1')) .mul(usdPrice) .div(parseEther('1')); const daiUsdValue = amountOut .mul(daiPrice) .div(parseEther('1')) .mul(usdPrice) .div(parseEther('1')); await mockUniswapRouter.setAmountIn(amountOut, weth.address, dai.address, amountIn); const result = await uniswapLiquiditySwapAdapter.getAmountsIn( amountOut, weth.address, dai.address ); expect(result['0']).to.be.eq(amountToSwap); expect(result['1']).to.be.eq(inPerOutPrice); expect(result['2']).to.be.eq(ethUsdValue); expect(result['3']).to.be.eq(daiUsdValue); }); it('should work correctly with different decimals', async () => { const { aave, usdc, uniswapLiquiditySwapAdapter, oracle } = testEnv; const amountIn = parseEther('10'); const flashloanPremium = amountIn.mul(9).div(10000); const amountToSwap = amountIn.add(flashloanPremium); const aavePrice = await oracle.getAssetPrice(aave.address); const usdcPrice = await oracle.getAssetPrice(usdc.address); const usdPrice = await oracle.getAssetPrice(USD_ADDRESS); const amountOut = await convertToCurrencyDecimals( usdc.address, new BigNumber(amountToSwap.toString()).div(usdcPrice.toString()).toFixed(0) ); const inPerOutPrice = amountOut .mul(parseEther('1')) .mul(parseEther('1')) .div(amountToSwap.mul('1000000')); // usdc 6 decimals const aaveUsdValue = amountToSwap .mul(aavePrice) .div(parseEther('1')) .mul(usdPrice) .div(parseEther('1')); const usdcUsdValue = amountOut .mul(usdcPrice) .div('1000000') // usdc 6 decimals .mul(usdPrice) .div(parseEther('1')); await mockUniswapRouter.setAmountIn(amountOut, aave.address, usdc.address, amountIn); const result = await uniswapLiquiditySwapAdapter.getAmountsIn( amountOut, aave.address, usdc.address ); expect(result['0']).to.be.eq(amountToSwap); expect(result['1']).to.be.eq(inPerOutPrice); expect(result['2']).to.be.eq(aaveUsdValue); expect(result['3']).to.be.eq(usdcUsdValue); }); }); }); });