feat: asset-swapper market depth (#2641)

* feat: asset-swapper market depth

* split promises into 2

* fix lint and docs

* chore: refactor

* rebase off development

* CHANGELOG
This commit is contained in:
Jacob Evans
2020-07-27 15:07:52 +10:00
committed by GitHub
parent 72c869649a
commit 5afe2616a4
6 changed files with 282 additions and 113 deletions

View File

@@ -27,7 +27,12 @@ import { calculateLiquidity } from './utils/calculate_liquidity';
import { MarketOperationUtils } from './utils/market_operation_utils';
import { createDummyOrderForSampler } from './utils/market_operation_utils/orders';
import { DexOrderSampler } from './utils/market_operation_utils/sampler';
import { ERC20BridgeSource } from './utils/market_operation_utils/types';
import {
ERC20BridgeSource,
MarketDepth,
MarketDepthSide,
MarketSideLiquidity,
} from './utils/market_operation_utils/types';
import { orderPrunerUtils } from './utils/order_prune_utils';
import { OrderStateUtils } from './utils/order_state_utils';
import { ProtocolFeeUtils } from './utils/protocol_fee_utils';
@@ -393,6 +398,94 @@ export class SwapQuoter {
return calculateLiquidity(ordersWithFillableAmounts);
}
/**
* Returns the bids and asks liquidity for the entire market.
* For certain sources (like AMM's) it is recommended to provide a practical maximum takerAssetAmount.
* @param makerTokenAddress The address of the maker asset
* @param takerTokenAddress The address of the taker asset
* @param takerAssetAmount The amount to sell and buy for the bids and asks.
*
* @return An object that conforms to MarketDepth that contains all of the samples and liquidity
* information for the source.
*/
public async getBidAskLiquidityForMakerTakerAssetPairAsync(
makerTokenAddress: string,
takerTokenAddress: string,
takerAssetAmount: BigNumber,
options: Partial<SwapQuoteRequestOpts> = {},
): Promise<MarketDepth> {
assert.isString('makerTokenAddress', makerTokenAddress);
assert.isString('takerTokenAddress', takerTokenAddress);
const makerAssetData = assetDataUtils.encodeERC20AssetData(makerTokenAddress);
const takerAssetData = assetDataUtils.encodeERC20AssetData(takerTokenAddress);
let [sellOrders, buyOrders] =
options.excludedSources && options.excludedSources.includes(ERC20BridgeSource.Native)
? Promise.resolve([[], []])
: await Promise.all([
this.orderbook.getOrdersAsync(makerAssetData, takerAssetData),
this.orderbook.getOrdersAsync(takerAssetData, makerAssetData),
]);
if (!sellOrders || sellOrders.length === 0) {
sellOrders = [
{
metaData: {},
order: createDummyOrderForSampler(
makerAssetData,
takerAssetData,
this._contractAddresses.uniswapBridge,
),
},
];
}
if (!buyOrders || buyOrders.length === 0) {
buyOrders = [
{
metaData: {},
order: createDummyOrderForSampler(
takerAssetData,
makerAssetData,
this._contractAddresses.uniswapBridge,
),
},
];
}
const getMarketDepthSide = (marketSideLiquidity: MarketSideLiquidity): MarketDepthSide => {
const { dexQuotes, nativeOrders, orderFillableAmounts, side } = marketSideLiquidity;
return [
...dexQuotes,
nativeOrders.map((o, i) => {
const scaleFactor = orderFillableAmounts[i].div(o.takerAssetAmount);
return {
input: (side === MarketOperation.Sell ? o.takerAssetAmount : o.makerAssetAmount)
.times(scaleFactor)
.integerValue(),
output: (side === MarketOperation.Sell ? o.makerAssetAmount : o.takerAssetAmount)
.times(scaleFactor)
.integerValue(),
fillData: o,
source: ERC20BridgeSource.Native,
};
}),
];
};
const [bids, asks] = await Promise.all([
this._marketOperationUtils.getMarketBuyLiquidityAsync(
(buyOrders || []).map(o => o.order),
takerAssetAmount,
options,
),
this._marketOperationUtils.getMarketSellLiquidityAsync(
(sellOrders || []).map(o => o.order),
takerAssetAmount,
options,
),
]);
return {
bids: getMarketDepthSide(bids),
asks: getMarketDepthSide(asks),
};
}
/**
* Get the asset data of all assets that can be used to purchase makerAssetData in the order provider passed in at init.
*