From 991ec9ba0366cf4f7c4cac831842581d9e01efdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20P=C3=A9rez?= Date: Mon, 26 Jun 2023 21:11:02 +0200 Subject: [PATCH] Use Pool Created Events to verify VIP Uni v2 Events --- docker-compose.yml | 26 +++---- src/events.ts | 37 ++++++++++ src/index.ts | 6 ++ src/parsers/events/uniswap_v2_events.ts | 24 +++++-- src/scripts/backfill_events.ts | 1 + src/scripts/pull_and_save_events_by_topic.ts | 1 + src/scripts/utils/event_abi_utils.ts | 72 ++++---------------- src/uniV2PoolSingleton.ts | 54 +++++++++++++++ src/utils/metrics.ts | 6 ++ 9 files changed, 150 insertions(+), 77 deletions(-) create mode 100644 src/uniV2PoolSingleton.ts diff --git a/docker-compose.yml b/docker-compose.yml index 69c06a2c..ac82a699 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -43,31 +43,31 @@ services: FEAT_UNISWAP_V2_VIP_SWAP_EVENT: "true" UNISWAP_V2_VIP_SWAP_SOURCES: "UniswapV2,SushiSwap" UNISWAP_V2_VIP_SWAP_START_BLOCK: 10917104 - FEAT_UNISWAP_V3_VIP_SWAP_EVENT: "true" + FEAT_UNISWAP_V3_VIP_SWAP_EVENT: "false" UNISWAP_V3_VIP_SWAP_START_BLOCK: 12553659 - FEAT_UNISWAP_V3_SWAP_EVENT: "true" + FEAT_UNISWAP_V3_SWAP_EVENT: "false" UNISWAP_V3_SWAP_START_BLOCK: 16670838 - FEAT_LIMIT_ORDERS: "true" + FEAT_LIMIT_ORDERS: "false" V4_NATIVE_FILL_START_BLOCK: "11591021" - FEAT_PLP_SWAP_EVENT: "true" + FEAT_PLP_SWAP_EVENT: "false" PLP_VIP_START_BLOCK: 11377457 - FEAT_OTC_ORDERS: "true" + FEAT_OTC_ORDERS: "false" OTC_ORDERS_FEATURE_START_BLOCK: 13143075 - FEAT_CANCEL_EVENTS: "true" - FEAT_STAKING: "true" + FEAT_CANCEL_EVENTS: "false" + FEAT_STAKING: "false" STAKING_DEPLOYMENT_BLOCK: 8952581 - FEAT_RFQ_EVENT: "true" - FEAT_V3_NATIVE_FILL: "true" - FEAT_ERC20_BRIDGE_TRANSFER_FLASHWALLET: "true" + FEAT_RFQ_EVENT: "false" + FEAT_V3_NATIVE_FILL: "false" + FEAT_ERC20_BRIDGE_TRANSFER_FLASHWALLET: "false" FLASHWALLET_ADDRESS: "0x22f9dcf4647084d6c31b2765f6910cd85c178c18" FLASHWALLET_DEPLOYMENT_BLOCK: 12231666 - FEAT_NFT: "true" + FEAT_NFT: "false" NFT_FEATURE_START_BLOCK: 14258205 FEAT_UNISWAP_V2_PAIR_CREATED_EVENT: "true" UNISWAP_V2_PAIR_CREATED_PROTOCOL_CONTRACT_ADDRESSES_AND_START_BLOCKS: "UniswapV2:0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f:10000835,SushiSwap:0xc0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac:10794229" - FEAT_UNISWAP_V2_SYNC_EVENT: "true" + FEAT_UNISWAP_V2_SYNC_EVENT: "false" UNISWAP_V2_SYNC_START_BLOCK: 10000835 - FEAT_ONCHAIN_GOVERNANCE: "true" + FEAT_ONCHAIN_GOVERNANCE: "false" ONCHAIN_GOVERNANCE_START_BLOCK: 16990159 event-pipeline-bsc: diff --git a/src/events.ts b/src/events.ts index c90a99d7..136aa574 100644 --- a/src/events.ts +++ b/src/events.ts @@ -138,6 +138,12 @@ import { } from './parsers/events/onchain_governance_events'; import { TokenMetadataMap } from './scripts/utils/web3_utils'; +import { UniV2PoolSingleton } from './uniV2PoolSingleton'; + +function uniV2PoolSingletonCallback(pools: UniswapV2PairCreatedEvent[]) { + const uniV2PoolSingleton = UniV2PoolSingleton.getInstance(); + uniV2PoolSingleton.addNewPools(pools); +} export type CommonEventParams = { connection: Connection; @@ -156,6 +162,7 @@ export type EventScraperProps = { parser: (decodedLog: RawLogEntry) => any; deleteOptions: DeleteOptions; tokenMetadataMap: TokenMetadataMap; + callback: any | null; }; export const eventScrperProps: EventScraperProps[] = [ @@ -170,6 +177,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseTransformedERC20Event, deleteOptions: {}, tokenMetadataMap: null, + callback: null, }, { enabled: FEAT_UNISWAP_V3_VIP_SWAP_EVENT, @@ -182,6 +190,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseUniswapV3VIPSwapEvent, deleteOptions: { isDirectTrade: true, directProtocol: ['UniswapV3'] }, tokenMetadataMap: { tokenA: 'fromToken', tokenB: 'toToken' }, + callback: null, }, { enabled: FEAT_ERC20_BRIDGE_TRANSFER_FLASHWALLET, @@ -194,6 +203,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseBridgeFill, deleteOptions: { isDirectTrade: false }, tokenMetadataMap: { tokenA: 'fromToken', tokenB: 'toToken' }, + callback: null, }, { enabled: FEAT_UNISWAP_V2_VIP_SWAP_EVENT, @@ -206,6 +216,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseUniswapV2SwapEvent, deleteOptions: { isDirectTrade: true, directProtocol: UNISWAP_V2_VIP_SWAP_SOURCES }, tokenMetadataMap: { tokenA: 'fromToken', tokenB: 'toToken' }, + callback: null, }, { enabled: FEAT_UNISWAP_V3_VIP_SWAP_EVENT, @@ -218,6 +229,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseUniswapV3SwapEvent, deleteOptions: { isDirectTrade: true, directProtocol: ['UniswapV3'] }, tokenMetadataMap: { tokenA: 'fromToken', tokenB: 'toToken' }, + callback: null, }, { enabled: FEAT_RFQ_EVENT, @@ -230,6 +242,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseV4RfqOrderFilledEvent, deleteOptions: {}, tokenMetadataMap: { tokenA: 'makerToken', tokenB: 'takerToken' }, + callback: null, }, { enabled: FEAT_RFQ_EVENT, @@ -242,6 +255,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseNativeFillFromV4RfqOrderFilledEvent, deleteOptions: { protocolVersion: 'v4', nativeOrderType: 'RFQ Order' }, tokenMetadataMap: null, + callback: null, }, { enabled: FEAT_RFQ_EVENT, @@ -254,6 +268,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseExpiredRfqOrderEvent, deleteOptions: {}, tokenMetadataMap: null, + callback: null, }, { enabled: FEAT_LIMIT_ORDERS, @@ -266,6 +281,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseV4LimitOrderFilledEvent, deleteOptions: {}, tokenMetadataMap: { tokenA: 'makerToken', tokenB: 'takerToken' }, + callback: null, }, { enabled: FEAT_LIMIT_ORDERS, @@ -278,6 +294,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseNativeFillFromV4LimitOrderFilledEvent, deleteOptions: { protocolVersion: 'v4', nativeOrderType: 'Limit Order' }, tokenMetadataMap: null, + callback: null, }, { enabled: FEAT_RFQ_EVENT || FEAT_LIMIT_ORDERS, @@ -290,6 +307,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseV4CancelEvent, deleteOptions: {}, tokenMetadataMap: null, + callback: null, }, { enabled: FEAT_OTC_ORDERS, @@ -302,6 +320,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseOtcOrderFilledEvent, deleteOptions: {}, tokenMetadataMap: { tokenA: 'makerTokenAddress', tokenB: 'takerTokenAddress' }, + callback: null, }, { enabled: FEAT_OTC_ORDERS, @@ -314,6 +333,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseNativeFillFromV4OtcOrderFilledEvent, deleteOptions: { protocolVersion: 'v4', nativeOrderType: 'OTC Order' }, tokenMetadataMap: null, + callback: null, }, { enabled: FEAT_V3_FILL_EVENT, @@ -326,6 +346,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseFillEvent, deleteOptions: {}, tokenMetadataMap: { tokenA: 'makerTokenAddress', tokenB: 'takerTokenAddress' }, + callback: null, }, { enabled: FEAT_V3_NATIVE_FILL, @@ -338,6 +359,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseNativeFillFromFillEvent, deleteOptions: { protocolVersion: 'v3' }, tokenMetadataMap: null, + callback: null, }, { enabled: FEAT_NFT, @@ -350,6 +372,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseErc721OrderFilledEvent, deleteOptions: {}, tokenMetadataMap: { tokenA: 'erc20Token', tokenB: 'erc721Token' }, + callback: null, }, { enabled: FEAT_NFT, @@ -362,6 +385,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseErc721OrderCancelledEvent, deleteOptions: {}, tokenMetadataMap: null, + callback: null, }, { enabled: FEAT_NFT, @@ -374,6 +398,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseErc721OrderPresignedEvent, deleteOptions: {}, tokenMetadataMap: { tokenA: 'erc20Token', tokenB: 'erc721Token' }, + callback: null, }, { enabled: FEAT_NFT, @@ -386,6 +411,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseErc1155OrderFilledEvent, deleteOptions: {}, tokenMetadataMap: { tokenA: 'erc20Token', tokenB: 'erc1155Token' }, + callback: null, }, { enabled: FEAT_NFT, @@ -398,6 +424,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseErc1155OrderCancelledEvent, deleteOptions: {}, tokenMetadataMap: null, + callback: null, }, { enabled: FEAT_NFT, @@ -410,6 +437,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseErc1155OrderPresignedEvent, deleteOptions: {}, tokenMetadataMap: { tokenA: 'erc20Token', tokenB: 'erc1155Token' }, + callback: null, }, { enabled: FEAT_UNISWAP_V2_SYNC_EVENT, @@ -422,6 +450,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseUniswapV2SyncEvent, deleteOptions: {}, tokenMetadataMap: null, + callback: null, }, { enabled: FEAT_META_TRANSACTION_EXECUTED_EVENT, @@ -434,6 +463,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseMetaTransactionExecutedEvent, deleteOptions: {}, tokenMetadataMap: null, + callback: null, }, { enabled: FEAT_UNISWAP_V3_SWAP_EVENT, @@ -446,6 +476,7 @@ export const eventScrperProps: EventScraperProps[] = [ parser: parseUniswapV3SwapEvent, deleteOptions: {}, tokenMetadataMap: null, + callback: null, }, { enabled: FEAT_ONCHAIN_GOVERNANCE, @@ -459,6 +490,7 @@ export const eventScrperProps: EventScraperProps[] = [ parseOnchainGovernanceProposalCreatedEvent(decodedLog, 'ZeroexTreasuryGovernor'), deleteOptions: {}, tokenMetadataMap: null, + callback: null, }, { enabled: FEAT_ONCHAIN_GOVERNANCE, @@ -473,6 +505,7 @@ export const eventScrperProps: EventScraperProps[] = [ parseOnchainGovernanceProposalCreatedEvent(decodedLog, 'ZeroexProtocolGovernor'), deleteOptions: {}, tokenMetadataMap: null, + callback: null, }, { enabled: FEAT_ONCHAIN_GOVERNANCE, @@ -486,6 +519,7 @@ export const eventScrperProps: EventScraperProps[] = [ parseOnchainGovernanceCallScheduledEvent(decodedLog, 'TreasuryZeroexTimelock'), deleteOptions: {}, tokenMetadataMap: null, + callback: null, }, { enabled: FEAT_ONCHAIN_GOVERNANCE, @@ -499,6 +533,7 @@ export const eventScrperProps: EventScraperProps[] = [ parseOnchainGovernanceCallScheduledEvent(decodedLog, 'ProtocolZeroexTimelock'), deleteOptions: {}, tokenMetadataMap: null, + callback: null, }, ]; @@ -519,6 +554,7 @@ for (const payment_recipient of POLYGON_RFQM_PAYMENTS_ADDRESSES) { parser: parseLogTransferEvent, deleteOptions: { recipient: payment_recipient }, tokenMetadataMap: null, + callback: null, }); } @@ -534,6 +570,7 @@ for (const protocol of UNISWAP_V2_PAIR_CREATED_PROTOCOL_CONTRACT_ADDRESSES_AND_S parser: (decodedLog: RawLogEntry) => parseUniswapV2PairCreatedEvent(decodedLog, protocol.name), deleteOptions: { protocol: protocol.name }, tokenMetadataMap: { tokenA: 'token0', tokenB: 'token1' }, + callback: uniV2PoolSingletonCallback, }); } diff --git a/src/index.ts b/src/index.ts index 6702be85..fc4a6f9d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -30,6 +30,7 @@ import { ChainIdChecker } from './scripts/check_chain_id'; import { CurrentBlockMonitor } from './scripts/monitor_current_block'; import { startMetricsServer } from './utils/metrics'; import { TokenMetadataSingleton } from './tokenMetadataSingleton'; +import { UniV2PoolSingleton } from './uniV2PoolSingleton'; const kafka = new Kafka({ clientId: 'event-pipeline', @@ -69,6 +70,11 @@ createConnection(ormConfig as ConnectionOptions) .then(async (connection) => { await producer.connect(); await TokenMetadataSingleton.getInstance(connection, producer); + await UniV2PoolSingleton.initInstance(connection); + + const uniV2PoolSingleton = UniV2PoolSingleton.getInstance(); + const poolInfo = uniV2PoolSingleton.getPool('0x1bb1d4ad0a83cbf44f111bb0688c78aa94f4255e'); + schedule(null, null, currentBlockMonitor.monitor, 'Current Block'); schedule(connection, producer, blockScraper.getParseSaveEventsAsync, 'Pull and Save Blocks'); diff --git a/src/parsers/events/uniswap_v2_events.ts b/src/parsers/events/uniswap_v2_events.ts index 2fdeff5f..f55fe685 100644 --- a/src/parsers/events/uniswap_v2_events.ts +++ b/src/parsers/events/uniswap_v2_events.ts @@ -1,12 +1,14 @@ const abiCoder = require('web3-eth-abi'); import { RawLogEntry } from 'ethereum-types'; +import { logger } from '../../utils/logger'; import { ERC20BridgeTransferEvent, UniswapV2PairCreatedEvent, UniswapV2SyncEvent } from '../../entities'; import { parseEvent } from './parse_event'; import { UNISWAP_V2_SWAP_ABI, UNISWAP_V2_SYNC_ABI, UNISWAP_V2_PAIR_CREATED_ABI } from '../../constants'; import { BigNumber } from '@0x/utils'; +import { UniV2PoolSingleton } from '../../uniV2PoolSingleton'; -export function parseUniswapV2SwapEvent(eventLog: RawLogEntry): ERC20BridgeTransferEvent { +export function parseUniswapV2SwapEvent(eventLog: RawLogEntry): ERC20BridgeTransferEvent | null { const eRC20BridgeTransferEvent = new ERC20BridgeTransferEvent(); parseEvent(eventLog, eRC20BridgeTransferEvent); // decode the basic info directly into eRC20BridgeTransferEvent @@ -15,13 +17,25 @@ export function parseUniswapV2SwapEvent(eventLog: RawLogEntry): ERC20BridgeTrans eventLog.topics[2], ]); + const uniV2PoolSingleton = UniV2PoolSingleton.getInstance(); + + const poolInfo = uniV2PoolSingleton.getPool(eRC20BridgeTransferEvent.contractAddress); + + if (poolInfo === undefined) { + logger.error( + `Got a Uni v2 VIP trade from an unknown pool, ignoring. Tx: ${eRC20BridgeTransferEvent.transactionHash}, Pool: ${eRC20BridgeTransferEvent.contractAddress}`, + ); + return null; + } + const { token0, token1, protocol } = poolInfo; + const amount0In = new BigNumber(decodedLog.amount0In); const amount1In = new BigNumber(decodedLog.amount1In); const amount0Out = new BigNumber(decodedLog.amount0Out); const amount1Out = new BigNumber(decodedLog.amount1Out); - eRC20BridgeTransferEvent.fromToken = amount0In.gt(amount0Out) ? '0' : '1'; // taker_token - eRC20BridgeTransferEvent.toToken = amount0In.gt(amount0Out) ? '1' : '0'; // maker_token + eRC20BridgeTransferEvent.fromToken = amount0In.gt(amount0Out) ? token0 : token1; // taker_token + eRC20BridgeTransferEvent.toToken = amount0In.gt(amount0Out) ? token1 : token0; // maker_token eRC20BridgeTransferEvent.fromTokenAmount = new BigNumber( amount0In.gt(amount0Out) ? amount0In.minus(amount0Out) : amount1In.minus(amount1Out), @@ -29,10 +43,10 @@ export function parseUniswapV2SwapEvent(eventLog: RawLogEntry): ERC20BridgeTrans eRC20BridgeTransferEvent.toTokenAmount = new BigNumber( amount0In.gt(amount0Out) ? amount1Out.minus(amount1In) : amount0Out.minus(amount0In), ); // maker_token_amount - eRC20BridgeTransferEvent.from = ''; // maker + eRC20BridgeTransferEvent.from = protocol; // maker TODO(jorge): Replace with pool address, after checking downstream impact eRC20BridgeTransferEvent.to = decodedLog.to.toLowerCase(); // taker eRC20BridgeTransferEvent.directFlag = true; - eRC20BridgeTransferEvent.directProtocol = ''; + eRC20BridgeTransferEvent.directProtocol = protocol; return eRC20BridgeTransferEvent; } diff --git a/src/scripts/backfill_events.ts b/src/scripts/backfill_events.ts index ae46caba..e827e16f 100644 --- a/src/scripts/backfill_events.ts +++ b/src/scripts/backfill_events.ts @@ -69,6 +69,7 @@ export class EventsBackfillScraper { props.parser, props.deleteOptions, props.tokenMetadataMap, + props.callback, backfillEventsOldestBlock.get(props.name)!, ) .then(async ({ transactionHashes, startBlockNumber, endBlockNumber }) => { diff --git a/src/scripts/pull_and_save_events_by_topic.ts b/src/scripts/pull_and_save_events_by_topic.ts index 8fd20bf2..385b2f78 100644 --- a/src/scripts/pull_and_save_events_by_topic.ts +++ b/src/scripts/pull_and_save_events_by_topic.ts @@ -53,6 +53,7 @@ export class EventsByTopicScraper { props.parser, props.deleteOptions, props.tokenMetadataMap, + props.callback, ), ); } diff --git a/src/scripts/utils/event_abi_utils.ts b/src/scripts/utils/event_abi_utils.ts index 7a3773f1..0f2fde08 100644 --- a/src/scripts/utils/event_abi_utils.ts +++ b/src/scripts/utils/event_abi_utils.ts @@ -12,7 +12,7 @@ import { RawLogEntry } from 'ethereum-types'; import { CHAIN_NAME_LOWER, MAX_BLOCKS_REORG, MAX_BLOCKS_TO_SEARCH, SCHEMA } from '../../config'; import { LastBlockProcessed } from '../../entities'; -import { SCAN_END_BLOCK, RPC_LOGS_ERROR, SCAN_RESULTS, SCAN_START_BLOCK } from '../../utils/metrics'; +import { SCAN_END_BLOCK, RPC_LOGS_ERROR, SCAN_RESULTS, SCAN_START_BLOCK, SKIPPED_EVENTS } from '../../utils/metrics'; export interface DeleteOptions { isDirectTrade?: boolean; @@ -44,6 +44,7 @@ export class PullAndSaveEventsByTopic { parser: (decodedLog: RawLogEntry) => Event, deleteOptions: DeleteOptions, tokenMetadataMap: TokenMetadataMap = null, + callback: (event: Event) => void, ): Promise { let startBlockResponse; try { @@ -91,6 +92,7 @@ export class PullAndSaveEventsByTopic { parser, deleteOptions, tokenMetadataMap, + callback, startBlockNumber, endBlockNumber, endBlockHash!, @@ -114,6 +116,7 @@ export class PullAndSaveEventsByTopic { parser: (decodedLog: RawLogEntry) => Event, deleteOptions: DeleteOptions, tokenMetadataMap: TokenMetadataMap = null, + callback: (event: Event) => void, startBlockNumber: number, ): Promise { const endBlockNumber = Math.min( @@ -143,6 +146,7 @@ export class PullAndSaveEventsByTopic { parser, deleteOptions, tokenMetadataMap, + callback, startBlockNumber, endBlockNumber, endBlockHash!, @@ -165,6 +169,7 @@ export class PullAndSaveEventsByTopic { parser: (decodedLog: RawLogEntry) => Event, deleteOptions: DeleteOptions, tokenMetadataMap: TokenMetadataMap = null, + callback: (event: Event) => void, startBlockNumber: number, endBlockNumber: number, endBlockHash: string, @@ -191,7 +196,13 @@ export class PullAndSaveEventsByTopic { let txHashes: string[] = []; await Promise.all( rawLogsArray.map(async (rawLogs) => { - const parsedLogs = rawLogs.logs.map((encodedLog: RawLogEntry) => parser(encodedLog)); + const parsedLogsWithSkipped = rawLogs.logs.map((encodedLog: RawLogEntry) => parser(encodedLog)); + + const parsedLogs = parsedLogsWithSkipped.filter((log: Event) => log !== null); + SKIPPED_EVENTS.inc( + { type: scrapingType, event: eventName }, + parsedLogsWithSkipped.length - parsedLogs.length, + ); const reorgedEvents = parsedLogs.filter((log: Event) => { return log.blockNumber == endBlockNumber && log.blockHash != endBlockHash; @@ -201,63 +212,6 @@ export class PullAndSaveEventsByTopic { throw Error(); } - if (eventName === 'VIPSwapEvent' && parsedLogs.length > 0) { - const contractCallToken0Array = []; - const contractCallToken1Array = []; - - const contractCallProtocolNameArray = []; - - for (const index in parsedLogs) { - const contract_address: string = (parsedLogs[index] as any).contractAddress; - - const contractCallToken0: ContractCallInfo = { - to: contract_address, - data: '0x0dfe1681', - }; - contractCallToken0Array.push(contractCallToken0); - - const contractCallToken1: ContractCallInfo = { - to: contract_address, - data: '0xd21220a7', - }; - contractCallToken1Array.push(contractCallToken1); - - const contractCallProtocolName: ContractCallInfo = { - to: contract_address, - data: '0x06fdde03', - }; - contractCallProtocolNameArray.push(contractCallProtocolName); - } - - const token0 = await web3Source.callContractMethodsAsync(contractCallToken0Array); - const token1 = await web3Source.callContractMethodsAsync(contractCallToken1Array); - const protocolName = await web3Source.callContractMethodsAsync(contractCallProtocolNameArray); - - for (let i = 0; i < parsedLogs.length; i++) { - const token0_i = '0x' + token0[i].slice(2).slice(token0[i].length == 66 ? 64 - 40 : 0); - const token1_i = '0x' + token1[i].slice(2).slice(token1[i].length == 66 ? 64 - 40 : 0); - parsedLogs[i].fromToken = parsedLogs[i].fromToken === '0' ? token0_i : token1_i; - parsedLogs[i].toToken = parsedLogs[i].toToken === '0' ? token0_i : token1_i; - - const protocolName_i = hexToUtf8('0x' + protocolName[i].slice(98)) - .split('LP')[0] - .split(' ')[0] - .slice(1); - - // Legacy compatibility - if (protocolName_i === 'Uniswap') { - parsedLogs[i].from = 'UniswapV2'; - parsedLogs[i].directProtocol = 'UniswapV2'; - } else { - parsedLogs[i].from = protocolName_i.includes('Swap') - ? protocolName_i - : protocolName_i + 'Swap'; - parsedLogs[i].directProtocol = protocolName_i.includes('Swap') - ? protocolName_i - : protocolName_i + 'Swap'; - } - } - } if (eventName === 'UniswapV3VIPEvent' && parsedLogs.length > 0) { const contractCallToken0Array = []; const contractCallToken1Array = []; diff --git a/src/uniV2PoolSingleton.ts b/src/uniV2PoolSingleton.ts new file mode 100644 index 00000000..132478b8 --- /dev/null +++ b/src/uniV2PoolSingleton.ts @@ -0,0 +1,54 @@ +import { Connection } from 'typeorm'; +import { UniswapV2PairCreatedEvent } from './entities'; + +export class UniV2PoolSingleton { + private static instance: UniV2PoolSingleton; + private pools: Map< + string, + { + token0: string; + token1: string; + protocol: string; + } + >; + + private constructor() { + this.pools = new Map< + string, + { + token0: string; + token1: string; + protocol: string; + } + >(); + } + + static async initInstance(connection: Connection): Promise { + if (!UniV2PoolSingleton.instance) { + UniV2PoolSingleton.instance = new UniV2PoolSingleton(); + const newPools = await connection.getRepository(UniswapV2PairCreatedEvent).find(); + UniV2PoolSingleton.instance.addNewPools(newPools); + } + } + + static getInstance(): UniV2PoolSingleton { + if (!UniV2PoolSingleton.instance) { + throw Error('Must initialize Uni v2 Pool Singleton before use'); + } + return UniV2PoolSingleton.instance; + } + + addNewPools(newPools: UniswapV2PairCreatedEvent[]) { + newPools.forEach((pool) => + this.pools.set(pool.pair, { + token0: pool.token0, + token1: pool.token1, + protocol: pool.protocol, + }), + ); + } + + getPool(address: string) { + return this.pools.get(address); + } +} diff --git a/src/utils/metrics.ts b/src/utils/metrics.ts index cd7f83c3..8620c33c 100644 --- a/src/utils/metrics.ts +++ b/src/utils/metrics.ts @@ -34,6 +34,12 @@ export const RPC_LOGS_ERROR = new Gauge({ labelNames: ['type', 'event'], }); +export const SKIPPED_EVENTS = new Gauge({ + name: 'event_scraper_skipped_events', + help: 'Counter for events that where skipped', + labelNames: ['type', 'event'], +}); + export const startMetricsServer = (): void => { const defaultLabels = { chain: CHAIN_NAME }; register.setDefaultLabels(defaultLabels);