UNPKG

forta-flashloan-detector

Version:

A library for forta agents that detects if a transaction event contains a flashloan

166 lines (128 loc) 5.17 kB
const { ethers } = require('forta-agent'); const FlashloanDetector = require('./flashloan-detector'); // Mock the initIronBankMarkets method because // it calls a JsonRpc provider jest.mock('./detectors/iron-bank-detector', () => ({ ...jest.requireActual('./detectors/iron-bank-detector'), initIronBankMarkets: () => {}, })); const amount = ethers.utils.parseUnits('100', 18); // Event information is not important if we mock 'filterLog' const mockAaveEvent = {}; const mockDydxWithdrawEvent = { args: { market: ethers.constants.Zero, update: { deltaWei: { sign: false, value: ethers.BigNumber.from(10), }, }, }, }; const mockDydxDepositEvent = { args: { market: ethers.constants.Zero, update: { deltaWei: { sign: true, value: ethers.BigNumber.from(12), }, }, }, }; const mockEulerBorrowEvent = { name: 'Borrow', args: { amount, underlying: '0xunderlying', }, }; const mockEulerRepayEvent = { name: 'Repay', args: { amount, underlying: '0xunderlying', }, }; // Event information is not important if we mock 'filterLog' const mockIronBankEvent = {}; // Event information is not important if we mock 'filterLog' const mockMakerEvent = {}; describe('FlashloanDetector library', () => { let flashloanDetector; const mockTxEvent = { filterLog: jest.fn() }; beforeEach(() => { mockTxEvent.filterLog.mockReset(); }); describe('init', () => { it('should support all protocols by default', () => { flashloanDetector = new FlashloanDetector(); expect(flashloanDetector.protocols).toEqual({ aave: true, dydx: true, euler: true, ironBank: true, maker: true, }); }); it('should support only the provided protocols', () => { flashloanDetector = new FlashloanDetector(['aave', 'maker']); expect(flashloanDetector.protocols).toEqual({ aave: true, maker: true, }); }); it('should throw on creation if unsupported protocol is provided', () => { expect(() => { flashloanDetector = new FlashloanDetector(['otherProtocol']); }).toThrow(); }); }); describe('getFlashloans', () => { it('should return empty array if there are no flashloans', () => { flashloanDetector = new FlashloanDetector(); // Don't mock mockTxEvent.filterLog.mockReturnValue([]); const flashloans = flashloanDetector.getFlashloans(mockTxEvent); expect(flashloans).toStrictEqual([]); }); it('should return the "Aave" protocol if there is a flashloan from Aave', () => { // Detect flashloans only for Aave so we don't have to mock // the filterLog calls for the other protocols flashloanDetector = new FlashloanDetector(['aave']); mockTxEvent.filterLog.mockReturnValueOnce([mockAaveEvent]); const flashloans = flashloanDetector.getFlashloans(mockTxEvent); expect(flashloans).toStrictEqual(['Aave']); }); it('should return the "dYdX" protocol if there is a flashloan from dYdX', () => { flashloanDetector = new FlashloanDetector(['dydx']); mockTxEvent.filterLog.mockReturnValueOnce([mockDydxWithdrawEvent, mockDydxDepositEvent]); const flashloans = flashloanDetector.getFlashloans(mockTxEvent); expect(flashloans).toStrictEqual(['dYdX']); }); it('should return the "Euler" protocol if there is a flashloan from Euler', () => { flashloanDetector = new FlashloanDetector(['euler']); mockTxEvent.filterLog.mockReturnValueOnce([mockEulerBorrowEvent, mockEulerRepayEvent]); const flashloans = flashloanDetector.getFlashloans(mockTxEvent); expect(flashloans).toStrictEqual(['Euler']); }); it('should return the "Iron Bank" protocol if there is a flashloan from Iron Bank', () => { flashloanDetector = new FlashloanDetector(['ironBank']); mockTxEvent.filterLog.mockReturnValueOnce([mockIronBankEvent]); const flashloans = flashloanDetector.getFlashloans(mockTxEvent); expect(flashloans).toStrictEqual(['Iron Bank']); }); it('should return the "MakerDAO" protocol if there is a flashloan from MakerDAO', () => { flashloanDetector = new FlashloanDetector(['maker']); mockTxEvent.filterLog.mockReturnValueOnce([mockMakerEvent]); const flashloans = flashloanDetector.getFlashloans(mockTxEvent); expect(flashloans).toStrictEqual(['MakerDAO']); }); it('should return the all protocols if there is a flashloan from all', () => { flashloanDetector = new FlashloanDetector(); mockTxEvent.filterLog.mockReturnValueOnce([mockAaveEvent]); mockTxEvent.filterLog.mockReturnValueOnce([mockDydxWithdrawEvent, mockDydxDepositEvent]); mockTxEvent.filterLog.mockReturnValueOnce([mockEulerBorrowEvent, mockEulerRepayEvent]); mockTxEvent.filterLog.mockReturnValueOnce([mockIronBankEvent]); mockTxEvent.filterLog.mockReturnValueOnce([mockMakerEvent]); const flashloans = flashloanDetector.getFlashloans(mockTxEvent); expect(flashloans).toStrictEqual(['Aave', 'dYdX', 'Euler', 'Iron Bank', 'MakerDAO']); }); }); });