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 14, 2020
1 parent 9bf7f9a commit aa57227
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 125 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({ tokens: 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
19 changes: 18 additions & 1 deletion 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 @@ -157,6 +157,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
56 changes: 36 additions & 20 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 @@ -104,9 +104,7 @@ export class SwapService {

const buyTokenDecimals = await this._fetchTokenDecimalsIfRequiredAsync(buyTokenAddress);
const sellTokenDecimals = await this._fetchTokenDecimalsIfRequiredAsync(sellTokenAddress);
const price = Web3Wrapper.toUnitAmount(makerAssetAmount, buyTokenDecimals)
.dividedBy(Web3Wrapper.toUnitAmount(totalTakerAssetAmount, sellTokenDecimals))
.decimalPlaces(sellTokenDecimals);
const price = calculatePrice(makerAssetAmount, buyTokenDecimals, totalTakerAssetAmount, sellTokenDecimals);

const apiSwapQuote: GetSwapQuoteResponse = {
price,
Expand All @@ -124,42 +122,48 @@ 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 price = calculatePrice(makerAssetAmount, buyTokenDecimals, totalTakerAssetAmount, sellTokenDecimals);
return {
symbol: queryAssetData[i].symbol,
price,
Expand Down Expand Up @@ -255,6 +259,18 @@ export class SwapService {
}
}

const calculatePrice = (
makerAssetAmount: BigNumber,
makerAssetDecimals: number,
takerAssetAmount: BigNumber,
takerAssetDecimals: number,
): BigNumber => {
const makerAssetUnitAmount = Web3Wrapper.toUnitAmount(makerAssetAmount, makerAssetDecimals);
const takerAssetUnitAmount = Web3Wrapper.toUnitAmount(takerAssetAmount, takerAssetDecimals);
const price = makerAssetUnitAmount.dividedBy(takerAssetUnitAmount).decimalPlaces(takerAssetDecimals);
return price;
};

const throwIfRevertError = (result: string): void => {
let revertError;
try {
Expand Down
153 changes: 62 additions & 91 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 @@ -95,26 +95,7 @@ export const TokenMetadatasForChains: TokenMetadataAndChainAddresses[] = [
[ChainId.Ganache]: NULL_ADDRESS,
},
},
{
decimals: 18,
symbol: 'SNX',
name: 'Synthetix Network Token',
tokenAddresses: {
[ChainId.Mainnet]: '0xc011a72400e58ecd99ee497cf89e3775d4bd732f',
[ChainId.Kovan]: NULL_ADDRESS,
[ChainId.Ganache]: NULL_ADDRESS,
},
},
{
decimals: 18,
symbol: 'SUSD',
name: 'sUSD',
tokenAddresses: {
[ChainId.Mainnet]: '0x57ab1e02fee23774580c119740129eac7081e9d3',
[ChainId.Kovan]: NULL_ADDRESS,
[ChainId.Ganache]: NULL_ADDRESS,
},
},

{
decimals: 18,
symbol: 'KNC',
Expand Down Expand Up @@ -165,16 +146,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 +216,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 +261,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 +296,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 +328,7 @@ export const TokenMetadatasForChains: TokenMetadataAndChainAddresses[] = [
},
{
decimals: 8,
symbol: 'cDAI',
symbol: 'cSAI',
name: 'Compound Dai',
tokenAddresses: {
[ChainId.Mainnet]: '0x5d3a536e4d6dbd6114cc1ead35777bab948e3643',
Expand Down Expand Up @@ -405,16 +356,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 +426,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 Expand Up @@ -625,4 +556,44 @@ export const TokenMetadatasForChains: TokenMetadataAndChainAddresses[] = [
[ChainId.Ganache]: NULL_ADDRESS,
},
},
{
decimals: 18,
symbol: 'USDT',
name: 'Tether USD',
tokenAddresses: {
[ChainId.Mainnet]: '0xdac17f958d2ee523a2206206994597c13d831ec7',
[ChainId.Kovan]: NULL_ADDRESS,
[ChainId.Ganache]: NULL_ADDRESS,
},
},
{
decimals: 18,
symbol: 'SNX',
name: 'Synthetix Network Token',
tokenAddresses: {
[ChainId.Mainnet]: '0xc011a72400e58ecd99ee497cf89e3775d4bd732f',
[ChainId.Kovan]: NULL_ADDRESS,
[ChainId.Ganache]: NULL_ADDRESS,
},
},
{
decimals: 18,
symbol: 'SETH',
name: 'sETH',
tokenAddresses: {
[ChainId.Mainnet]: '0x5e74c9036fb86bd7ecdcb084a0673efc32ea31cb',
[ChainId.Kovan]: NULL_ADDRESS,
[ChainId.Ganache]: NULL_ADDRESS,
},
},
{
decimals: 18,
symbol: 'SUSD',
name: 'sUSD',
tokenAddresses: {
[ChainId.Mainnet]: '0x57ab1ec28d129707052df4df418d58a2d46d5f51',
[ChainId.Kovan]: NULL_ADDRESS,
[ChainId.Ganache]: NULL_ADDRESS,
},
},
];
Loading

0 comments on commit aa57227

Please sign in to comment.