Skip to content
This repository has been archived by the owner on Oct 15, 2024. It is now read-only.

Commit

Permalink
Batch fetch orders for /price endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
dekz committed Jan 23, 2020
1 parent 656555f commit 2e104dd
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 103 deletions.
4 changes: 2 additions & 2 deletions src/handlers/swap_handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ export class SwapHandlers {
res.status(HttpStatus.OK).send({ records: filteredTokens });
}
// tslint:disable-next-line:prefer-function-over-method
public async getTokenPricesAsync(_req: express.Request, res: express.Response): Promise<void> {
const prices = await this._swapService.getTokenPricesAsync();
public async getTokenPricesAsync(req: express.Request, res: express.Response): Promise<void> {
const prices = await this._swapService.getTokenPricesAsync(req.query.sellToken || 'WETH');
res.status(HttpStatus.OK).send({ prices });
}
}
Expand Down
20 changes: 18 additions & 2 deletions src/services/orderbook_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { WSClient } from '@0x/mesh-rpc-client';
import { assetDataUtils } from '@0x/order-utils';
import { AssetPairsItem, OrdersRequestOpts, SignedOrder } from '@0x/types';
import * as _ from 'lodash';
import { Connection } from 'typeorm';
import { Connection, In } from 'typeorm';

import { SignedOrderEntity } from '../entities';
import { ValidationError } from '../errors';
Expand Down Expand Up @@ -75,7 +75,6 @@ export class OrderBookService {
where: { takerAssetData: quoteAssetData, makerAssetData: baseAssetData },
}),
]);
console.log(bidSignedOrderEntities.length, askSignedOrderEntities.length);
const bidApiOrders: APIOrder[] = (bidSignedOrderEntities as Array<Required<SignedOrderEntity>>)
.map(orderUtils.deserializeOrderToAPIOrder)
.sort((orderA, orderB) => orderUtils.compareBidOrder(orderA.order, orderB.order));
Expand Down Expand Up @@ -157,6 +156,23 @@ export class OrderBookService {
const paginatedApiOrders = paginationUtils.paginate(apiOrders, page, perPage);
return paginatedApiOrders;
}
public async getBatchOrdersAsync(
page: number,
perPage: number,
makerAssetDatas: string[],
takerAssetDatas: string[],
): Promise<PaginatedCollection<APIOrder>> {
const filterObject = {
makerAssetData: In(makerAssetDatas),
takerAssetData: In(takerAssetDatas),
};
const signedOrderEntities = (await this._connection.manager.find(SignedOrderEntity, {
where: filterObject,
})) as Array<Required<SignedOrderEntity>>;
const apiOrders = _.map(signedOrderEntities, orderUtils.deserializeOrderToAPIOrder);
const paginatedApiOrders = paginationUtils.paginate(apiOrders, page, perPage);
return paginatedApiOrders;
}
constructor(connection: Connection, meshClient?: WSClient) {
this._meshClient = meshClient;
this._connection = connection;
Expand Down
44 changes: 27 additions & 17 deletions src/services/swap_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { logger } from '../logger';
import { TokenMetadatasForChains } from '../token_metadatas_for_networks';
import { CalculateSwapQuoteParams, GetSwapQuoteResponse } from '../types';
import { orderUtils } from '../utils/order_utils';
import { findTokenDecimalsIfExists } from '../utils/token_metadata_utils';
import { findTokenDecimalsIfExists, getTokenMetadataIfExists } from '../utils/token_metadata_utils';

export class SwapService {
private readonly _provider: SupportedProvider;
Expand Down Expand Up @@ -48,9 +48,9 @@ export class SwapService {
from,
} = params;
const assetSwapperOpts = {
...ASSET_SWAPPER_MARKET_ORDERS_OPTS,
slippagePercentage,
gasPrice: providedGasPrice,
...ASSET_SWAPPER_MARKET_ORDERS_OPTS,
};
if (sellAmount !== undefined) {
swapQuote = await this._swapQuoter.getMarketSellSwapQuoteAsync(
Expand Down Expand Up @@ -130,42 +130,52 @@ export class SwapService {
return apiSwapQuote;
}

public async getTokenPricesAsync(): Promise<Array<{ symbol: string; price: BigNumber }>> {
const baseAssetSymbol = 'WETH';
const unitAmount = new BigNumber(1);
const baseAsset = TokenMetadatasForChains.find(m => m.symbol === baseAssetSymbol);
public async getTokenPricesAsync(baseAssetSymbol: string): Promise<Array<{ symbol: string; price: BigNumber }>> {
const baseAsset = getTokenMetadataIfExists(baseAssetSymbol, CHAIN_ID);
if (!baseAsset) {
throw new Error('Invalid Base Asset');
}
const takerAssetData = assetDataUtils.encodeERC20AssetData(baseAsset.tokenAddresses[CHAIN_ID]); // WETH
const unitAmount = new BigNumber(1);
const takerAssetData = assetDataUtils.encodeERC20AssetData(baseAsset.tokenAddress);
const queryAssetData = TokenMetadatasForChains.filter(m => m.symbol !== baseAssetSymbol);
const tokenMetadataChunks = _.chunk(queryAssetData, 10);
const chunkSize = 10;
const assetDataChunks = _.chunk(queryAssetData, chunkSize);
const allResults = _.flatten(
await Promise.all(
tokenMetadataChunks.map(async chunk => {
const makerAssetDatas = chunk.map(m =>
assetDataChunks.map(async a => {
const encodedAssetData = a.map(m =>
assetDataUtils.encodeERC20AssetData(m.tokenAddresses[CHAIN_ID]),
);
const amounts = chunk.map(m => Web3Wrapper.toBaseUnitAmount(unitAmount, m.decimals));
return this._swapQuoter.getMultipleMarketBuySwapQuoteForAssetDataAsync(
makerAssetDatas,
const amounts = a.map(m => Web3Wrapper.toBaseUnitAmount(unitAmount, m.decimals));
const quotes = await this._swapQuoter.getBatchMarketBuySwapQuoteForAssetDataAsync(
encodedAssetData,
takerAssetData,
amounts,
{ slippagePercentage: 0 },
{
...ASSET_SWAPPER_MARKET_ORDERS_OPTS,
slippagePercentage: 0,
bridgeSlippage: 0,
numSamples: 1,
runLimit: 1,
},
);
return quotes;
}),
),
);

const prices = allResults.map((quote, i) => {
if (!quote) {
return { symbol: queryAssetData[i].symbol, price: ZERO };
}
const buyTokenDecimals = queryAssetData[i].decimals;
const sellTokenDecimals = baseAsset.decimals;
const { makerAssetAmount, totalTakerAssetAmount } = quote.bestCaseQuoteInfo;
const makerAssetUnitAmount = Web3Wrapper.toUnitAmount(makerAssetAmount, buyTokenDecimals);
const takerAssetUnitAmount = Web3Wrapper.toUnitAmount(totalTakerAssetAmount, sellTokenDecimals);
const price = makerAssetUnitAmount.dividedBy(takerAssetUnitAmount).decimalPlaces(sellTokenDecimals);
const unitMakerAssetAmount = Web3Wrapper.toUnitAmount(makerAssetAmount, buyTokenDecimals);
const unitTakerAssetAMount = Web3Wrapper.toUnitAmount(totalTakerAssetAmount, sellTokenDecimals);
const price = unitMakerAssetAmount
.dividedBy(unitTakerAssetAMount)
.decimalPlaces(sellTokenDecimals);
return {
symbol: queryAssetData[i].symbol,
price,
Expand Down
92 changes: 21 additions & 71 deletions src/token_metadatas_for_networks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,22 @@ export interface TokenMetadataAndChainAddresses {
// tslint:disable:max-file-line-count
export const TokenMetadatasForChains: TokenMetadataAndChainAddresses[] = [
{
symbol: 'DAI',
name: 'Dai Stablecoin',
symbol: 'ZRX',
name: '0x Protocol Token',
decimals: 18,
tokenAddresses: {
[ChainId.Mainnet]: '0x6b175474e89094c44da98b954eedeac495271d0f',
[ChainId.Kovan]: '0xc4375b7de8af5a38a93548eb8453a498222c4ff2',
[ChainId.Ganache]: '0x34d402f14d58e001d8efbe6585051bf9706aa064',
[ChainId.Mainnet]: '0xe41d2489571d322189246dafa5ebde1f4699f498',
[ChainId.Kovan]: '0x2002d3812f58e35f0ea1ffbf80a75a38c32175fa',
[ChainId.Ganache]: '0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c',
},
},
{
symbol: 'REP',
name: 'Augur Reputation',
symbol: 'DAI',
name: 'Dai Stablecoin',
decimals: 18,
tokenAddresses: {
[ChainId.Mainnet]: '0x1985365e9f78359a9B6AD760e32412f4a445E862',
[ChainId.Kovan]: '0xb18845c260f680d5b9d84649638813e342e4f8c9',
[ChainId.Mainnet]: '0x6b175474e89094c44da98b954eedeac495271d0f',
[ChainId.Kovan]: '0xc4375b7de8af5a38a93548eb8453a498222c4ff2',
[ChainId.Ganache]: '0x34d402f14d58e001d8efbe6585051bf9706aa064',
},
},
Expand All @@ -45,16 +45,6 @@ export const TokenMetadatasForChains: TokenMetadataAndChainAddresses[] = [
[ChainId.Ganache]: '0x0b1ba0af832d7c05fd64161e0db78e85978e8082',
},
},
{
symbol: 'ZRX',
name: '0x Protocol Token',
decimals: 18,
tokenAddresses: {
[ChainId.Mainnet]: '0xe41d2489571d322189246dafa5ebde1f4699f498',
[ChainId.Kovan]: '0x2002d3812f58e35f0ea1ffbf80a75a38c32175fa',
[ChainId.Ganache]: '0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c',
},
},
{
symbol: 'USDC',
name: 'USD Coin',
Expand All @@ -65,6 +55,16 @@ export const TokenMetadatasForChains: TokenMetadataAndChainAddresses[] = [
[ChainId.Ganache]: NULL_ADDRESS,
},
},
{
symbol: 'REP',
name: 'Augur Reputation',
decimals: 18,
tokenAddresses: {
[ChainId.Mainnet]: '0x1985365e9f78359a9B6AD760e32412f4a445E862',
[ChainId.Kovan]: '0xb18845c260f680d5b9d84649638813e342e4f8c9',
[ChainId.Ganache]: '0x34d402f14d58e001d8efbe6585051bf9706aa064',
},
},
{
symbol: 'BAT',
name: 'Basic Attention Token',
Expand Down Expand Up @@ -165,16 +165,6 @@ export const TokenMetadatasForChains: TokenMetadataAndChainAddresses[] = [
[ChainId.Ganache]: NULL_ADDRESS,
},
},
{
decimals: 18,
symbol: 'GNT',
name: 'Golem Network Token',
tokenAddresses: {
[ChainId.Mainnet]: '0xa74476443119a942de498590fe1f2454d7d4ac0d',
[ChainId.Kovan]: NULL_ADDRESS,
[ChainId.Ganache]: NULL_ADDRESS,
},
},
{
decimals: 18,
symbol: 'OMG',
Expand Down Expand Up @@ -245,16 +235,6 @@ export const TokenMetadatasForChains: TokenMetadataAndChainAddresses[] = [
[ChainId.Ganache]: NULL_ADDRESS,
},
},
{
decimals: 8,
symbol: 'AION',
name: 'Aion Network',
tokenAddresses: {
[ChainId.Mainnet]: '0x4ceda7906a5ed2179785cd3a40a69ee8bc99c466',
[ChainId.Kovan]: NULL_ADDRESS,
[ChainId.Ganache]: NULL_ADDRESS,
},
},
{
decimals: 18,
symbol: 'GEN',
Expand Down Expand Up @@ -300,7 +280,7 @@ export const TokenMetadatasForChains: TokenMetadataAndChainAddresses[] = [
symbol: 'MLN',
name: 'Melon',
tokenAddresses: {
[ChainId.Mainnet]: '0xbeb9ef514a379b997e0798fdcc901ee474b6d9a1',
[ChainId.Mainnet]: '0xec67005c4e498ec7f55e092bd1d35cbc47c91892',
[ChainId.Kovan]: NULL_ADDRESS,
[ChainId.Ganache]: NULL_ADDRESS,
},
Expand Down Expand Up @@ -335,16 +315,6 @@ export const TokenMetadatasForChains: TokenMetadataAndChainAddresses[] = [
[ChainId.Ganache]: NULL_ADDRESS,
},
},
{
decimals: 18,
symbol: 'ICN',
name: 'ICONOMI',
tokenAddresses: {
[ChainId.Mainnet]: '0x888666ca69e0f178ded6d75b5726cee99a87d698',
[ChainId.Kovan]: NULL_ADDRESS,
[ChainId.Ganache]: NULL_ADDRESS,
},
},
{
decimals: 9,
symbol: 'DGD',
Expand Down Expand Up @@ -377,7 +347,7 @@ export const TokenMetadatasForChains: TokenMetadataAndChainAddresses[] = [
},
{
decimals: 8,
symbol: 'cDAI',
symbol: 'cSAI',
name: 'Compound Dai',
tokenAddresses: {
[ChainId.Mainnet]: '0x5d3a536e4d6dbd6114cc1ead35777bab948e3643',
Expand Down Expand Up @@ -405,16 +375,6 @@ export const TokenMetadatasForChains: TokenMetadataAndChainAddresses[] = [
[ChainId.Ganache]: NULL_ADDRESS,
},
},
{
decimals: 8,
symbol: 'cREP',
name: 'Compound Augur',
tokenAddresses: {
[ChainId.Mainnet]: '0x158079ee67fce2f58472a96584a73c7ab9ac95c1',
[ChainId.Kovan]: NULL_ADDRESS,
[ChainId.Ganache]: NULL_ADDRESS,
},
},
{
decimals: 8,
symbol: 'cUSDC',
Expand Down Expand Up @@ -485,16 +445,6 @@ export const TokenMetadatasForChains: TokenMetadataAndChainAddresses[] = [
[ChainId.Ganache]: NULL_ADDRESS,
},
},
{
decimals: 18,
symbol: 'ICX',
name: 'ICON',
tokenAddresses: {
[ChainId.Mainnet]: '0xb5a5f22694352c15b00323844ad545abb2b11028',
[ChainId.Kovan]: NULL_ADDRESS,
[ChainId.Ganache]: NULL_ADDRESS,
},
},
{
decimals: 18,
symbol: 'NMR',
Expand Down
32 changes: 21 additions & 11 deletions src/utils/order_store_db_adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,30 @@ export class OrderStoreDbAdapter extends OrderStore {
}
// Currently not handling deletes as this is handled by Mesh
}
public async getBatchOrderSetsForAssetsAsync(
makerAssetDatas: string[],
takerAssetDatas: string[],
): Promise<OrderSet[]> {
const { records: apiOrders } = await this._orderbookService.getBatchOrdersAsync(
FIRST_PAGE,
MAX_QUERY_SIZE,
makerAssetDatas,
takerAssetDatas,
);
const orderSets: { [makerAssetData: string]: OrderSet } = {};
makerAssetDatas.forEach(m =>
takerAssetDatas.forEach(t => (orderSets[OrderStore.getKeyForAssetPair(m, t)] = new OrderSet())),
);
await Promise.all(
apiOrders.map(async o =>
orderSets[OrderStore.getKeyForAssetPair(o.order.makerAssetData, o.order.takerAssetData)].addAsync(o),
),
);
return Object.values(orderSets);
}
// tslint:disable-next-line:prefer-function-over-method
public async hasAsync(_assetPairKey: string): Promise<boolean> {
return true;
// const [assetA, assetB] = OrderStore.assetPairKeyToAssets(assetPairKey);
// const { bids, asks } = await this._orderbookService.getOrderBookAsync(
// FIRST_PAGE,
// MAX_QUERY_SIZE,
// assetA,
// assetB,
// );
// return bids.total !== 0 || asks.total !== 0;
// const [assetA, assetB] = OrderStore.assetPairKeyToAssets(assetPairKey);
// const pairs = await this._orderbookService.getAssetPairsAsync(FIRST_PAGE, MAX_QUERY_SIZE, assetA, assetB);
// return pairs.total !== 0;
}
public async valuesAsync(assetPairKey: string): Promise<APIOrder[]> {
return Array.from((await this.getOrderSetForAssetPairAsync(assetPairKey)).values());
Expand Down

0 comments on commit 2e104dd

Please sign in to comment.