diff --git a/test/chains/ethereum/ethereum.controllers.test.ts b/test/chains/ethereum/ethereum.controllers.test.ts index a0fd3bc346..45d9ddcf78 100644 --- a/test/chains/ethereum/ethereum.controllers.test.ts +++ b/test/chains/ethereum/ethereum.controllers.test.ts @@ -42,12 +42,12 @@ const mockAddress = '0xFaA12FD102FE8623C9299c72B03E45107F2772B5'; // noqa: mock describe('init', () => { it('should wait for the first init() call to finish in future immediate init() calls', async () => { let firstCallFullfilled = false; - eth.init().then(() => { + const initPromise = eth.init().then(() => { firstCallFullfilled = true; }); - await eth.init().then(() => { - expect(firstCallFullfilled).toEqual(true); - }); + await eth.init(); + await initPromise; + expect(firstCallFullfilled).toEqual(true); }); }); diff --git a/test/connectors/uniswap/uniswap.lp.routes.test.ts b/test/connectors/uniswap/uniswap.lp.routes.test.ts deleted file mode 100644 index 5abb7d237b..0000000000 --- a/test/connectors/uniswap/uniswap.lp.routes.test.ts +++ /dev/null @@ -1,442 +0,0 @@ -import express from 'express'; -import { Express } from 'express-serve-static-core'; -import request from 'supertest'; -import { Ethereum } from '../../../src/chains/ethereum/ethereum'; -import { UniswapLP } from '../../../src/connectors/uniswap/uniswap.lp'; -import { AmmLiquidityRoutes } from '../../../src/amm/amm.routes'; -import { patch, unpatch } from '../../../test/services/patch'; -import { patchEVMNonceManager } from '../../evm.nonce.mock'; - -let app: Express; -let ethereum: Ethereum; -let uniswap: UniswapLP; - -beforeAll(async () => { - app = express(); - app.use(express.json()); - ethereum = Ethereum.getInstance('goerli'); - patchEVMNonceManager(ethereum.nonceManager); - await ethereum.init(); - - uniswap = UniswapLP.getInstance('ethereum', 'goerli'); - await uniswap.init(); - app.use('/amm/liquidity', AmmLiquidityRoutes.router); -}); - -beforeEach(() => { - patchEVMNonceManager(ethereum.nonceManager); -}); - -afterEach(() => { - unpatch(); -}); - -afterAll(async () => { - await ethereum.close(); -}); - -const address: string = '0xFaA12FD102FE8623C9299c72B03E45107F2772B5'; - -const patchGetWallet = () => { - patch(ethereum, 'getWallet', () => { - return { - address: '0xFaA12FD102FE8623C9299c72B03E45107F2772B5', - }; - }); -}; - -const patchInit = () => { - patch(uniswap, 'init', async () => { - return; - }); -}; - -const patchStoredTokenList = () => { - patch(ethereum, 'tokenList', () => { - return [ - { - chainId: 42, - name: 'WETH', - symbol: 'WETH', - address: '0xd0A1E359811322d97991E03f863a0C30C2cF029C', - decimals: 18, - }, - { - chainId: 42, - name: 'DAI', - symbol: 'DAI', - address: '0x4f96fe3b7a6cf9725f59d353f723c1bdb64ca6aa', - decimals: 18, - }, - ]; - }); -}; - -const patchGetTokenBySymbol = () => { - patch(ethereum, 'getTokenBySymbol', (symbol: string) => { - if (symbol === 'WETH') { - return { - chainId: 42, - name: 'WETH', - symbol: 'WETH', - address: '0xd0A1E359811322d97991E03f863a0C30C2cF029C', - decimals: 18, - }; - } else { - return { - chainId: 42, - name: 'DAI', - symbol: 'DAI', - address: '0x4f96fe3b7a6cf9725f59d353f723c1bdb64ca6aa', - decimals: 18, - }; - } - }); -}; - -const patchGetTokenByAddress = () => { - patch(uniswap, 'getTokenByAddress', () => { - return { - chainId: 42, - name: 'WETH', - symbol: 'WETH', - address: '0xd0A1E359811322d97991E03f863a0C30C2cF029C', - decimals: 18, - }; - }); -}; - -const patchGasPrice = () => { - patch(ethereum, 'gasPrice', () => 100); -}; - -const patchGetNonce = () => { - patch(ethereum.nonceManager, 'getNonce', () => 21); -}; - -const patchAddPosition = () => { - patch(uniswap, 'addPosition', () => { - return { nonce: 21, hash: '000000000000000' }; - }); -}; - -const patchRemovePosition = () => { - patch(uniswap, 'reducePosition', () => { - return { nonce: 21, hash: '000000000000000' }; - }); -}; - -const patchCollectFees = () => { - patch(uniswap, 'collectFees', () => { - return { nonce: 21, hash: '000000000000000' }; - }); -}; - -const patchPosition = () => { - patch(uniswap, 'getPosition', () => { - return { - token0: 'DAI', - token1: 'WETH', - fee: 300, - lowerPrice: '1', - upperPrice: '5', - amount0: '1', - amount1: '1', - unclaimedToken0: '1', - unclaimedToken1: '1', - }; - }); -}; - -describe('POST /liquidity/add', () => { - it('should return 200 when all parameter are OK', async () => { - patchGetWallet(); - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - patchGetTokenByAddress(); - patchGasPrice(); - patchAddPosition(); - patchGetNonce(); - - await request(app) - .post(`/amm/liquidity/add`) - .send({ - address: address, - token0: 'DAI', - token1: 'WETH', - amount0: '1', - amount1: '1', - fee: 'LOW', - lowerPrice: '1', - upperPrice: '5', - chain: 'ethereum', - network: 'goerli', - connector: 'uniswapLP', - }) - .set('Accept', 'application/json') - .expect(200); - }); - - it('should return 500 for unrecognized token0 symbol', async () => { - patchGetWallet(); - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - - await request(app) - .post(`/amm/liquidity/add`) - .send({ - address: address, - token0: 'DOGE', - token1: 'WETH', - amount0: '1', - amount1: '1', - fee: 'LOW', - lowerPrice: '1', - upperPrice: '5', - chain: 'ethereum', - network: 'goerli', - connector: 'uniswapLP', - }) - .set('Accept', 'application/json') - .expect(500); - }); - - it('should return 404 for invalid fee tier', async () => { - patchGetWallet(); - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - patchGetTokenByAddress(); - - await request(app) - .post(`/amm/liquidity/add`) - .send({ - address: address, - token0: 'DAI', - token1: 'WETH', - amount0: '1', - amount1: '1', - fee: 300, - lowerPrice: '1', - upperPrice: '5', - chain: 'ethereum', - network: 'goerli', - connector: 'uniswapLP', - }) - .set('Accept', 'application/json') - .expect(404); - }); - - it('should return 500 when the helper operation fails', async () => { - patchGetWallet(); - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - patchGetTokenByAddress(); - patch(uniswap, 'addPositionHelper', () => { - return 'error'; - }); - - await request(app) - .post(`/amm/liquidity/add`) - .send({ - address: address, - token0: 'DAI', - token1: 'WETH', - amount0: '1', - amount1: '1', - fee: 'LOW', - lowerPrice: '1', - upperPrice: '5', - chain: 'ethereum', - network: 'goerli', - connector: 'uniswapLP', - }) - .set('Accept', 'application/json') - .expect(500); - }); -}); - -describe('POST /liquidity/remove', () => { - const patchForBuy = () => { - patchGetWallet(); - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - patchGetTokenByAddress(); - patchGasPrice(); - patchRemovePosition(); - patchGetNonce(); - }; - it('should return 200 when all parameter are OK', async () => { - patchForBuy(); - await request(app) - .post(`/amm/liquidity/remove`) - .send({ - address: address, - tokenId: 2732, - chain: 'ethereum', - network: 'goerli', - connector: 'uniswapLP', - }) - .set('Accept', 'application/json') - .expect(200); - }); - - it('should return 404 when the tokenId is invalid', async () => { - patchGetWallet(); - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - patchGetTokenByAddress(); - - await request(app) - .post(`/amm/liquidity/remove`) - .send({ - address: address, - tokenId: 'Invalid', - chain: 'ethereum', - network: 'goerli', - connector: 'uniswapLP', - }) - .set('Accept', 'application/json') - .expect(404); - }); -}); - -describe('POST /liquidity/collect_fees', () => { - const patchForBuy = () => { - patchGetWallet(); - patchInit(); - patchGasPrice(); - patchCollectFees(); - patchGetNonce(); - }; - it('should return 200 when all parameter are OK', async () => { - patchForBuy(); - await request(app) - .post(`/amm/liquidity/collect_fees`) - .send({ - address: address, - tokenId: 2732, - chain: 'ethereum', - network: 'goerli', - connector: 'uniswapLP', - }) - .set('Accept', 'application/json') - .expect(200); - }); - - it('should return 404 when the tokenId is invalid', async () => { - patchGetWallet(); - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - patchGetTokenByAddress(); - - await request(app) - .post(`/amm/liquidity/collect_fees`) - .send({ - address: address, - tokenId: 'Invalid', - chain: 'ethereum', - network: 'goerli', - connector: 'uniswapLP', - }) - .set('Accept', 'application/json') - .expect(404); - }); -}); - -describe('POST /liquidity/position', () => { - it('should return 200 when all parameter are OK', async () => { - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - patchGetTokenByAddress(); - patchPosition(); - - await request(app) - .post(`/amm/liquidity/position`) - .send({ - tokenId: 2732, - chain: 'ethereum', - network: 'goerli', - connector: 'uniswapLP', - }) - .set('Accept', 'application/json') - .expect(200); - }); - - it('should return 404 when the tokenId is invalid', async () => { - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - patchGetTokenByAddress(); - - await request(app) - .post(`/amm/liquidity/position`) - .send({ - tokenId: 'Invalid', - chain: 'ethereum', - network: 'goerli', - connector: 'uniswapLP', - }) - .set('Accept', 'application/json') - .expect(404); - }); -}); - -describe('POST /liquidity/price', () => { - const patchForBuy = () => { - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - patchGetTokenByAddress(); - patch(uniswap, 'poolPrice', () => { - return ['100', '105']; - }); - }; - it('should return 200 when all parameter are OK', async () => { - patchForBuy(); - await request(app) - .post(`/amm/liquidity/price`) - .send({ - token0: 'DAI', - token1: 'WETH', - fee: 'LOW', - period: 120, - interval: 60, - chain: 'ethereum', - network: 'goerli', - connector: 'uniswapLP', - }) - .set('Accept', 'application/json') - .expect(200); - }); - - it('should return 404 when the fee is invalid', async () => { - patchGetWallet(); - patchInit(); - patchStoredTokenList(); - patchGetTokenBySymbol(); - patchGetTokenByAddress(); - - await request(app) - .post(`/amm/liquidity/price`) - .send({ - token0: 'DAI', - token1: 'WETH', - fee: 11, - period: 120, - interval: 60, - chain: 'ethereum', - network: 'goerli', - connector: 'uniswapLP', - }) - .set('Accept', 'application/json') - .expect(404); - }); -}); diff --git a/test/connectors/uniswap/uniswap.lp.test.ts b/test/connectors/uniswap/uniswap.lp.test.ts deleted file mode 100644 index a09e39b97a..0000000000 --- a/test/connectors/uniswap/uniswap.lp.test.ts +++ /dev/null @@ -1,287 +0,0 @@ -jest.useFakeTimers(); -import { Token } from '@uniswap/sdk-core'; -import * as uniV3 from '@uniswap/v3-sdk'; -import { BigNumber, Transaction, Wallet } from 'ethers'; -import { Ethereum } from '../../../src/chains/ethereum/ethereum'; -import { UniswapLP } from '../../../src/connectors/uniswap/uniswap.lp'; -import { patch, unpatch } from '../../../test/services/patch'; -import { patchEVMNonceManager } from '../../evm.nonce.mock'; -let ethereum: Ethereum; -let uniswapLP: UniswapLP; -let wallet: Wallet; - -const WETH = new Token( - 5, - '0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6', - 18, - 'WETH' -); - -const DAI = new Token( - 5, - '0xdc31Ee1784292379Fbb2964b3B9C4124D8F89C60', - 18, - 'DAI' -); - -const USDC = new Token( - 5, - '0xD87Ba7A50B2E7E660f678A895E4B72E7CB4CCd9C', - 6, - 'USDC' -); - -const TX = { - type: 2, - chainId: 5, - nonce: 115, - maxPriorityFeePerGas: { toString: () => '106000000000' }, - maxFeePerGas: { toString: () => '106000000000' }, - gasPrice: { toString: () => null }, - gasLimit: { toString: () => '100000' }, - to: '0xdc31Ee1784292379Fbb2964b3B9C4124D8F89C60', - value: { toString: () => '0' }, - data: '0x095ea7b30000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', // noqa: mock - accessList: [], - hash: '0x75f98675a8f64dcf14927ccde9a1d59b67fa09b72cc2642ad055dae4074853d9', // noqa: mock - v: 0, - r: '0xbeb9aa40028d79b9fdab108fcef5de635457a05f3a254410414c095b02c64643', // noqa: mock - s: '0x5a1506fa4b7f8b4f3826d8648f27ebaa9c0ee4bd67f569414b8cd8884c073100', // noqa: mock - from: '0xFaA12FD102FE8623C9299c72B03E45107F2772B5', - confirmations: 0, -}; - -const POOL_SQRT_RATIO_START = uniV3.encodeSqrtRatioX96(100e6, 100e18); - -const POOL_TICK_CURRENT = uniV3.TickMath.getTickAtSqrtRatio( - POOL_SQRT_RATIO_START -); - -const DAI_USDC_POOL = new uniV3.Pool( - DAI, - USDC, - 500, - POOL_SQRT_RATIO_START, - 0, - POOL_TICK_CURRENT, - [] -); - -beforeAll(async () => { - ethereum = Ethereum.getInstance('goerli'); - patchEVMNonceManager(ethereum.nonceManager); - await ethereum.init(); - - wallet = new Wallet( - '0000000000000000000000000000000000000000000000000000000000000002', // noqa: mock - ethereum.provider - ); - uniswapLP = UniswapLP.getInstance('ethereum', 'goerli'); - await uniswapLP.init(); -}); - -beforeEach(() => { - patchEVMNonceManager(ethereum.nonceManager); -}); - -afterEach(() => { - unpatch(); -}); - -afterAll(async () => { - await ethereum.close(); -}); - -const patchPoolState = () => { - patch(uniswapLP, 'getPoolContract', () => { - return { - liquidity() { - return DAI_USDC_POOL.liquidity; - }, - slot0() { - return [ - DAI_USDC_POOL.sqrtRatioX96, - DAI_USDC_POOL.tickCurrent, - 0, - 1, - 1, - 0, - true, - ]; - }, - ticks() { - return ['-118445039955967015140', '118445039955967015140']; - }, - }; - }); -}; - -const patchAlphaRouter = () => { - patch(uniswapLP, '_alphaRouter', { - routeToRatio() { - return { status: 3 }; - } - }); -}; - -const patchContract = () => { - patch(uniswapLP, 'getContract', () => { - return { - estimateGas: { - multicall() { - return BigNumber.from(5); - }, - }, - positions() { - return { - token0: WETH.address, - token1: USDC.address, - fee: 500, - tickLower: 0, - tickUpper: 23030, - liquidity: '6025055903594410671025', - }; - }, - multicall() { - return TX; - }, - collect() { - return TX; - }, - }; - }); -}; - -const patchWallet = () => { - patch(wallet, 'sendTransaction', () => { - return TX; - }); -}; - -describe('verify UniswapLP Nft functions', () => { - it('Should return correct contract addresses', async () => { - expect(uniswapLP.router).toEqual( - '0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45' - ); - expect(uniswapLP.nftManager).toEqual( - '0xC36442b4a4522E871399CD717aBDD847Ab11FE88' - ); - }); - - it('Should return correct contract abi', async () => { - expect(Array.isArray(uniswapLP.routerAbi)).toEqual(true); - expect(Array.isArray(uniswapLP.nftAbi)).toEqual(true); - expect(Array.isArray(uniswapLP.poolAbi)).toEqual(true); - }); - - it('addPositionHelper returns calldata and value', async () => { - patchPoolState(); - patchAlphaRouter(); - - const callData = await uniswapLP.addPositionHelper( - wallet, - DAI, - WETH, - '10', - '10', - 500, - 1, - 10 - ); - expect(callData).toHaveProperty('calldata'); - expect(callData).toHaveProperty('value'); - }); - - it('reducePositionHelper returns calldata and value', async () => { - patchPoolState(); - patchContract(); - - const callData = await uniswapLP.reducePositionHelper(wallet, 1, 100); - expect(callData).toHaveProperty('calldata'); - expect(callData).toHaveProperty('value'); - }); - - it('basic functions should work', async () => { - patchContract(); - patchPoolState(); - - expect(uniswapLP.ready()).toEqual(true); - expect(uniswapLP.gasLimitEstimate).toBeGreaterThan(0); - expect(typeof uniswapLP.getContract('nft', ethereum.provider)).toEqual( - 'object' - ); - expect( - typeof uniswapLP.getPoolContract( - '0x4F96Fe3b7A6Cf9725f59d353F723c1bDb64CA6Aa', - wallet - ) - ).toEqual('object'); - }); - - it('generateOverrides returns overrides correctly', async () => { - const overrides = uniswapLP.generateOverrides( - 1, - 2, - 3, - BigNumber.from(4), - BigNumber.from(5), - '6' - ); - expect(overrides.gasLimit).toEqual(BigNumber.from('1')); - expect(overrides.gasPrice).toBeUndefined(); - expect(overrides.nonce).toEqual(BigNumber.from(3)); - expect(overrides.maxFeePerGas as BigNumber).toEqual(BigNumber.from(4)); - expect(overrides.maxPriorityFeePerGas as BigNumber).toEqual( - BigNumber.from(5) - ); - expect(overrides.value).toEqual(BigNumber.from('6')); - }); - - it('reducePosition should work', async () => { - patchPoolState(); - patchContract(); - - const reduceTx = (await uniswapLP.reducePosition( - wallet, - 1, - 100, - 50000, - 10 - )) as Transaction; - expect(reduceTx.hash).toEqual( - '0x75f98675a8f64dcf14927ccde9a1d59b67fa09b72cc2642ad055dae4074853d9' // noqa: mock - ); - }); - - it('addPosition should work', async () => { - patchPoolState(); - patchWallet(); - patchAlphaRouter(); - - const addTx = await uniswapLP.addPosition( - wallet, - DAI, - WETH, - '10', - '10', - 'LOWEST', - 1, - 10, - 0, - 1, - 1 - ); - expect(addTx.hash).toEqual( - '0x75f98675a8f64dcf14927ccde9a1d59b67fa09b72cc2642ad055dae4074853d9' // noqa: mock - ); - }); - - it('collectFees should work', async () => { - patchContract(); - - const collectTx = (await uniswapLP.collectFees(wallet, 1)) as Transaction; - expect(collectTx.hash).toEqual( - '0x75f98675a8f64dcf14927ccde9a1d59b67fa09b72cc2642ad055dae4074853d9' // noqa: mock - ); - }); -});