Make event parsing more functional and less class-based
This commit is contained in:
committed by
Fred Carlsen
parent
c99b71f354
commit
7d9afce13b
@@ -1,34 +0,0 @@
|
||||
import { AbiDefinition, BlockParam, BlockParamLiteral, LogEntry } from 'ethereum-types';
|
||||
import * as R from 'ramda';
|
||||
import { BaseEntity } from 'typeorm';
|
||||
|
||||
import { Etherscan } from '../../../data_sources/etherscan';
|
||||
import { convertResponseToLogEntry } from '../event_utils';
|
||||
|
||||
export abstract class BaseEventHandler<EntityType extends BaseEntity> {
|
||||
protected _abi: AbiDefinition[];
|
||||
protected _address: string;
|
||||
protected _etherscan: Etherscan;
|
||||
constructor(abi: AbiDefinition[], address: string, etherscan: Etherscan) {
|
||||
this._abi = abi;
|
||||
this._address = address;
|
||||
this._etherscan = etherscan;
|
||||
}
|
||||
public abstract convertLogEntryToEventEntity(logEntry: LogEntry): EntityType;
|
||||
|
||||
public async getEventsAsync(
|
||||
fromBlock: BlockParam = BlockParamLiteral.Earliest,
|
||||
toBlock: BlockParam = BlockParamLiteral.Latest,
|
||||
): Promise<EntityType[]> {
|
||||
const rawEventsResponse = await this._etherscan.getContractEventsAsync(this._address, fromBlock, toBlock);
|
||||
const logEntries = R.map(convertResponseToLogEntry, rawEventsResponse.result);
|
||||
// Note(albrow): Imperative for loop is required here because we can't
|
||||
// bind convertLogEntryToEventEntity without having a specific instance
|
||||
// of a sub-class.
|
||||
const result = [];
|
||||
for (const logEntry of logEntries) {
|
||||
result.push(this.convertLogEntryToEventEntity(logEntry));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,29 @@
|
||||
import { ExchangeEventArgs, ExchangeFillEventArgs } from '@0xproject/contract-wrappers';
|
||||
import { assetDataUtils } from '@0xproject/order-utils';
|
||||
import { AssetProxyId, ERC721AssetData } from '@0xproject/types';
|
||||
import { AbiDecoder, BigNumber } from '@0xproject/utils';
|
||||
import { AbiDefinition, LogEntry, LogWithDecodedArgs } from 'ethereum-types';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { LogWithDecodedArgs } from 'ethereum-types';
|
||||
import * as R from 'ramda';
|
||||
|
||||
import { ExchangeFillEvent } from '../../../entities/ExchangeFillEvent';
|
||||
import { decodeLogEntry } from '../event_utils';
|
||||
import { artifacts } from '../../artifacts';
|
||||
import { EventsResponse } from '../../data_sources/etherscan';
|
||||
import { ExchangeFillEvent } from '../../entities/ExchangeFillEvent';
|
||||
|
||||
import { BaseEventHandler } from './base_event_handler';
|
||||
import { convertResponseToLogEntry, decodeLogEntry } from './event_utils';
|
||||
|
||||
// TODO(albrow): Union with other exchange event entity types
|
||||
export type ExchangeEventEntity = ExchangeFillEvent;
|
||||
|
||||
export class ExchangeEventHandler extends BaseEventHandler<ExchangeEventEntity> {
|
||||
public convertLogEntryToEventEntity(logEntry: LogEntry): ExchangeEventEntity {
|
||||
const decodedLogEntry = decodeLogEntry<ExchangeEventArgs>(this._abi, logEntry);
|
||||
return _convertToEntity(decodedLogEntry);
|
||||
}
|
||||
const exchangeContractAbi = artifacts.Exchange.compilerOutput.abi;
|
||||
|
||||
export function parseExchangeEvents(rawEventsResponse: EventsResponse): ExchangeEventEntity[] {
|
||||
const logEntries = R.map(convertResponseToLogEntry, rawEventsResponse.result);
|
||||
const decodedLogEntries = R.map(
|
||||
eventResponse => decodeLogEntry<ExchangeEventArgs>(exchangeContractAbi, eventResponse),
|
||||
logEntries,
|
||||
);
|
||||
const filteredLogEntries = R.filter(logEntry => R.contains(logEntry.event, ['Fill']), decodedLogEntries);
|
||||
return R.map(_convertToEntity, filteredLogEntries);
|
||||
}
|
||||
|
||||
export function _convertToEntity(eventLog: LogWithDecodedArgs<ExchangeEventArgs>): ExchangeEventEntity {
|
||||
@@ -25,8 +31,7 @@ export function _convertToEntity(eventLog: LogWithDecodedArgs<ExchangeEventArgs>
|
||||
case 'Fill':
|
||||
return _convertToExchangeFillEvent(eventLog as LogWithDecodedArgs<ExchangeFillEventArgs>);
|
||||
default:
|
||||
return new ExchangeFillEvent();
|
||||
// throw new Error('unexpected eventLog.event type: ' + eventLog.event);
|
||||
throw new Error('unexpected eventLog.event type: ' + eventLog.event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,9 +73,3 @@ function bigNumbertoStringOrNull(n: BigNumber): string | null {
|
||||
}
|
||||
return n.toString();
|
||||
}
|
||||
|
||||
function filterEventLogs(
|
||||
eventLogs: Array<LogWithDecodedArgs<ExchangeEventArgs>>,
|
||||
): Array<LogWithDecodedArgs<ExchangeEventArgs>> {
|
||||
return R.filter(eventLog => eventLog.event === 'Fill', eventLogs);
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
import 'reflect-metadata';
|
||||
import { createConnection } from 'typeorm';
|
||||
|
||||
import { artifacts } from './artifacts';
|
||||
import { Etherscan } from './data_sources/etherscan';
|
||||
import { ExchangeFillEvent } from './entities/ExchangeFillEvent';
|
||||
import { config } from './ormconfig';
|
||||
|
||||
import { ExchangeEventHandler } from './data_types/events/event_handlers/exchange_event_handler';
|
||||
import { parseExchangeEvents } from './data_types/events/exchange_events';
|
||||
|
||||
const etherscan = new Etherscan(process.env.ETHERSCAN_API_KEY as string);
|
||||
const EXCHANGE_ADDRESS = '0x4f833a24e1f95d70f028921e27040ca56e09ab0b';
|
||||
@@ -15,18 +14,10 @@ const EXCHANGE_ADDRESS = '0x4f833a24e1f95d70f028921e27040ca56e09ab0b';
|
||||
const connection = await createConnection(config);
|
||||
const repository = connection.getRepository(ExchangeFillEvent);
|
||||
console.log(`found ${await repository.count()} existing fill events`);
|
||||
const exchangeEventHandler = new ExchangeEventHandler(
|
||||
artifacts.Exchange.compilerOutput.abi,
|
||||
EXCHANGE_ADDRESS,
|
||||
etherscan,
|
||||
);
|
||||
const events = await exchangeEventHandler.getEventsAsync();
|
||||
console.log(JSON.stringify(events, null, 2));
|
||||
const rawEvents = await etherscan.getContractEventsAsync(EXCHANGE_ADDRESS);
|
||||
const events = parseExchangeEvents(rawEvents);
|
||||
for (const event of events) {
|
||||
// TODO(albrow): remove this check once we can parse all Exchange events
|
||||
if (event.address != null) {
|
||||
await event.save();
|
||||
}
|
||||
await event.save();
|
||||
}
|
||||
console.log(`now ${await repository.count()} total fill events`);
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user