Implement scraping and parsing exchange cancel events

This commit is contained in:
Alex Browne
2018-09-25 15:03:49 -07:00
committed by Fred Carlsen
parent 7d9afce13b
commit 5262d3b1f2
5 changed files with 81 additions and 10 deletions

View File

@@ -1,4 +1,4 @@
import { ExchangeEventArgs, ExchangeFillEventArgs } from '@0xproject/contract-wrappers';
import { ExchangeCancelEventArgs, ExchangeEventArgs, ExchangeFillEventArgs } from '@0xproject/contract-wrappers';
import { assetDataUtils } from '@0xproject/order-utils';
import { AssetProxyId, ERC721AssetData } from '@0xproject/types';
import { BigNumber } from '@0xproject/utils';
@@ -7,12 +7,12 @@ import * as R from 'ramda';
import { artifacts } from '../../artifacts';
import { EventsResponse } from '../../data_sources/etherscan';
import { ExchangeCancelEvent } from '../../entities/ExchangeCancelEvent';
import { ExchangeFillEvent } from '../../entities/ExchangeFillEvent';
import { convertResponseToLogEntry, decodeLogEntry } from './event_utils';
// TODO(albrow): Union with other exchange event entity types
export type ExchangeEventEntity = ExchangeFillEvent;
export type ExchangeEventEntity = ExchangeFillEvent | ExchangeCancelEvent;
const exchangeContractAbi = artifacts.Exchange.compilerOutput.abi;
@@ -22,7 +22,7 @@ export function parseExchangeEvents(rawEventsResponse: EventsResponse): Exchange
eventResponse => decodeLogEntry<ExchangeEventArgs>(exchangeContractAbi, eventResponse),
logEntries,
);
const filteredLogEntries = R.filter(logEntry => R.contains(logEntry.event, ['Fill']), decodedLogEntries);
const filteredLogEntries = R.filter(logEntry => R.contains(logEntry.event, ['Fill', 'Cancel']), decodedLogEntries);
return R.map(_convertToEntity, filteredLogEntries);
}
@@ -30,6 +30,8 @@ export function _convertToEntity(eventLog: LogWithDecodedArgs<ExchangeEventArgs>
switch (eventLog.event) {
case 'Fill':
return _convertToExchangeFillEvent(eventLog as LogWithDecodedArgs<ExchangeFillEventArgs>);
case 'Cancel':
return _convertToExchangeCancelEvent(eventLog as LogWithDecodedArgs<ExchangeCancelEventArgs>);
default:
throw new Error('unexpected eventLog.event type: ' + eventLog.event);
}
@@ -67,6 +69,37 @@ export function _convertToExchangeFillEvent(eventLog: LogWithDecodedArgs<Exchang
return exchangeFillEvent;
}
export function _convertToExchangeCancelEvent(
eventLog: LogWithDecodedArgs<ExchangeCancelEventArgs>,
): ExchangeCancelEvent {
const makerAssetData = assetDataUtils.decodeAssetDataOrThrow(eventLog.args.makerAssetData);
const makerAssetType = makerAssetData.assetProxyId === AssetProxyId.ERC20 ? 'erc20' : 'erc721';
const takerAssetData = assetDataUtils.decodeAssetDataOrThrow(eventLog.args.takerAssetData);
const takerAssetType = takerAssetData.assetProxyId === AssetProxyId.ERC20 ? 'erc20' : 'erc721';
const exchangeCancelEvent = new ExchangeCancelEvent();
exchangeCancelEvent.logIndex = eventLog.logIndex as number;
exchangeCancelEvent.address = eventLog.address as string;
exchangeCancelEvent.rawData = eventLog.data as string;
exchangeCancelEvent.blockNumber = eventLog.blockNumber as number;
exchangeCancelEvent.makerAddress = eventLog.args.makerAddress.toString();
exchangeCancelEvent.takerAddress =
eventLog.args.takerAddress == null ? null : eventLog.args.takerAddress.toString();
exchangeCancelEvent.feeRecepientAddress = eventLog.args.feeRecipientAddress;
exchangeCancelEvent.senderAddress = eventLog.args.senderAddress;
exchangeCancelEvent.orderHash = eventLog.args.orderHash;
exchangeCancelEvent.rawMakerAssetData = eventLog.args.makerAssetData;
exchangeCancelEvent.makerAssetType = makerAssetType;
exchangeCancelEvent.makerAssetProxyId = makerAssetData.assetProxyId;
exchangeCancelEvent.makerTokenAddress = makerAssetData.tokenAddress;
exchangeCancelEvent.makerTokenId = bigNumbertoStringOrNull((makerAssetData as ERC721AssetData).tokenId);
exchangeCancelEvent.rawTakerAssetData = eventLog.args.takerAssetData;
exchangeCancelEvent.takerAssetType = takerAssetType;
exchangeCancelEvent.takerAssetProxyId = takerAssetData.assetProxyId;
exchangeCancelEvent.takerTokenAddress = takerAssetData.tokenAddress;
exchangeCancelEvent.takerTokenId = bigNumbertoStringOrNull((takerAssetData as ERC721AssetData).tokenId);
return exchangeCancelEvent;
}
function bigNumbertoStringOrNull(n: BigNumber): string | null {
if (n == null) {
return null;

View File

@@ -0,0 +1,32 @@
import { BaseEntity, Column, Entity, PrimaryColumn } from 'typeorm';
import { AssetType } from '../types';
@Entity()
export class ExchangeCancelEvent extends BaseEntity {
@PrimaryColumn() public logIndex!: number;
@Column() public address!: string;
@Column() public rawData!: string;
@Column() public blockNumber!: number;
@Column() public makerAddress!: string;
@Column({ nullable: true, type: String })
public takerAddress!: string;
@Column() public feeRecepientAddress!: string;
@Column() public senderAddress!: string;
@Column() public orderHash!: string;
@Column() public rawMakerAssetData!: string;
@Column() public makerAssetType!: AssetType;
@Column() public makerAssetProxyId!: string;
@Column() public makerTokenAddress!: string;
@Column({ nullable: true, type: String })
public makerTokenId!: string | null;
@Column() public rawTakerAssetData!: string;
@Column() public takerAssetType!: AssetType;
@Column() public takerAssetProxyId!: string;
@Column() public takerTokenAddress!: string;
@Column({ nullable: true, type: String })
public takerTokenId!: string | null;
// TODO(albrow): Include topics?
}

View File

@@ -1,6 +1,6 @@
import { BaseEntity, Column, Entity, PrimaryColumn } from 'typeorm';
export type ExchangeFillEventAssetType = 'erc20' | 'erc721';
import { AssetType } from '../types';
@Entity()
export class ExchangeFillEvent extends BaseEntity {
@@ -20,13 +20,13 @@ export class ExchangeFillEvent extends BaseEntity {
@Column() public takerFeePaid!: string;
@Column() public orderHash!: string;
@Column() public rawMakerAssetData!: string;
@Column() public makerAssetType!: ExchangeFillEventAssetType;
@Column() public makerAssetType!: AssetType;
@Column() public makerAssetProxyId!: string;
@Column() public makerTokenAddress!: string;
@Column({ nullable: true, type: String })
public makerTokenId!: string | null;
@Column() public rawTakerAssetData!: string;
@Column() public takerAssetType!: ExchangeFillEventAssetType;
@Column() public takerAssetType!: AssetType;
@Column() public takerAssetProxyId!: string;
@Column() public takerTokenAddress!: string;
@Column({ nullable: true, type: String })

View File

@@ -2,6 +2,7 @@ import 'reflect-metadata';
import { createConnection } from 'typeorm';
import { Etherscan } from './data_sources/etherscan';
import { ExchangeCancelEvent } from './entities/ExchangeCancelEvent';
import { ExchangeFillEvent } from './entities/ExchangeFillEvent';
import { config } from './ormconfig';
@@ -12,12 +13,16 @@ const EXCHANGE_ADDRESS = '0x4f833a24e1f95d70f028921e27040ca56e09ab0b';
(async () => {
const connection = await createConnection(config);
const repository = connection.getRepository(ExchangeFillEvent);
console.log(`found ${await repository.count()} existing fill events`);
const fillRepository = connection.getRepository(ExchangeFillEvent);
const cancelRepository = connection.getRepository(ExchangeCancelEvent);
console.log(`found ${await fillRepository.count()} existing fill events`);
console.log(`found ${await cancelRepository.count()} existing cancel events`);
const rawEvents = await etherscan.getContractEventsAsync(EXCHANGE_ADDRESS);
const events = parseExchangeEvents(rawEvents);
console.log(`got ${events.length} parsed events`);
for (const event of events) {
await event.save();
}
console.log(`now ${await repository.count()} total fill events`);
console.log(`now ${await fillRepository.count()} total fill events`);
console.log(`now ${await cancelRepository.count()} total cancel events`);
})();

View File

@@ -0,0 +1 @@
export type AssetType = 'erc20' | 'erc721';