diff --git a/src/dex/morphex/config.ts b/src/dex/morphex/config.ts index 7d576f158..be57e017c 100644 --- a/src/dex/morphex/config.ts +++ b/src/dex/morphex/config.ts @@ -12,6 +12,14 @@ export const MorphexConfig: DexConfigMap = { fastPriceEvents: '0xDc7C389be5da32e326A261dC0126feCa7AE04d79', usdg: '0xe135c7BFfda932b5B862Da442cF4CbC4d43DC3Ad', }, + [Network.BSC]: { + vault: '0x46940Dc651bFe3F2CC3E04cf9dC5579B50Cf0765', + reader: '0x49A97680938B4F1f73816d1B70C3Ab801FAd124B', + priceFeed: '0x0144b19D1B9338fC7C286d6767bd9b29F0347f27', + fastPriceFeed: '0x55e6e6A968e485abEC1e1d957f408586e45a4f99', + fastPriceEvents: '0x491Df61db853761d42C4F38BeD220E9D807143dE', + usdg: '0x548f93779fBC992010C07467cBaf329DD5F059B7', + }, }, }; @@ -24,7 +32,15 @@ export const Adapters: { [SwapSide.SELL]: [ { name: 'FantomAdapter01', - index: 6, // TODO: it's for aavev3, but there is no Morphex adapter + index: 6, // TODO: there is no Morphex adapter + }, + ], + }, + [Network.BSC]: { + [SwapSide.SELL]: [ + { + name: 'BscAdapter01', + index: 6, // TODO: there is no Morphex adapter }, ], }, diff --git a/src/dex/morphex/morphex-e2e.test.ts b/src/dex/morphex/morphex-e2e.test.ts index 47d04c20a..cf701af17 100644 --- a/src/dex/morphex/morphex-e2e.test.ts +++ b/src/dex/morphex/morphex-e2e.test.ts @@ -88,4 +88,79 @@ describe('Morphex E2E', () => { }), ); }); + + describe('Morphex BSC', () => { + const network = Network.BSC; + const tokens = Tokens[network]; + const holders = Holders[network]; + const provider = new StaticJsonRpcProvider( + generateConfig(network).privateHttpProvider, + network, + ); + + const tokenASymbol: string = 'USDT'; + const tokenBSymbol: string = 'ETH'; + const nativeTokenSymbol = NativeTokenSymbols[network]; + + const tokenAAmount: string = '2000000000000000000000'; // 2000 USDT + const tokenBAmount: string = '1000000000000000000'; // 1 ETH + const nativeTokenAmount = '1000000000000000000'; // 1 BNB + + const sideToContractMethods = new Map([ + [ + SwapSide.SELL, + [ + ContractMethod.simpleSwap, + // ContractMethod.multiSwap, + // ContractMethod.megaSwap, + ], + ], + ]); + + sideToContractMethods.forEach((contractMethods, side) => + contractMethods.forEach((contractMethod: ContractMethod) => { + describe(`${contractMethod}`, () => { + it(nativeTokenSymbol + ' -> TOKEN', async () => { + await testE2E( + tokens[nativeTokenSymbol], + tokens[tokenASymbol], + holders[nativeTokenSymbol], + side === SwapSide.SELL ? nativeTokenAmount : tokenAAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + it('TOKEN -> ' + nativeTokenSymbol, async () => { + await testE2E( + tokens[tokenASymbol], + tokens[nativeTokenSymbol], + holders[tokenASymbol], + side === SwapSide.SELL ? tokenAAmount : nativeTokenAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + it('TOKEN -> TOKEN', async () => { + await testE2E( + tokens[tokenASymbol], + tokens[tokenBSymbol], + holders[tokenASymbol], + side === SwapSide.SELL ? tokenAAmount : tokenBAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + }); + }), + ); + }); }); diff --git a/src/dex/morphex/morphex-events.test.ts b/src/dex/morphex/morphex-events.test.ts index e488738af..f2bf62360 100644 --- a/src/dex/morphex/morphex-events.test.ts +++ b/src/dex/morphex/morphex-events.test.ts @@ -10,8 +10,6 @@ import { PoolState } from '../gmx/types'; jest.setTimeout(50 * 1000); const dexKey = 'Morphex'; -const network = Network.FANTOM; -const params = MorphexConfig[dexKey][network]; async function fetchPoolState( gmxPool: GMXEventPool, @@ -38,7 +36,9 @@ function compareState(state: PoolState, expectedState: PoolState) { ); } -describe('Morphex Event', function () { +describe('Morphex Fantom Events', function () { + const network = Network.FANTOM; + const params = MorphexConfig[dexKey][network]; const blockNumbers: { [eventName: string]: number[] } = { IncreaseUsdgAmount: [ 67247602, 67247565, 67247561, 67247508, 67247393, 67247305, 67247303, @@ -90,3 +90,61 @@ describe('Morphex Event', function () { }); }); }); + +describe('Morphex BSC Events', function () { + const network = Network.BSC; + const params = MorphexConfig[dexKey][network]; + const blockNumbers: { [eventName: string]: number[] } = { + IncreaseUsdgAmount: [ + 31152256, 31138628, 31137790, 31137788, 31131427, 31123797, 31120641, + 31116766, 31116335, 31116205, 31115380, 31112437, 31112433, 31107317, + 31106077, 31106044, 31105166, 31104580, 31104252, 31104234, 31102490, + 31097010, + ], + DecreaseUsdgAmount: [ + 31152256, 31137790, 31137788, 31136832, 31136830, 31136827, 31136825, + 31136823, 31136820, 31136818, 31136815, 31131427, 31112437, 31112433, + 31106077, 31106044, 31105166, 31104580, 31099233, 31099169, 31098990, + 31097010, 31093513, + ], + Transfer: [ + 31138628, 31123797, 31120641, 31116766, 31116335, 31116205, 31115380, + 31107317, 31104252, 31104234, 31102490, 31099233, 31099233, 31099169, + ], + PriceUpdate: [31156757, 31156707, 31156648, 31156597, 31156526], + }; + + describe('MorphexEventPool', function () { + Object.keys(blockNumbers).forEach((event: string) => { + blockNumbers[event].forEach((blockNumber: number) => { + it(`Should return the correct state after the ${blockNumber}:${event}`, async function () { + const dexHelper = new DummyDexHelper(network); + const logger = dexHelper.getLogger(dexKey); + + const config = await GMXEventPool.getConfig( + params, + blockNumber, + dexHelper.multiContract, + ); + const gmxPool = new GMXEventPool( + dexKey, + network, + dexHelper, + logger, + config, + ); + + await testEventSubscriber( + gmxPool, + gmxPool.addressesSubscribed, + (_blockNumber: number) => fetchPoolState(gmxPool, _blockNumber), + blockNumber, + `${dexKey}_${params.vault}`, + dexHelper.provider, + compareState, + ); + }); + }); + }); + }); +}); diff --git a/src/dex/morphex/morphex-integration.test.ts b/src/dex/morphex/morphex-integration.test.ts index 6300b74f6..7574e5767 100644 --- a/src/dex/morphex/morphex-integration.test.ts +++ b/src/dex/morphex/morphex-integration.test.ts @@ -14,28 +14,126 @@ import { import { Tokens } from '../../../tests/constants-e2e'; import ReaderABI from '../../abi/gmx/reader.json'; -const network = Network.FANTOM; -const TokenASymbol = 'axlUSDC'; -const TokenA = Tokens[network][TokenASymbol]; - -const TokenBSymbol = 'WFTM'; -const TokenB = Tokens[network][TokenBSymbol]; - -const amounts = [ - 0n, - 1000000000n, - 2000000000n, - 3000000000n, - 4000000000n, - 5000000000n, -]; - const dexKey = 'Morphex'; -const params = MorphexConfig[dexKey][network]; -const readerInterface = new Interface(ReaderABI); -const readerAddress = params.reader; -describe('Morphex', function () { +describe('Morphex Fantom', function () { + const network = Network.FANTOM; + const TokenASymbol = 'axlUSDC'; + const TokenA = Tokens[network][TokenASymbol]; + + const TokenBSymbol = 'WFTM'; + const TokenB = Tokens[network][TokenBSymbol]; + + const amounts = [ + 0n, + 1000000000n, + 2000000000n, + 3000000000n, + 4000000000n, + 5000000000n, + ]; + + const readerInterface = new Interface(ReaderABI); + const params = MorphexConfig[dexKey][network]; + const readerAddress = params.reader; + + it('getPoolIdentifiers and getPricesVolume SELL', async function () { + const dexHelper = new DummyDexHelper(network); + const blocknumber = await dexHelper.web3Provider.eth.getBlockNumber(); + const gmx = new Morphex(network, dexKey, dexHelper); + + await gmx.initializePricing(blocknumber); + + const pools = await gmx.getPoolIdentifiers( + TokenA, + TokenB, + SwapSide.SELL, + blocknumber, + ); + console.log(`${TokenASymbol} <> ${TokenBSymbol} Pool Identifiers: `, pools); + + expect(pools.length).toBeGreaterThan(0); + + const poolPrices = await gmx.getPricesVolume( + TokenA, + TokenB, + amounts, + SwapSide.SELL, + blocknumber, + pools, + ); + console.log(`${TokenASymbol} <> ${TokenBSymbol} Pool Prices: `, poolPrices); + + expect(poolPrices).not.toBeNull(); + if (gmx.hasConstantPriceLargeAmounts) { + checkConstantPoolPrices(poolPrices!, amounts, dexKey); + } else { + checkPoolPrices(poolPrices!, amounts, SwapSide.SELL, dexKey); + } + + // Do on chain pricing based on reader to compare + const readerCallData = amounts.map(a => ({ + target: readerAddress, + callData: readerInterface.encodeFunctionData('getAmountOut', [ + params.vault, + TokenA.address, + TokenB.address, + a.toString(), + ]), + })); + + const readerResult = ( + await dexHelper.multiContract.methods + .aggregate(readerCallData) + .call({}, blocknumber) + ).returnData; + const expectedPrices = readerResult.map((p: any) => + BigInt( + readerInterface.decodeFunctionResult('getAmountOut', p)[0].toString(), + ), + ); + + expect(poolPrices![0].prices).toEqual(expectedPrices); + }); + + it('getTopPoolsForToken', async function () { + const dexHelper = new DummyDexHelper(network); + const gmx = new Morphex(network, dexKey, dexHelper); + + await gmx.updatePoolState(); + const poolLiquidity = await gmx.getTopPoolsForToken(TokenA.address, 10); + console.log( + `${TokenASymbol} Top Pools:`, + JSON.stringify(poolLiquidity, null, 2), + ); + + if (!gmx.hasConstantPriceLargeAmounts) { + checkPoolsLiquidity(poolLiquidity, TokenA.address, dexKey); + } + }); +}); + +describe('Morphex BSC', function () { + const network = Network.BSC; + const TokenASymbol = 'ETH'; + const TokenA = Tokens[network][TokenASymbol]; + + const TokenBSymbol = 'USDT'; + const TokenB = Tokens[network][TokenBSymbol]; + + const amounts = [ + 0n, + 1000000000000000000n, + 2000000000000000000n, + 3000000000000000000n, + 4000000000000000000n, + 5000000000000000000n, + ]; + + const readerInterface = new Interface(ReaderABI); + const params = MorphexConfig[dexKey][network]; + const readerAddress = params.reader; + it('getPoolIdentifiers and getPricesVolume SELL', async function () { const dexHelper = new DummyDexHelper(network); const blocknumber = await dexHelper.web3Provider.eth.getBlockNumber();