From 392063c930cb9cd63b39bf294dca75eac0287efa Mon Sep 17 00:00:00 2001 From: Yijing <0xyijing@Yijings-MBP.1337.lan> Date: Mon, 26 Jun 2023 16:30:53 -0500 Subject: [PATCH] add pool created events --- build_local.sh | 8 +--- docker-compose.yml | 2 + ...00-CreateUniswapV3PoolCreatedEventTable.ts | 36 +++++++++++++++++ src/abis.ts | 39 +++++++++++++++++++ src/config.ts | 14 +++++++ src/constants.ts | 2 + src/entities/index.ts | 1 + src/entities/uniswap_v3_pool_created_event.ts | 25 ++++++++++++ src/ormconfig.ts | 2 + src/parsers/events/uniswap_v3_events.ts | 22 ++++++++++- src/scripts/pull_and_save_events_by_topic.ts | 29 +++++++++++++- 11 files changed, 171 insertions(+), 9 deletions(-) create mode 100644 migrations/ethereum/1687800088000-CreateUniswapV3PoolCreatedEventTable.ts create mode 100644 src/entities/uniswap_v3_pool_created_event.ts diff --git a/build_local.sh b/build_local.sh index 238293ff..ad43f23a 100755 --- a/build_local.sh +++ b/build_local.sh @@ -2,11 +2,7 @@ docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d postgres docker-compose -f docker-compose.yml build event-pipeline-ethereum - -# `-f docker-compose.dev.yml` add environment variables for testing docker-compose -f docker-compose.yml up event-pipeline-ethereum -docker-compose -f docker-compose.yml build token-scraper-ethereum - -# `-f docker-compose.dev.yml` add environment variables for testing -docker-compose -f docker-compose.yml up token-scraper-ethereum +# docker-compose -f docker-compose.yml build token-scraper-ethereum +# docker-compose -f docker-compose.yml up token-scraper-ethereum diff --git a/docker-compose.yml b/docker-compose.yml index e6d828fc..bb3eda4a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -47,6 +47,8 @@ services: UNISWAP_V3_VIP_SWAP_START_BLOCK: 12553659 FEAT_UNISWAP_V3_SWAP_EVENT: "true" UNISWAP_V3_SWAP_START_BLOCK: 16670838 + FEAT_UNISWAP_V3_POOL_CREATED_EVENT: "true" + UNISWAP_V3_POOL_CREATED_START_BLOCK: 16600000 FEAT_LIMIT_ORDERS: "true" V4_NATIVE_FILL_START_BLOCK: "11591021" FEAT_PLP_SWAP_EVENT: "true" diff --git a/migrations/ethereum/1687800088000-CreateUniswapV3PoolCreatedEventTable.ts b/migrations/ethereum/1687800088000-CreateUniswapV3PoolCreatedEventTable.ts new file mode 100644 index 00000000..b9b703b0 --- /dev/null +++ b/migrations/ethereum/1687800088000-CreateUniswapV3PoolCreatedEventTable.ts @@ -0,0 +1,36 @@ +import { MigrationInterface, QueryRunner, getConnection } from 'typeorm'; + +export class CreateUniswapV3PoolCreatedEventTable1687800088000 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + const connection = getConnection(); + const { schema } = connection.options as any; + await queryRunner.query(` + CREATE TABLE ${schema}.uniswap_v3_pool_created_events ( + observed_timestamp NUMERIC NOT NULL, + contract_address VARCHAR NOT NULL, + transaction_hash VARCHAR NOT NULL, + transaction_index NUMERIC NOT NULL, + log_index NUMERIC NOT NULL, + block_hash VARCHAR NOT NULL, + block_number NUMERIC NOT NULL, + token0 VARCHAR NOT NULL, + token1 VARCHAR NOT NULL, + fee INTEGER NOT NULL, + tickSpacing INTEGER NOT NULL, + pool VARCHAR NOT NULL, + PRIMARY KEY (transaction_hash, log_index) + ); + + CREATE INDEX uniswap_v3_pool_created_events_block_number_idx ON ${schema}.uniswap_v3_pool_created_events (block_number); + CREATE INDEX uniswap_v3_pool_created_events_token0_idx ON ${schema}.uniswap_v3_pool_created_events (token0); + CREATE INDEX uniswap_v3_pool_created_events_token1_idx ON ${schema}.uniswap_v3_pool_created_events (token1); + CREATE INDEX uniswap_v3_pool_created_events_pool_idx ON ${schema}.uniswap_v3_pool_created_events (pool); +`); + } + + public async down(queryRunner: QueryRunner): Promise { + const connection = getConnection(); + const { schema } = connection.options as any; + await queryRunner.query(`DROP TABLE ${schema}.uniswap_v3_pool_created_events;`); + } +} \ No newline at end of file diff --git a/src/abis.ts b/src/abis.ts index f979319a..7ee2fc2a 100644 --- a/src/abis.ts +++ b/src/abis.ts @@ -559,6 +559,45 @@ export const UNISWAP_V3_SWAP_ABI = { type: 'event', }; +export const UNISWAP_V3_POOL_CREATED_ABI = { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'token0', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'token1', + type: 'address', + }, + { + indexed: true, + internalType: 'uint24', + name: 'fee', + type: 'uint24', + }, + { + indexed: false, + internalType: 'int24', + name: 'tickSpacing', + type: 'int24', + }, + { + indexed: false, + internalType: 'address', + name: 'pool', + type: 'address', + }, + ], + name: 'PoolCreated', + type: 'event', +} + + export const TIMECHAIN_SWAP_V1_ABI = { anonymous: false, inputs: [ diff --git a/src/config.ts b/src/config.ts index 84701f7a..7fed50fb 100644 --- a/src/config.ts +++ b/src/config.ts @@ -31,6 +31,7 @@ import { DEFAULT_FEAT_UNISWAP_V2_VIP_SWAP_EVENT, DEFAULT_FEAT_UNISWAP_V3_VIP_SWAP_EVENT, DEFAULT_FEAT_UNISWAP_V3_SWAP_EVENT, + DEFAULT_FEAT_UNISWAP_V3_POOL_CREATED_EVENT, DEFAULT_FEAT_V3_FILL_EVENT, DEFAULT_FEAT_V3_NATIVE_FILL, DEFAULT_LOCAL_POSTGRES_URI, @@ -369,6 +370,19 @@ validateStartBlock( FEAT_UNISWAP_V3_VIP_SWAP_EVENT, ); +export const FEAT_UNISWAP_V3_POOL_CREATED_EVENT = getBoolConfig( + 'FEAT_UNISWAP_V3_POOL_CREATED_EVENT', + DEFAULT_FEAT_UNISWAP_V3_POOL_CREATED_EVENT, +); + +export const UNISWAP_V3_POOL_CREATED_START_BLOCK = getIntConfig('UNISWAP_V3_POOL_CREATED_START_BLOCK', -1); +validateStartBlock( + 'UNISWAP_V3_POOL_CREATED_START_BLOCK', + UNISWAP_V3_POOL_CREATED_START_BLOCK, + 'FEAT_UNISWAP_V3_POOL_CREATED_EVENT', + FEAT_UNISWAP_V3_POOL_CREATED_EVENT, +); + export const FEAT_V3_FILL_EVENT = getBoolConfig('FEAT_V3_FILL_EVENT', DEFAULT_FEAT_V3_FILL_EVENT); export const FEAT_OTC_ORDERS = getBoolConfig('FEAT_OTC_ORDERS', DEFAULT_FEAT_OTC_ORDERS); diff --git a/src/constants.ts b/src/constants.ts index 385b412c..b18091a8 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -39,6 +39,7 @@ export const DEFAULT_FEAT_UNISWAP_V2_SYNC_EVENT = false; export const DEFAULT_FEAT_UNISWAP_V2_VIP_SWAP_EVENT = false; export const DEFAULT_FEAT_UNISWAP_V3_VIP_SWAP_EVENT = false; export const DEFAULT_FEAT_UNISWAP_V3_SWAP_EVENT = false; +export const DEFAULT_FEAT_UNISWAP_V3_POOL_CREATED_EVENT = false; export const DEFAULT_FEAT_V3_FILL_EVENT = false; export const DEFAULT_FEAT_V3_NATIVE_FILL = false; export const DEFAULT_FEAT_VIP_SWAP_EVENT = false; @@ -74,6 +75,7 @@ export const V3_EXCHANGE_ADDRESS = '0x61935cbdd02287b511119ddb11aeb42f1593b7ef'; // ]; export const UNISWAP_V2_SWAP_EVENT_TOPIC_0 = '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822'; export const UNISWAP_V3_SWAP_EVENT_TOPIC_0 = '0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67'; +export const UNISWAP_V3_POOL_CREATED_TOPIC_0 = '0x783cca1c0412dd0d695e784568c96da2e9c22ff989357a2e8b1d9b2b4e6b7118'; export const V3_FILL_EVENT_TOPIC = ['0x6869791f0a34781b29882982cc39e882768cf2c96995c2a110c577c53bc932d5']; export const ERC721_ORDER_FILLED_EVENT_TOPIC = ['0x50273fa02273cceea9cf085b42de5c8af60624140168bd71357db833535877af']; diff --git a/src/entities/index.ts b/src/entities/index.ts index 0f89d0a4..28efe4be 100644 --- a/src/entities/index.ts +++ b/src/entities/index.ts @@ -4,6 +4,7 @@ export { CancelUpToEvent } from './cancel_up_to_event'; export { CurrentEpochInfo } from './current_epoch_info'; export { ERC20BridgeTransferEvent } from './erc20_bridge_transfer_event'; export { UniswapV3SwapEvent } from './uniswap_v3_swap_event'; +export { UniswapV3PoolCreatedEvent } from './uniswap_v3_pool_created_event'; export { EpochEndedEvent } from './epoch_ended_event'; export { EpochFinalizedEvent } from './epoch_finalized_event'; export { Erc1155OrderCancelledEvent } from './erc1155_order_cancelled_event'; diff --git a/src/entities/uniswap_v3_pool_created_event.ts b/src/entities/uniswap_v3_pool_created_event.ts new file mode 100644 index 00000000..6b965365 --- /dev/null +++ b/src/entities/uniswap_v3_pool_created_event.ts @@ -0,0 +1,25 @@ +import { BigNumber } from '@0x/utils'; +import { Column, Entity } from 'typeorm'; + +import { Event } from './event'; +import { bigNumberTransformer } from '../transformers'; + +// These events come directly from the Exchange contract and are fired whenever +// someone fills an order. +@Entity({ name: 'uniswap_v3_pool_created_events' }) +export class UniswapV3PoolCreatedEvent extends Event { + // The address of token0 + @Column({ name: 'token0', type: 'varchar' }) + public token0!: string; + // The address of token1 + @Column({ name: 'token1', type: 'varchar' }) + public token1!: string; + // The fee collected upon every swap in the pool, denominated in hundredths of a bip + @Column({ name: 'fee', type: 'integer' }) + public fee!: number; + @Column({ name: 'tickSpacing', type: 'integer' }) + public tickSpacing!: number; + // The address of the pool + @Column({ name: 'pool', type: 'varchar' }) + public pool!: string; +} \ No newline at end of file diff --git a/src/ormconfig.ts b/src/ormconfig.ts index 753ab9c7..1b139b32 100644 --- a/src/ormconfig.ts +++ b/src/ormconfig.ts @@ -9,6 +9,7 @@ import { CurrentEpochInfo, ERC20BridgeTransferEvent, UniswapV3SwapEvent, + UniswapV3PoolCreatedEvent, EpochEndedEvent, EpochFinalizedEvent, Erc1155OrderCancelledEvent, @@ -66,6 +67,7 @@ const entities = [ CurrentEpochInfo, ERC20BridgeTransferEvent, UniswapV3SwapEvent, + UniswapV3PoolCreatedEvent, EpochEndedEvent, EpochFinalizedEvent, Erc1155OrderCancelledEvent, diff --git a/src/parsers/events/uniswap_v3_events.ts b/src/parsers/events/uniswap_v3_events.ts index a69e3981..91baba09 100644 --- a/src/parsers/events/uniswap_v3_events.ts +++ b/src/parsers/events/uniswap_v3_events.ts @@ -1,9 +1,9 @@ const abiCoder = require('web3-eth-abi'); import { RawLogEntry } from 'ethereum-types'; -import { ERC20BridgeTransferEvent, UniswapV3SwapEvent } from '../../entities'; +import { ERC20BridgeTransferEvent, UniswapV3SwapEvent, UniswapV3PoolCreatedEvent } from '../../entities'; import { parseEvent } from './parse_event'; -import { UNISWAP_V3_SWAP_ABI } from '../../constants'; +import { UNISWAP_V3_SWAP_ABI, UNISWAP_V3_POOL_CREATED_ABI } from '../../constants'; import { BigNumber } from '@0x/utils'; export function parseUniswapV3VIPSwapEvent(eventLog: RawLogEntry): ERC20BridgeTransferEvent { @@ -52,3 +52,21 @@ export function parseUniswapV3SwapEvent(eventLog: RawLogEntry): UniswapV3SwapEve return uniswapV3SwapEvent; } + +export function parseUniswapV3PoolCreatedEvent(eventLog: RawLogEntry, protocol: string): UniswapV3PoolCreatedEvent { + const UniswapV3poolCreated = new UniswapV3PoolCreatedEvent(); + parseEvent(eventLog, UniswapV3poolCreated); + const decodedLog = abiCoder.decodeLog(UNISWAP_V3_POOL_CREATED_ABI.inputs, eventLog.data, [ + eventLog.topics[1], + eventLog.topics[2], + eventLog.topics[3], + ]); + + UniswapV3poolCreated.token0 = decodedLog.token0.toLowerCase(); + UniswapV3poolCreated.token1 = decodedLog.token1.toLowerCase(); + UniswapV3poolCreated.fee = decodedLog.fee; + UniswapV3poolCreated.tickSpacing = decodedLog.tickSpacing; + UniswapV3poolCreated.pool = decodedLog.pool.toLowerCase(); + + return UniswapV3poolCreated; +} diff --git a/src/scripts/pull_and_save_events_by_topic.ts b/src/scripts/pull_and_save_events_by_topic.ts index 0f486824..20715354 100644 --- a/src/scripts/pull_and_save_events_by_topic.ts +++ b/src/scripts/pull_and_save_events_by_topic.ts @@ -37,6 +37,7 @@ import { V4LimitOrderFilledEvent, V4RfqOrderFilledEvent, UniswapV3SwapEvent, + UniswapV3PoolCreatedEvent, OnchainGovernanceProposalCreatedEvent, OnchainGovernanceCallScheduledEvent, } from '../entities'; @@ -67,6 +68,7 @@ import { FEAT_UNISWAP_V2_VIP_SWAP_EVENT, FEAT_UNISWAP_V3_VIP_SWAP_EVENT, FEAT_UNISWAP_V3_SWAP_EVENT, + FEAT_UNISWAP_V3_POOL_CREATED_EVENT, FEAT_V3_FILL_EVENT, FEAT_V3_NATIVE_FILL, FEAT_ONCHAIN_GOVERNANCE, @@ -95,6 +97,7 @@ import { UNISWAP_V2_VIP_SWAP_START_BLOCK, UNISWAP_V3_VIP_SWAP_START_BLOCK, UNISWAP_V3_SWAP_START_BLOCK, + UNISWAP_V3_POOL_CREATED_START_BLOCK, V4_NATIVE_FILL_START_BLOCK, ONCHAIN_GOVERNANCE_START_BLOCK, } from '../config'; @@ -126,6 +129,7 @@ import { SLINGSHOT_TRADE_EVENT_TOPIC, UNISWAP_V2_SWAP_EVENT_TOPIC_0, UNISWAP_V3_SWAP_EVENT_TOPIC_0, + UNISWAP_V3_POOL_CREATED_TOPIC_0, TIMECHAIN_SWAP_V1_EVENT_TOPIC, TIMECHAIN_V1_CONTRACT_ADDRESS, TRANSFORMEDERC20_EVENT_TOPIC, @@ -157,7 +161,11 @@ import { parseV4RfqOrderFilledEvent, } from '../parsers/events/v4_rfq_order_filled_events'; import { parseTimechainSwapV1Event } from '../parsers/events/timechain_swap_event'; -import { parseUniswapV3VIPSwapEvent, parseUniswapV3SwapEvent } from '../parsers/events/uniswap_v3_events'; +import { + parseUniswapV3VIPSwapEvent, + parseUniswapV3SwapEvent, + parseUniswapV3PoolCreatedEvent, +} from '../parsers/events/uniswap_v3_events'; import { parseNativeFillFromV4LimitOrderFilledEvent, parseV4LimitOrderFilledEvent, @@ -478,6 +486,25 @@ export class EventsByTopicScraper { ); } + if (FEAT_UNISWAP_V3_POOL_CREATED_EVENT) { + promises.push( + pullAndSaveEventsByTopic.getParseSaveEventsByTopic( + connection, + producer, + web3Source, + latestBlockWithOffset, + 'UniswapV3PoolCreatedEvent', + UniswapV3PoolCreatedEvent, + 'uniswap_v3_pool_created_events', + [UNISWAP_V3_POOL_CREATED_EVENT_TOPIC_0], + 'nofilter', + UNISWAP_V3_POOL_CREATED_START_BLOCK, + parseUniswapV3PoolCreatedEvent, + {}, + ), + ); + } + if (FEAT_RFQ_EVENT) { promises.push( pullAndSaveEventsByTopic.getParseSaveEventsByTopic(