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

feat: Depth Chart API endpoint #290

Merged
merged 5 commits into from
Jul 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@
},
"dependencies": {
"@0x/assert": "^3.0.4",
"@0x/asset-swapper": "0xProject/gitpkg-registry#0x-asset-swapper-v4.6.0-9a16f5736",
"@0x/asset-swapper": "0xProject/gitpkg-registry#0x-asset-swapper-v4.6.0-ae2a6fb68",
"@0x/connect": "^6.0.4",
"@0x/contract-addresses": "^4.11.0",
"@0x/contract-wrappers": "^13.7.0",
Expand Down
4 changes: 2 additions & 2 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ export const ASSET_SWAPPER_MARKET_ORDERS_V0_OPTS: Partial<SwapQuoteRequestOpts>
feeSchedule: FEE_SCHEDULE_V0,
gasSchedule: GAS_SCHEDULE_V0,
shouldBatchBridgeOrders: true,
runLimit: 2 ** 13,
runLimit: 2 ** 8,
};

export const GAS_SCHEDULE_V1: FeeSchedule = {
Expand All @@ -356,7 +356,7 @@ export const ASSET_SWAPPER_MARKET_ORDERS_V1_OPTS: Partial<SwapQuoteRequestOpts>
feeSchedule: FEE_SCHEDULE_V1,
gasSchedule: GAS_SCHEDULE_V1,
shouldBatchBridgeOrders: false,
runLimit: 2 ** 13,
runLimit: 2 ** 8,
};

