From a6c379a8e05095afb6f09173d7b2cbadfa89f358 Mon Sep 17 00:00:00 2001 From: 0xyijing <120416247+0xyijing@users.noreply.github.com> Date: Wed, 10 Jan 2024 12:47:38 +0100 Subject: [PATCH] Fix/uniswap v3 events DENG-25 (#132) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add pool created events * add changes * minor adjustments * add trailing line * add ; * add uni v3 create pool address * prettier * Cleanup --------- Co-authored-by: Yijing <0xyijing@Yijings-MBP.1337.lan> Co-authored-by: Jorge PĂ©rez --- docker-compose.yml | 3 ++ ...00-CreateUniswapV3PoolCreatedEventTable.ts | 36 ++++++++++++++ src/abis.ts | 38 ++++++++++++++ src/config.ts | 22 +++++++++ src/constants.ts | 13 ++--- src/entities/index.ts | 1 + src/entities/uniswap_v3_pool_created_event.ts | 21 ++++++++ src/events.ts | 49 +++++++++++-------- src/ormconfig.ts | 2 + src/parsers/events/uniswap_v3_events.ts | 22 ++++++++- 10 files changed, 174 insertions(+), 33 deletions(-) create mode 100644 migrations/ethereum/1687800088000-CreateUniswapV3PoolCreatedEventTable.ts create mode 100644 src/entities/uniswap_v3_pool_created_event.ts diff --git a/docker-compose.yml b/docker-compose.yml index 28bdfd06..5355b3df 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -48,6 +48,9 @@ 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: 12369621 + UNISWAP_V3_FACTORY_ADDRESS: "0x1f98431c8ad98523631ae4a59f267346ea31f984" 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..222f5ed2 --- /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, + tick_spacing 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;`); + } +} diff --git a/src/abis.ts b/src/abis.ts index e35d74c1..de45cfa5 100644 --- a/src/abis.ts +++ b/src/abis.ts @@ -480,6 +480,44 @@ 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 OTC_ORDER_FILLED_ABI = { anonymous: false, inputs: [ diff --git a/src/config.ts b/src/config.ts index fd006538..17339fc7 100644 --- a/src/config.ts +++ b/src/config.ts @@ -20,6 +20,7 @@ import { DEFAULT_FEAT_UNISWAP_V2_PAIR_CREATED_EVENT, DEFAULT_FEAT_UNISWAP_V2_SYNC_EVENT, DEFAULT_FEAT_UNISWAP_V2_VIP_SWAP_EVENT, + DEFAULT_FEAT_UNISWAP_V3_POOL_CREATED_EVENT, DEFAULT_FEAT_UNISWAP_V3_SWAP_EVENT, DEFAULT_FEAT_UNISWAP_V3_VIP_SWAP_EVENT, DEFAULT_FEAT_V3_FILL_EVENT, @@ -247,6 +248,27 @@ 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 UNISWAP_V3_FACTORY_ADDRESS = process.env.UNISWAP_V3_FACTORY_ADDRESS || ''; +validateAddress( + 'UNISWAP_V3_FACTORY_ADDRESS', + UNISWAP_V3_FACTORY_ADDRESS, + '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 d7e6d9c4..0a503fd6 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -32,6 +32,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; @@ -58,16 +59,10 @@ export const UNISWAP_V2_PAIR_CREATED_TOPIC = ['0x0d3648bd0f6ba80134a33ba9275ac58 export const UNISWAP_V2_SYNC_TOPIC = ['0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1']; export const V3_EXCHANGE_ADDRESS = '0x61935cbdd02287b511119ddb11aeb42f1593b7ef'; -// export const UNISWAP_V2_SWAP_EVENT_TOPIC = [ -// '0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822', -// '0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff', -// ]; -// export const UNISWAP_V3_SWAP_EVENT_TOPIC = [ -// '0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67', -// '0x000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff', -// ]; + 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']; @@ -109,8 +104,6 @@ export const ONCHAIN_GOVERNANCE_PROPOSAL_CREATED_EVENT_TOPIC = [ '0x7d84a6263ae0d98d3329bd7b46bb4e8d6f98cd35a7adb45c274c8b7fd5ebd5e0', ]; -export const DEFAULT_UNISWAP_V3_FACTORY_ADDRESS = '0x1f98431c8ad98523631ae4a59f267346ea31f984'; - export const SOCKET_BRIDGE_CONTRACT_ADDRESS = '0x3a23f943181408eac424116af7b7790c94cb97a5'; export const SOCKET_BRIDGE_EVENT_TOPIC = ['0x74594da9e31ee4068e17809037db37db496702bf7d8d63afe6f97949277d1609']; export const SOCKET_BRIDGE_MATCHA_METADATA = '0x0000000000000000000000000000000000000000000000000000000000000932'; diff --git a/src/entities/index.ts b/src/entities/index.ts index 169d71ea..192499de 100644 --- a/src/entities/index.ts +++ b/src/entities/index.ts @@ -42,6 +42,7 @@ export { TransactionReceipt } from './transaction_receipt'; export { TransformedERC20Event } from './transformed_erc20_event'; export { UniswapV2PairCreatedEvent } from './uniswap_v2_pair_created_event'; export { UniswapV2SyncEvent } from './uniswap_v2_sync_event'; +export { UniswapV3PoolCreatedEvent } from './uniswap_v3_pool_created_event'; export { UniswapV3SwapEvent } from './uniswap_v3_swap_event'; export { UnstakeEvent } from './unstake_event'; export { UnwrapNativeEvent } from './unwrap_native_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..df40c336 --- /dev/null +++ b/src/entities/uniswap_v3_pool_created_event.ts @@ -0,0 +1,21 @@ +import { Column, Entity } from 'typeorm'; + +import { Event } from './event'; + +@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: 'tick_spacing', type: 'integer' }) + public tickSpacing!: number; + // The address of the pool + @Column({ name: 'pool', type: 'varchar' }) + public pool!: string; +} diff --git a/src/events.ts b/src/events.ts index 3921865a..d7a8ea5f 100644 --- a/src/events.ts +++ b/src/events.ts @@ -24,12 +24,13 @@ import { TransformedERC20Event, UniswapV2PairCreatedEvent, UniswapV2SyncEvent, + UniswapV3PoolCreatedEvent, UniswapV3SwapEvent, + UnwrapNativeEvent, V4CancelEvent, V4LimitOrderFilledEvent, V4RfqOrderFilledEvent, WrapNativeEvent, - UnwrapNativeEvent, } from './entities'; import { @@ -49,12 +50,13 @@ import { FEAT_UNISWAP_V2_PAIR_CREATED_EVENT, FEAT_UNISWAP_V2_SYNC_EVENT, FEAT_UNISWAP_V2_VIP_SWAP_EVENT, + FEAT_UNISWAP_V3_POOL_CREATED_EVENT, FEAT_UNISWAP_V3_SWAP_EVENT, FEAT_UNISWAP_V3_VIP_SWAP_EVENT, - FEAT_WRAP_UNWRAP_NATIVE_EVENT, - FEAT_WRAP_UNWRAP_NATIVE_TRANSFER_EVENT, FEAT_V3_FILL_EVENT, FEAT_V3_NATIVE_FILL, + FEAT_WRAP_UNWRAP_NATIVE_EVENT, + FEAT_WRAP_UNWRAP_NATIVE_TRANSFER_EVENT, FIRST_SEARCH_BLOCK, FLASHWALLET_ADDRESS, FLASHWALLET_DEPLOYMENT_BLOCK, @@ -71,11 +73,13 @@ import { UNISWAP_V2_SYNC_START_BLOCK, UNISWAP_V2_VIP_SWAP_SOURCES, UNISWAP_V2_VIP_SWAP_START_BLOCK, + UNISWAP_V3_FACTORY_ADDRESS, + UNISWAP_V3_POOL_CREATED_START_BLOCK, UNISWAP_V3_SWAP_START_BLOCK, UNISWAP_V3_VIP_SWAP_START_BLOCK, V4_NATIVE_FILL_START_BLOCK, - WRAP_UNWRAP_NATIVE_START_BLOCK, WRAP_UNWRAP_NATIVE_CONTRACT_ADDRESS, + WRAP_UNWRAP_NATIVE_START_BLOCK, } from './config'; import { @@ -90,7 +94,6 @@ import { LIMITORDERFILLED_EVENT_TOPIC, LIQUIDITYPROVIDERSWAP_EVENT_TOPIC, LOG_TRANSFER_EVENT_TOPIC_0, - SOCKET_BRIDGE_EVENT_TOPIC, META_TRANSACTION_EXECUTED_EVENT_TOPIC, ONCHAIN_GOVERNANCE_CALL_SCHEDULED_EVENT_TOPIC, ONCHAIN_GOVERNANCE_PROPOSAL_CREATED_EVENT_TOPIC, @@ -98,20 +101,22 @@ import { POLYGON_MATIC_ADDRESS, PROTOCOL_ZEROEX_TIMELOCK_CONTRACT_ADDRESS, RFQ_ORDER_FILLED_EVENT_TOPIC, + SOCKET_BRIDGE_EVENT_TOPIC, + TRANSFER_EVENT_TOPIC_0, TRANSFORMEDERC20_EVENT_TOPIC, TREASURY_ZEROEX_TIMELOCK_CONTRACT_ADDRESS, UNISWAP_V2_PAIR_CREATED_TOPIC, UNISWAP_V2_SWAP_EVENT_TOPIC_0, UNISWAP_V2_SYNC_TOPIC, + UNISWAP_V3_POOL_CREATED_TOPIC_0, UNISWAP_V3_SWAP_EVENT_TOPIC_0, + UNWRAP_NATIVE_EVENT_TOPIC, V3_EXCHANGE_ADDRESS, V3_FILL_EVENT_TOPIC, V4_CANCEL_EVENT_TOPIC, + WRAP_NATIVE_EVENT_TOPIC, ZEROEX_PROTOCOL_GOVERNOR_CONTRACT_ADDRESS, ZEROEX_TREASURY_GOVERNOR_CONTRACT_ADDRESS, - WRAP_NATIVE_EVENT_TOPIC, - UNWRAP_NATIVE_EVENT_TOPIC, - TRANSFER_EVENT_TOPIC_0, } from './constants'; import { DeleteOptions } from './utils'; @@ -120,7 +125,11 @@ import { parseNativeFillFromV4RfqOrderFilledEvent, parseV4RfqOrderFilledEvent, } from './parsers/events/v4_rfq_order_filled_events'; -import { parseUniswapV3VIPSwapEvent, parseUniswapV3SwapEvent } from './parsers/events/uniswap_v3_events'; +import { + parseUniswapV3VIPSwapEvent, + parseUniswapV3SwapEvent, + parseUniswapV3PoolCreatedEvent, +} from './parsers/events/uniswap_v3_events'; import { parseNativeFillFromV4LimitOrderFilledEvent, parseV4LimitOrderFilledEvent, @@ -245,18 +254,6 @@ export const eventScrperProps: EventScraperProps[] = [ deleteOptions: { directFlag: true, directProtocol: UNISWAP_V2_VIP_SWAP_SOURCES }, tokenMetadataMap: { tokenA: 'fromToken', tokenB: 'toToken' }, }, - { - enabled: FEAT_UNISWAP_V3_VIP_SWAP_EVENT, - name: 'UniswapV3VIPEvent', - tType: ERC20BridgeTransferEvent, - table: 'erc20_bridge_transfer_events', - topics: [UNISWAP_V3_SWAP_EVENT_TOPIC_0, addressToTopic(EP_ADDRESS)], - contractAddress: 'nofilter', - startBlock: UNISWAP_V3_VIP_SWAP_START_BLOCK, - parser: parseUniswapV3SwapEvent, - deleteOptions: { directFlag: true, directProtocol: ['UniswapV3'] }, - tokenMetadataMap: { tokenA: 'fromToken', tokenB: 'toToken' }, - }, { enabled: FEAT_PLP_SWAP_EVENT, name: 'LiquidityProviderSwapEvent', @@ -471,6 +468,16 @@ export const eventScrperProps: EventScraperProps[] = [ startBlock: UNISWAP_V3_SWAP_START_BLOCK, parser: parseUniswapV3SwapEvent, }, + { + enabled: FEAT_UNISWAP_V3_POOL_CREATED_EVENT, + name: 'UniswapV3PoolCreatedEvent', + tType: UniswapV3PoolCreatedEvent, + table: 'uniswap_v3_pool_created_events', + topics: [UNISWAP_V3_POOL_CREATED_TOPIC_0], + contractAddress: UNISWAP_V3_FACTORY_ADDRESS, + startBlock: UNISWAP_V3_POOL_CREATED_START_BLOCK, + parser: parseUniswapV3PoolCreatedEvent, + }, { enabled: FEAT_ONCHAIN_GOVERNANCE, name: 'ZeroexTreasuryGovernorProposalCreatedEvent', diff --git a/src/ormconfig.ts b/src/ormconfig.ts index 5426f3ca..631ace20 100644 --- a/src/ormconfig.ts +++ b/src/ormconfig.ts @@ -9,6 +9,7 @@ import { CurrentEpochInfo, ERC20BridgeTransferEvent, UniswapV3SwapEvent, + UniswapV3PoolCreatedEvent, EpochEndedEvent, EpochFinalizedEvent, Erc1155OrderCancelledEvent, @@ -62,6 +63,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..5d5de501 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): 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; +}