Implement scraping sra orders from radar relay

This commit is contained in:
Alex Browne
2018-11-13 15:33:43 -08:00
parent 55bbe1954b
commit 26280e4aba
7 changed files with 52 additions and 24 deletions

View File

@@ -6,3 +6,4 @@ export { Relayer } from './relayer';
export { SraOrder } from './sra_order'; export { SraOrder } from './sra_order';
export { Transaction } from './transaction'; export { Transaction } from './transaction';
export { TokenOnChainMetadata } from './token_on_chain_metadata'; export { TokenOnChainMetadata } from './token_on_chain_metadata';
export { SraOrdersObservedTimeStamp, createObservedTimestampForOrder } from './sra_order_observed_timestamp';

View File

@@ -19,9 +19,9 @@ export class SraOrder {
public feeRecipientAddress!: string; public feeRecipientAddress!: string;
@Column({ name: 'sender_address' }) @Column({ name: 'sender_address' })
public senderAddress!: string; public senderAddress!: string;
@Column({ name: 'maker_asset_amount' }) @Column({ name: 'maker_asset_filled_amount' })
public makerAssetAmount!: string; public makerAssetAmount!: string;
@Column({ name: 'taker_asset_amount' }) @Column({ name: 'taker_asset_filled_amount' })
public takerAssetAmount!: string; public takerAssetAmount!: string;
@Column({ name: 'maker_fee' }) @Column({ name: 'maker_fee' })
public makerFee!: string; public makerFee!: string;

View File

@@ -0,0 +1,30 @@
import { Entity, PrimaryColumn } from 'typeorm';
import { SraOrder } from './sra_order';
@Entity({ name: 'sra_orders_observed_timestamps', schema: 'raw' })
export class SraOrdersObservedTimeStamp {
@PrimaryColumn({ name: 'exchange_address' })
public exchangeAddress!: string;
@PrimaryColumn({ name: 'order_hash_hex' })
public orderHashHex!: string;
@PrimaryColumn({ name: 'source_url' })
public sourceUrl!: string;
@PrimaryColumn({ name: 'observed_timestamp' })
public observedTimestamp!: number;
}
/**
* Returns a new SraOrdersObservedTimeStamp for the given order based on the
* current time.
* @param order The order to generate a timestamp for.
*/
export function createObservedTimestampForOrder(order: SraOrder): SraOrdersObservedTimeStamp {
const observed = new SraOrdersObservedTimeStamp();
observed.exchangeAddress = order.exchangeAddress;
observed.orderHashHex = order.orderHashHex;
observed.sourceUrl = order.sourceUrl;
observed.observedTimestamp = Date.now();
return observed;
}

View File

@@ -7,6 +7,7 @@ import {
ExchangeFillEvent, ExchangeFillEvent,
Relayer, Relayer,
SraOrder, SraOrder,
SraOrdersObservedTimeStamp,
Transaction, Transaction,
} from './entities'; } from './entities';
@@ -17,6 +18,7 @@ const entities = [
ExchangeFillEvent, ExchangeFillEvent,
Relayer, Relayer,
SraOrder, SraOrder,
SraOrdersObservedTimeStamp,
Transaction, Transaction,
]; ];

View File

