import { Chain } from '__tests__/utils/chain'; import { mockInjector } from '__tests__/utils/mock-injector'; import { TOKENS as ALL_TOKENS } from '__tests__/utils/tokens'; import { Injector } from 'src/core/injector/injector'; import BigNumber from 'bignumber.js'; import { Web3Public } from 'src/core'; import { PriceTokenAmount } from 'src/common/tokens/price-token-amount'; import { PriceToken } from 'src/common/tokens/price-token'; import { TransactionReceipt } from 'web3-eth'; import { UniSwapV2EthereumProvider } from '@rsdk-features/instant-trades/dexes/ethereum/uni-swap-v2-ethereum/uni-swap-v2-ethereum-provider'; import { BLOCKCHAIN_NAME } from 'src/core/blockchain/models/blockchain-name'; import fn = jest.fn; const TOKENS = ALL_TOKENS[BLOCKCHAIN_NAME.ETHEREUM]; export const uniswapV2TradeSpec = () => describe('Uniswap V2 trade tests.', () => { let chain: Chain; let uniswapV2Provider: UniSwapV2EthereumProvider; let web3Public: Web3Public; let userAddress: string; const getTransactionFeeByReceipt = async ( transactionReceipt: TransactionReceipt ): Promise => { const transaction = (await web3Public.getTransactionByHash( transactionReceipt.transactionHash ))!; return new BigNumber(transactionReceipt.gasUsed).multipliedBy(transaction.gasPrice); }; const getTransactionFeeByHash = async (transactionHash: string): Promise => { const transaction = (await web3Public.getTransactionByHash(transactionHash))!; const transactionReceipt = (await chain.web3.eth.getTransactionReceipt( transactionHash ))!; return new BigNumber(transactionReceipt.gasUsed).multipliedBy(transaction.gasPrice); }; beforeAll(async () => { uniswapV2Provider = new UniSwapV2EthereumProvider(); }); beforeEach(async () => { chain = await Chain.reset(BLOCKCHAIN_NAME.ETHEREUM); const configuration = await chain.getConfiguration(); await mockInjector(configuration); web3Public = Injector.web3PublicService.getWeb3Public(BLOCKCHAIN_NAME.ETHEREUM); userAddress = Injector.web3PrivateService.address; }, 20_000); test('Swap method must works with NATIVE-ERC20 trade', async () => { const ethTokenAmountToSwap = 1; const expectedToTokensAmount = 3173.460947; // constant data about tokens rate in 13961175 block const ethBalanceBefore = await web3Public.getBalance(userAddress); const usdtBalanceBefore = await web3Public.getBalance(userAddress, TOKENS.USDT.address); const from = await PriceTokenAmount.createFromToken({ ...TOKENS.ETH, tokenAmount: new BigNumber(ethTokenAmountToSwap) }); const to = await PriceToken.createFromToken(TOKENS.USDT); const trade = await uniswapV2Provider.calculate(from, to, { gasCalculation: 'disabled' }); const transactionReceipt = await trade.swap(); const ethBalanceAfter = await web3Public.getBalance(userAddress); const usdtBalanceAfter = await web3Public.getBalance(userAddress, TOKENS.USDT.address); const transactionFee = await getTransactionFeeByReceipt(transactionReceipt); expect(transactionReceipt.status).toBeTruthy(); expect( ethBalanceAfter.isEqualTo( ethBalanceBefore .minus(ethTokenAmountToSwap * 10 ** TOKENS.ETH.decimals) .minus(transactionFee) ) ).toBeTruthy(); expect( usdtBalanceAfter.isEqualTo( usdtBalanceBefore.plus(expectedToTokensAmount * 10 ** TOKENS.USDT.decimals) ) ).toBeTruthy(); const trade1 = await uniswapV2Provider.calculate(from, to, { gasCalculation: 'disabled' }); expect(trade1.to.weiAmount.isEqualTo(trade.to.weiAmount)).not.toBeTruthy(); }, 400_000); test('Swap method must works with ERC20-NATIVE trade', async () => { const rbcTokenAmountToSwap = 1; const expectedToTokensAmount = '0.000068319082745321'; // constant data about tokens rate in 13961175 block const from = await PriceTokenAmount.createFromToken({ ...TOKENS.RBC, tokenAmount: new BigNumber(rbcTokenAmountToSwap) }); const to = await PriceToken.createFromToken(TOKENS.ETH); await chain.increaseTokensBalance(from, rbcTokenAmountToSwap, { inEtherUnits: true }); const rbcBalanceBefore = await web3Public.getBalance(userAddress, from.address); const ethBalanceBefore = await web3Public.getBalance(userAddress); let approveTxHash = ''; const onApprove = fn(hash => (approveTxHash = hash)); const trade = await uniswapV2Provider.calculate(from, to, { gasCalculation: 'disabled' }); const transactionReceipt = await trade.swap({ onApprove }); const rbcBalanceAfter = await web3Public.getBalance(userAddress, from.address); const ethBalanceAfter = await web3Public.getBalance(userAddress); const approveTransactionFee = await getTransactionFeeByHash(approveTxHash); const transactionFee = await getTransactionFeeByReceipt(transactionReceipt); expect(transactionReceipt.status).toBeTruthy(); expect( rbcBalanceAfter.isEqualTo( rbcBalanceBefore.minus(rbcTokenAmountToSwap * 10 ** from.decimals) ) ).toBeTruthy(); expect( ethBalanceAfter.isEqualTo( ethBalanceBefore .plus(new BigNumber(expectedToTokensAmount).multipliedBy(10 ** to.decimals)) .minus(approveTransactionFee) .minus(transactionFee) ) ).toBeTruthy(); expect(onApprove.mock.calls.length).toBe(1); }, 400_000); test('Swap method must works with ERC20-ERC20 trade', async () => { const rbcTokenAmountToSwap = 1; const expectedToTokensAmount = '0.216816'; // constant data about tokens rate in 13961175 block const from = await PriceTokenAmount.createFromToken({ ...TOKENS.RBC, tokenAmount: new BigNumber(rbcTokenAmountToSwap) }); const to = await PriceToken.createFromToken(TOKENS.USDT); await chain.increaseTokensBalance(from, rbcTokenAmountToSwap, { inEtherUnits: true }); const rbcBalanceBefore = await web3Public.getBalance(userAddress, from.address); const usdtBalanceBefore = await web3Public.getBalance(userAddress, to.address); const trade = await uniswapV2Provider.calculate(from, to, { gasCalculation: 'disabled' }); const transactionReceipt = await trade.swap(); const rbcBalanceAfter = await web3Public.getBalance(userAddress, from.address); const usdtBalanceAfter = await web3Public.getBalance(userAddress, to.address); expect(transactionReceipt.status).toBeTruthy(); expect( rbcBalanceAfter.isEqualTo( rbcBalanceBefore.minus(rbcTokenAmountToSwap * 10 ** from.decimals) ) ).toBeTruthy(); expect( usdtBalanceAfter.isEqualTo( usdtBalanceBefore.plus( new BigNumber(expectedToTokensAmount).multipliedBy(10 ** to.decimals) ) ) ).toBeTruthy(); }, 400_000); });