export const SAMPLER_OVERRIDES: SamplerOverrides | undefined = (() => {
Expand Down
5 changes: 5 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,8 @@ export const GST2_WALLET_ADDRESSES = {
[ChainId.Kovan]: NULL_ADDRESS,
[ChainId.Ganache]: NULL_ADDRESS,
};

// Market Depth
export const MARKET_DEPTH_MAX_SAMPLES = 50;
export const MARKET_DEPTH_DEFAULT_DISTRIBUTION = 1.05;
export const MARKET_DEPTH_END_PRICE_SLIPPAGE_PERC = 20;
28 changes: 27 additions & 1 deletion src/handlers/swap_handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import * as express from 'express';
import * as HttpStatus from 'http-status-codes';

import { CHAIN_ID } from '../config';
import { DEFAULT_QUOTE_SLIPPAGE_PERCENTAGE, SWAP_DOCS_URL } from '../constants';
import {
DEFAULT_QUOTE_SLIPPAGE_PERCENTAGE,
MARKET_DEPTH_DEFAULT_DISTRIBUTION,
MARKET_DEPTH_MAX_SAMPLES,
SWAP_DOCS_URL,
} from '../constants';
import {
InternalServerError,
RevertAPIError,
Expand Down Expand Up @@ -125,6 +130,27 @@ export class SwapHandlers {
const records = await this._swapService.getTokenPricesAsync(baseAsset, unitAmount);
res.status(HttpStatus.OK).send({ records });
}

public async getMarketDepthAsync(req: express.Request, res: express.Response): Promise<void> {
const makerToken = getTokenMetadataIfExists(req.query.buyToken as string, CHAIN_ID);
const takerToken = getTokenMetadataIfExists(req.query.sellToken as string, CHAIN_ID);
const response = await this._swapService.calculateMarketDepthAsync({
buyToken: makerToken,
sellToken: takerToken,
sellAmount: new BigNumber(req.query.sellAmount as string),
// tslint:disable-next-line:radix custom-no-magic-numbers
numSamples: req.query.numSamples ? parseInt(req.query.numSamples as string) : MARKET_DEPTH_MAX_SAMPLES,
sampleDistributionBase: req.query.sampleDistributionBase
? parseFloat(req.query.sampleDistributionBase as string)
: MARKET_DEPTH_DEFAULT_DISTRIBUTION,
excludedSources:
req.query.excludedSources === undefined
? []
: parseUtils.parseStringArrForERC20BridgeSources((req.query.excludedSources as string).split(',')),
});
res.status(HttpStatus.OK).send({ ...response, buyToken: makerToken, sellToken: takerToken });
}

private async _calculateSwapQuoteAsync(
params: GetSwapQuoteRequestParams,
swapVersion: SwapVersion,
Expand Down
1 change: 1 addition & 0 deletions src/routers/swap_router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export function createSwapRouter(swapService: SwapService): express.Router {
router.get('/v0', asyncHandler(SwapHandlers.rootAsync.bind(SwapHandlers)));
router.get('/v0/prices', asyncHandler(handlers.getTokenPricesAsync.bind(handlers)));
router.get('/v0/tokens', asyncHandler(handlers.getSwapTokensAsync.bind(handlers)));
router.get('/v0/depth', asyncHandler(handlers.getMarketDepthAsync.bind(handlers)));

router.get('/v0/quote', asyncHandler(handlers.getSwapQuoteAsync.bind(handlers, SwapVersion.V0)));
router.get('/v0/price', asyncHandler(handlers.getSwapPriceAsync.bind(handlers, SwapVersion.V0)));
Expand Down
56 changes: 56 additions & 0 deletions src/services/swap_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { SwapQuoteRequestOpts, SwapQuoterOpts } from '@0x/asset-swapper/lib/src/
import { ContractAddresses, getContractAddressesForChainOrThrow } from '@0x/contract-addresses';
import { ERC20TokenContract, WETH9Contract } from '@0x/contract-wrappers';
import { assetDataUtils, SupportedProvider } from '@0x/order-utils';
import { MarketOperation } from '@0x/types';
import { BigNumber, decodeThrownErrorAsRevertError, RevertError } from '@0x/utils';
import { TxData, Web3Wrapper } from '@0x/web3-wrapper';
import * as _ from 'lodash';
Expand All @@ -38,6 +39,8 @@ import { InsufficientFundsError } from '../errors';
import { logger } from '../logger';
import { TokenMetadatasForChains } from '../token_metadatas_for_networks';
import {
BucketedPriceDepth,
CalaculateMarketDepthParams,
CalculateSwapQuoteParams,
GetSwapQuoteResponse,
GetTokenPricesResponse,
Expand All @@ -46,6 +49,7 @@ import {
SwapVersion,
TokenMetadata,
} from '../types';
import { marketDepthUtils } from '../utils/market_depth_utils';
import { createResultCache, ResultCache } from '../utils/result_cache';
import { serviceUtils } from '../utils/service_utils';
import { getTokenMetadataIfExists } from '../utils/token_metadata_utils';
Expand Down Expand Up @@ -269,6 +273,58 @@ export class SwapService {
return prices;
}

public async calculateMarketDepthAsync(
params: CalaculateMarketDepthParams,
): Promise<{
asks: { depth: BucketedPriceDepth[] };
bids: { depth: BucketedPriceDepth[] };
}> {
const { buyToken, sellToken, sellAmount, numSamples, sampleDistributionBase, excludedSources } = params;
const marketDepth = await this._swapQuoter.getBidAskLiquidityForMakerTakerAssetPairAsync(
buyToken.tokenAddress,
sellToken.tokenAddress,
sellAmount,
{
numSamples,
excludedSources: [...(excludedSources || []), ERC20BridgeSource.MultiBridge],
sampleDistributionBase,
},
);

const maxEndSlippagePercentage = 20;
const scalePriceByDecimals = (priceDepth: BucketedPriceDepth[]) =>
priceDepth.map(b => ({
...b,
price: b.price.times(new BigNumber(10).pow(sellToken.decimals - buyToken.decimals)),
}));
const askDepth = scalePriceByDecimals(
marketDepthUtils.calculateDepthForSide(
marketDepth.asks,
MarketOperation.Sell,
numSamples * 2,
sampleDistributionBase,
maxEndSlippagePercentage,
),
);
const bidDepth = scalePriceByDecimals(
marketDepthUtils.calculateDepthForSide(
marketDepth.bids,
MarketOperation.Buy,
numSamples * 2,
sampleDistributionBase,
maxEndSlippagePercentage,
),
);
return {
// We're buying buyToken and SELLING sellToken (DAI) (50k)
// Price goes from HIGH to LOW
asks: { depth: askDepth },
// We're BUYING sellToken (DAI) (50k) and selling buyToken
// Price goes from LOW to HIGH
bids: { depth: bidDepth },
};
}

private async _getSwapQuoteForWethAsync(
params: CalculateSwapQuoteParams,
isUnwrap: boolean,
Expand Down
16 changes: 16 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -613,4 +613,20 @@ export interface HttpServiceConfig {
meshHttpUri?: string;
metaTxnRateLimiters?: MetaTransactionRateLimitConfig;
}

export interface CalaculateMarketDepthParams {
buyToken: TokenMetadata;
sellToken: TokenMetadata;
sellAmount: BigNumber;
numSamples: number;
sampleDistributionBase: number;
excludedSources?: ERC20BridgeSource[];
}

export interface BucketedPriceDepth {
cumulative: BigNumber;
price: BigNumber;
bucket: number;
bucketTotal: BigNumber;
}
// tslint:disable-line:max-file-line-count
Loading