@@ -30,10 +30,6 @@ export function _convertToEntity(apiOrder: APIOrder): SraOrder {
sraOrder.exchangeAddress = apiOrder.order.exchangeAddress; sraOrder.exchangeAddress = apiOrder.order.exchangeAddress;
sraOrder.orderHashHex = orderHashUtils.getOrderHashHex(apiOrder.order); sraOrder.orderHashHex = orderHashUtils.getOrderHashHex(apiOrder.order);
// TODO(albrow): Set these fields to the correct values upstack.
sraOrder.lastUpdatedTimestamp = 0;
sraOrder.firstSeenTimestamp = 0;
sraOrder.makerAddress = apiOrder.order.makerAddress; sraOrder.makerAddress = apiOrder.order.makerAddress;
sraOrder.takerAddress = apiOrder.order.takerAddress; sraOrder.takerAddress = apiOrder.order.takerAddress;
sraOrder.feeRecipientAddress = apiOrder.order.feeRecipientAddress; sraOrder.feeRecipientAddress = apiOrder.order.feeRecipientAddress;

View File

@@ -2,15 +2,14 @@
import { HttpClient } from '@0x/connect'; import { HttpClient } from '@0x/connect';
import * as R from 'ramda'; import * as R from 'ramda';
import 'reflect-metadata'; import 'reflect-metadata';
import { Connection, ConnectionOptions, createConnection } from 'typeorm'; import { Connection, ConnectionOptions, createConnection, EntityManager } from 'typeorm';
import { SraOrder } from '../entities'; import { createObservedTimestampForOrder, SraOrder } from '../entities';
import * as ormConfig from '../ormconfig'; import * as ormConfig from '../ormconfig';
import { parseSraOrders } from '../parsers/sra_orders'; import { parseSraOrders } from '../parsers/sra_orders';
import { handleError } from '../utils'; import { handleError } from '../utils';
const RADAR_RELAY_URL = 'https://api.radarrelay.com/0x/v2'; const RADAR_RELAY_URL = 'https://api.radarrelay.com/0x/v2';
const BATCH_SAVE_SIZE = 1000; // Number of orders to save at once.
const ORDERS_PER_PAGE = 10000; // Number of orders to get per request. const ORDERS_PER_PAGE = 10000; // Number of orders to get per request.
let connection: Connection; let connection: Connection;
@@ -29,24 +28,26 @@ async function getOrderbook(): Promise<void> {
}); });
console.log(`Got ${rawOrders.records.length} orders.`); console.log(`Got ${rawOrders.records.length} orders.`);
console.log('Parsing orders...'); console.log('Parsing orders...');
// Parse the sra orders, then add source url to each.
const orders = R.pipe(parseSraOrders, R.map(setSourceUrl(RADAR_RELAY_URL)))(rawOrders); const orders = R.pipe(parseSraOrders, R.map(setSourceUrl(RADAR_RELAY_URL)))(rawOrders);
const ordersRepository = connection.getRepository(SraOrder); // Save all the orders and update the observed time stamps in a single
// TODO(albrow): Move batch saving to a utility function to reduce // transaction.
// duplicated code. console.log('Saving orders and updating timestamps...');
for (const ordersBatch of R.splitEvery(BATCH_SAVE_SIZE, orders)) { await connection.transaction(async (manager: EntityManager): Promise<void> => {
await ordersRepository.save(ordersBatch); for (const order of orders) {
} await manager.save(SraOrder, order);
const observedTimestamp = createObservedTimestampForOrder(order);
await manager.save(observedTimestamp);
}
});
} }
const sourceUrlProp = R.lensProp('sourceUrl'); const sourceUrlProp = R.lensProp('sourceUrl');
/**
* Sets the source url for a single order. Returns a new order instead of
* mutating the given one.
*/
const setSourceUrl = R.curry((sourceURL: string, order: SraOrder): SraOrder => { const setSourceUrl = R.curry((sourceURL: string, order: SraOrder): SraOrder => {
return R.set(sourceUrlProp, sourceURL, order); return R.set(sourceUrlProp, sourceURL, order);
}); });
const firstSeenProp = R.lensProp('firstSeenTimestamp');
const lastUpdatedProp = R.lensProp('lastUpdatedTimestamp');
const setFirstSeen = R.curry((sourceURL: string, order: SraOrder): SraOrder => {
return R.set(firstSeenTimestampProp, sourceURL, order);
});

View File

@@ -37,8 +37,6 @@ describe('sra_orders', () => {
const expected = new SraOrder(); const expected = new SraOrder();
expected.exchangeAddress = '0x4f833a24e1f95d70f028921e27040ca56e09ab0b'; expected.exchangeAddress = '0x4f833a24e1f95d70f028921e27040ca56e09ab0b';
expected.orderHashHex = '0x1bdbeb0d088a33da28b9ee6d94e8771452f90f4a69107da2fa75195d61b9a1c9'; expected.orderHashHex = '0x1bdbeb0d088a33da28b9ee6d94e8771452f90f4a69107da2fa75195d61b9a1c9';
expected.lastUpdatedTimestamp = 0;
expected.firstSeenTimestamp = 0;
expected.makerAddress = '0xb45df06e38540a675fdb5b598abf2c0dbe9d6b81'; expected.makerAddress = '0xb45df06e38540a675fdb5b598abf2c0dbe9d6b81';
expected.takerAddress = '0x0000000000000000000000000000000000000000'; expected.takerAddress = '0x0000000000000000000000000000000000000000';
expected.feeRecipientAddress = '0xa258b39954cef5cb142fd567a46cddb31a670124'; expected.feeRecipientAddress = '0xa258b39954cef5cb142fd567a46cddb31a670124';