Add liquidity source breakdown to asset-swapper (#2465)

* add liquidity source breakdown to asset-swapper

* remove debug line

* use OptimizedMarketOrder metadata

* updated change-log

* prettier + lint

* bug fixes

* fixes

* Prettier

* Fix types

Co-authored-by: Jacob Evans <dekz@dekz.net>
This commit is contained in:
David Sun 2020-02-04 04:03:28 -05:00 committed by GitHub
parent 919fc66b9d
commit 74d3b9334c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 71 additions and 19 deletions

View File

@ -1,10 +1,14 @@
[ [
{ {
"version": "4.0.2", "version": "4.1.0",
"changes": [ "changes": [
{ {
"note": "Allow contract addresses to be passed as optional constructor ags instead of hardcoding", "note": "Allow contract addresses to be passed as optional constructor ags instead of hardcoding",
"pr": 2461 "pr": 2461
},
{
"note": "Add swap quote liquidity source breakdown",
"pr": 2465
} }
] ]
}, },

View File

@ -54,6 +54,7 @@ export {
SwapQuoterOpts, SwapQuoterOpts,
SwapQuoteConsumerError, SwapQuoteConsumerError,
SignedOrderWithFillableAmounts, SignedOrderWithFillableAmounts,
SwapQuoteOrdersBreakdown,
} from './types'; } from './types';
export { export {
ERC20BridgeSource, ERC20BridgeSource,

View File

@ -1,4 +1,4 @@
import { ContractAddresses } from '@0x/migrations'; import { ContractAddresses } from '@0x/contract-wrappers';
import { SignedOrder } from '@0x/types'; import { SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils'; import { BigNumber } from '@0x/utils';
@ -142,6 +142,7 @@ export interface SwapQuoteBase {
orders: SignedOrder[]; orders: SignedOrder[];
bestCaseQuoteInfo: SwapQuoteInfo; bestCaseQuoteInfo: SwapQuoteInfo;
worstCaseQuoteInfo: SwapQuoteInfo; worstCaseQuoteInfo: SwapQuoteInfo;
sourceBreakdown: SwapQuoteOrdersBreakdown;
} }
/** /**
@ -177,6 +178,13 @@ export interface SwapQuoteInfo {
protocolFeeInWeiAmount: BigNumber; protocolFeeInWeiAmount: BigNumber;
} }
/**
* percentage breakdown of each liquidity source used in quote
*/
export interface SwapQuoteOrdersBreakdown {
[source: string]: BigNumber;
}
/** /**
* slippagePercentage: The percentage buffer to add to account for slippage. Affects max ETH price estimates. Defaults to 0.2 (20%). * slippagePercentage: The percentage buffer to add to account for slippage. Affects max ETH price estimates. Defaults to 0.2 (20%).
* gasPrice: gas price to determine protocolFee amount, default to ethGasStation fast amount * gasPrice: gas price to determine protocolFee amount, default to ethGasStation fast amount

View File

@ -11,7 +11,9 @@ import {
MarketSellSwapQuote, MarketSellSwapQuote,
SignedOrderWithFillableAmounts, SignedOrderWithFillableAmounts,
SwapQuote, SwapQuote,
SwapQuoteBase,
SwapQuoteInfo, SwapQuoteInfo,
SwapQuoteOrdersBreakdown,
} from '../types'; } from '../types';
import { fillableAmountsUtils } from './fillable_amounts_utils'; import { fillableAmountsUtils } from './fillable_amounts_utils';
@ -176,7 +178,9 @@ export class SwapQuoteCalculator {
true, true,
); );
const quoteBase = { const breakdown = this._getSwapQuoteOrdersBreakdown(resultOrders, operation);
const quoteBase: SwapQuoteBase = {
takerAssetData, takerAssetData,
makerAssetData, makerAssetData,
// Remove fill metadata. // Remove fill metadata.
@ -184,6 +188,7 @@ export class SwapQuoteCalculator {
bestCaseQuoteInfo, bestCaseQuoteInfo,
worstCaseQuoteInfo, worstCaseQuoteInfo,
gasPrice, gasPrice,
sourceBreakdown: breakdown,
}; };
if (operation === MarketOperation.Buy) { if (operation === MarketOperation.Buy) {
@ -398,6 +403,34 @@ export class SwapQuoteCalculator {
protocolFeeInWeiAmount, protocolFeeInWeiAmount,
}; };
} }
// tslint:disable-next-line: prefer-function-over-method
private _getSwapQuoteOrdersBreakdown(
orders: OptimizedMarketOrder[],
operation: MarketOperation,
): SwapQuoteOrdersBreakdown {
// HACK: to shut up linter
const breakdown: SwapQuoteOrdersBreakdown = {};
// total asset amount (accounting for slippage protection)
const totalAssetAmount = BigNumber.sum(
...[
constants.ZERO_AMOUNT,
...orders.map(o => (operation === MarketOperation.Buy ? o.makerAssetAmount : o.takerAssetAmount)),
],
);
return orders.reduce((acc: SwapQuoteOrdersBreakdown, order: OptimizedMarketOrder): SwapQuoteOrdersBreakdown => {
const assetAmount = operation === MarketOperation.Buy ? order.makerAssetAmount : order.takerAssetAmount;
const { source } = order.fill;
return {
...acc,
...{
[source]: (!!acc[source] ? acc[source].plus(assetAmount) : assetAmount).dividedBy(totalAssetAmount),
},
};
}, breakdown);
}
} }
function getTakerAssetAmountBreakDown( function getTakerAssetAmountBreakDown(

View File

@ -98,7 +98,7 @@ describe('swapQuoteCalculator', () => {
// exchangeAddress: contractAddresses.exchange, // exchangeAddress: contractAddresses.exchange,
// chainId: TESTRPC_CHAIN_ID, // chainId: TESTRPC_CHAIN_ID,
// }); // });
// const swapQuoteCalculator = new SwapQuoteCalculator(protocolFeeUtils, marketOperationUtils); // const swapQuoteCalculator = new SwapQuoteCalculator( protocolFeeUtils, marketOperationUtils);
// const errorFunction = async () => { // const errorFunction = async () => {
// await swapQuoteCalculator.calculateMarketSellSwapQuoteAsync( // await swapQuoteCalculator.calculateMarketSellSwapQuoteAsync(
// testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEELESS, // testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEELESS,
@ -117,7 +117,7 @@ describe('swapQuoteCalculator', () => {
// exchangeAddress: contractAddresses.exchange, // exchangeAddress: contractAddresses.exchange,
// chainId: TESTRPC_CHAIN_ID, // chainId: TESTRPC_CHAIN_ID,
// }); // });
// const swapQuoteCalculator = new SwapQuoteCalculator(protocolFeeUtils, marketOperationUtils); // const swapQuoteCalculator = new SwapQuoteCalculator( protocolFeeUtils, marketOperationUtils);
// await swapQuoteCalculator.calculateMarketSellSwapQuoteAsync( // await swapQuoteCalculator.calculateMarketSellSwapQuoteAsync(
// testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEELESS, // testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEELESS,
// baseUnitAmount(10), // baseUnitAmount(10),
@ -134,7 +134,7 @@ describe('swapQuoteCalculator', () => {
// exchangeAddress: contractAddresses.exchange, // exchangeAddress: contractAddresses.exchange,
// chainId: TESTRPC_CHAIN_ID, // chainId: TESTRPC_CHAIN_ID,
// }); // });
// const swapQuoteCalculator = new SwapQuoteCalculator(protocolFeeUtils, marketOperationUtils); // const swapQuoteCalculator = new SwapQuoteCalculator( protocolFeeUtils, marketOperationUtils);
// const errorFunction = async () => { // const errorFunction = async () => {
// await swapQuoteCalculator.calculateMarketSellSwapQuoteAsync( // await swapQuoteCalculator.calculateMarketSellSwapQuoteAsync(
// testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEE_IN_TAKER_ASSET, // testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEE_IN_TAKER_ASSET,
@ -152,7 +152,7 @@ describe('swapQuoteCalculator', () => {
// exchangeAddress: contractAddresses.exchange, // exchangeAddress: contractAddresses.exchange,
// chainId: TESTRPC_CHAIN_ID, // chainId: TESTRPC_CHAIN_ID,
// }); // });
// const swapQuoteCalculator = new SwapQuoteCalculator(protocolFeeUtils, marketOperationUtils); // const swapQuoteCalculator = new SwapQuoteCalculator( protocolFeeUtils, marketOperationUtils);
// const errorFunction = async () => { // const errorFunction = async () => {
// await swapQuoteCalculator.calculateMarketSellSwapQuoteAsync( // await swapQuoteCalculator.calculateMarketSellSwapQuoteAsync(
// testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEE_IN_TAKER_ASSET, // testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEE_IN_TAKER_ASSET,
@ -170,7 +170,7 @@ describe('swapQuoteCalculator', () => {
// exchangeAddress: contractAddresses.exchange, // exchangeAddress: contractAddresses.exchange,
// chainId: TESTRPC_CHAIN_ID, // chainId: TESTRPC_CHAIN_ID,
// }); // });
// const swapQuoteCalculator = new SwapQuoteCalculator(protocolFeeUtils, marketOperationUtils); // const swapQuoteCalculator = new SwapQuoteCalculator( protocolFeeUtils, marketOperationUtils);
// const errorFunction = async () => { // const errorFunction = async () => {
// await swapQuoteCalculator.calculateMarketSellSwapQuoteAsync( // await swapQuoteCalculator.calculateMarketSellSwapQuoteAsync(
// testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEE_IN_MAKER_ASSET, // testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEE_IN_MAKER_ASSET,
@ -188,7 +188,7 @@ describe('swapQuoteCalculator', () => {
// exchangeAddress: contractAddresses.exchange, // exchangeAddress: contractAddresses.exchange,
// chainId: TESTRPC_CHAIN_ID, // chainId: TESTRPC_CHAIN_ID,
// }); // });
// const swapQuoteCalculator = new SwapQuoteCalculator(protocolFeeUtils, marketOperationUtils); // const swapQuoteCalculator = new SwapQuoteCalculator( protocolFeeUtils, marketOperationUtils);
// const errorFunction = async () => { // const errorFunction = async () => {
// await swapQuoteCalculator.calculateMarketSellSwapQuoteAsync( // await swapQuoteCalculator.calculateMarketSellSwapQuoteAsync(
// testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEE_IN_MAKER_ASSET, // testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEE_IN_MAKER_ASSET,
@ -206,7 +206,7 @@ describe('swapQuoteCalculator', () => {
// exchangeAddress: contractAddresses.exchange, // exchangeAddress: contractAddresses.exchange,
// chainId: TESTRPC_CHAIN_ID, // chainId: TESTRPC_CHAIN_ID,
// }); // });
// const swapQuoteCalculator = new SwapQuoteCalculator(protocolFeeUtils, marketOperationUtils); // const swapQuoteCalculator = new SwapQuoteCalculator( protocolFeeUtils, marketOperationUtils);
// const errorFunction = async () => { // const errorFunction = async () => {
// await swapQuoteCalculator.calculateMarketSellSwapQuoteAsync( // await swapQuoteCalculator.calculateMarketSellSwapQuoteAsync(
// MIXED_TEST_ORDERS, // MIXED_TEST_ORDERS,
@ -224,7 +224,7 @@ describe('swapQuoteCalculator', () => {
// exchangeAddress: contractAddresses.exchange, // exchangeAddress: contractAddresses.exchange,
// chainId: TESTRPC_CHAIN_ID, // chainId: TESTRPC_CHAIN_ID,
// }); // });
// const swapQuoteCalculator = new SwapQuoteCalculator(protocolFeeUtils, marketOperationUtils); // const swapQuoteCalculator = new SwapQuoteCalculator( protocolFeeUtils, marketOperationUtils);
// const errorFunction = async () => { // const errorFunction = async () => {
// await swapQuoteCalculator.calculateMarketSellSwapQuoteAsync( // await swapQuoteCalculator.calculateMarketSellSwapQuoteAsync(
// MIXED_TEST_ORDERS, // MIXED_TEST_ORDERS,
@ -485,7 +485,7 @@ describe('swapQuoteCalculator', () => {
// exchangeAddress: contractAddresses.exchange, // exchangeAddress: contractAddresses.exchange,
// chainId: TESTRPC_CHAIN_ID, // chainId: TESTRPC_CHAIN_ID,
// }); // });
// const swapQuoteCalculator = new SwapQuoteCalculator(protocolFeeUtils, marketOperationUtils); // const swapQuoteCalculator = new SwapQuoteCalculator( protocolFeeUtils, marketOperationUtils);
// const errorFunction = async () => { // const errorFunction = async () => {
// await swapQuoteCalculator.calculateMarketBuySwapQuoteAsync( // await swapQuoteCalculator.calculateMarketBuySwapQuoteAsync(
// testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEELESS, // testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEELESS,
@ -503,7 +503,7 @@ describe('swapQuoteCalculator', () => {
// exchangeAddress: contractAddresses.exchange, // exchangeAddress: contractAddresses.exchange,
// chainId: TESTRPC_CHAIN_ID, // chainId: TESTRPC_CHAIN_ID,
// }); // });
// const swapQuoteCalculator = new SwapQuoteCalculator(protocolFeeUtils, marketOperationUtils); // const swapQuoteCalculator = new SwapQuoteCalculator( protocolFeeUtils, marketOperationUtils);
// const errorFunction = async () => { // const errorFunction = async () => {
// await swapQuoteCalculator.calculateMarketBuySwapQuoteAsync( // await swapQuoteCalculator.calculateMarketBuySwapQuoteAsync(
// testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEELESS, // testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEELESS,
@ -521,7 +521,7 @@ describe('swapQuoteCalculator', () => {
// exchangeAddress: contractAddresses.exchange, // exchangeAddress: contractAddresses.exchange,
// chainId: TESTRPC_CHAIN_ID, // chainId: TESTRPC_CHAIN_ID,
// }); // });
// const swapQuoteCalculator = new SwapQuoteCalculator(protocolFeeUtils, marketOperationUtils); // const swapQuoteCalculator = new SwapQuoteCalculator( protocolFeeUtils, marketOperationUtils);
// const errorFunction = async () => { // const errorFunction = async () => {
// await swapQuoteCalculator.calculateMarketBuySwapQuoteAsync( // await swapQuoteCalculator.calculateMarketBuySwapQuoteAsync(
// testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEE_IN_TAKER_ASSET, // testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEE_IN_TAKER_ASSET,
@ -539,7 +539,7 @@ describe('swapQuoteCalculator', () => {
// exchangeAddress: contractAddresses.exchange, // exchangeAddress: contractAddresses.exchange,
// chainId: TESTRPC_CHAIN_ID, // chainId: TESTRPC_CHAIN_ID,
// }); // });
// const swapQuoteCalculator = new SwapQuoteCalculator(protocolFeeUtils, marketOperationUtils); // const swapQuoteCalculator = new SwapQuoteCalculator( protocolFeeUtils, marketOperationUtils);
// const errorFunction = async () => { // const errorFunction = async () => {
// await swapQuoteCalculator.calculateMarketBuySwapQuoteAsync( // await swapQuoteCalculator.calculateMarketBuySwapQuoteAsync(
// testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEE_IN_TAKER_ASSET, // testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEE_IN_TAKER_ASSET,
@ -557,7 +557,7 @@ describe('swapQuoteCalculator', () => {
// exchangeAddress: contractAddresses.exchange, // exchangeAddress: contractAddresses.exchange,
// chainId: TESTRPC_CHAIN_ID, // chainId: TESTRPC_CHAIN_ID,
// }); // });
// const swapQuoteCalculator = new SwapQuoteCalculator(protocolFeeUtils, marketOperationUtils); // const swapQuoteCalculator = new SwapQuoteCalculator( protocolFeeUtils, marketOperationUtils);
// const errorFunction = async () => { // const errorFunction = async () => {
// await swapQuoteCalculator.calculateMarketBuySwapQuoteAsync( // await swapQuoteCalculator.calculateMarketBuySwapQuoteAsync(
// testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEE_IN_MAKER_ASSET, // testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEE_IN_MAKER_ASSET,
@ -575,7 +575,7 @@ describe('swapQuoteCalculator', () => {
// exchangeAddress: contractAddresses.exchange, // exchangeAddress: contractAddresses.exchange,
// chainId: TESTRPC_CHAIN_ID, // chainId: TESTRPC_CHAIN_ID,
// }); // });
// const swapQuoteCalculator = new SwapQuoteCalculator(protocolFeeUtils, marketOperationUtils); // const swapQuoteCalculator = new SwapQuoteCalculator( protocolFeeUtils, marketOperationUtils);
// const errorFunction = async () => { // const errorFunction = async () => {
// await swapQuoteCalculator.calculateMarketBuySwapQuoteAsync( // await swapQuoteCalculator.calculateMarketBuySwapQuoteAsync(
// testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEE_IN_MAKER_ASSET, // testOrders.SIGNED_ORDERS_WITH_FILLABLE_AMOUNTS_FEE_IN_MAKER_ASSET,
@ -593,7 +593,7 @@ describe('swapQuoteCalculator', () => {
// exchangeAddress: contractAddresses.exchange, // exchangeAddress: contractAddresses.exchange,
// chainId: TESTRPC_CHAIN_ID, // chainId: TESTRPC_CHAIN_ID,
// }); // });
// const swapQuoteCalculator = new SwapQuoteCalculator(protocolFeeUtils, marketOperationUtils); // const swapQuoteCalculator = new SwapQuoteCalculator( protocolFeeUtils, marketOperationUtils);
// const errorFunction = async () => { // const errorFunction = async () => {
// await swapQuoteCalculator.calculateMarketBuySwapQuoteAsync( // await swapQuoteCalculator.calculateMarketBuySwapQuoteAsync(
// MIXED_TEST_ORDERS, // MIXED_TEST_ORDERS,
@ -611,7 +611,7 @@ describe('swapQuoteCalculator', () => {
// exchangeAddress: contractAddresses.exchange, // exchangeAddress: contractAddresses.exchange,
// chainId: TESTRPC_CHAIN_ID, // chainId: TESTRPC_CHAIN_ID,
// }); // });
// const swapQuoteCalculator = new SwapQuoteCalculator(protocolFeeUtils, marketOperationUtils); // const swapQuoteCalculator = new SwapQuoteCalculator( protocolFeeUtils, marketOperationUtils);
// const errorFunction = async () => { // const errorFunction = async () => {
// await swapQuoteCalculator.calculateMarketBuySwapQuoteAsync( // await swapQuoteCalculator.calculateMarketBuySwapQuoteAsync(
// MIXED_TEST_ORDERS, // MIXED_TEST_ORDERS,

View File

@ -1,6 +1,7 @@
import { BigNumber } from '@0x/utils'; import { BigNumber } from '@0x/utils';
import * as _ from 'lodash'; import * as _ from 'lodash';
import { ERC20BridgeSource } from '../../src';
import { constants } from '../../src/constants'; import { constants } from '../../src/constants';
import { MarketOperation, SignedOrderWithFillableAmounts, SwapQuote } from '../../src/types'; import { MarketOperation, SignedOrderWithFillableAmounts, SwapQuote } from '../../src/types';
import { ProtocolFeeUtils } from '../../src/utils/protocol_fee_utils'; import { ProtocolFeeUtils } from '../../src/utils/protocol_fee_utils';
@ -26,6 +27,10 @@ export async function getFullyFillableSwapQuoteWithNoFeesAsync(
protocolFeeInWeiAmount: await protocolFeeUtils.calculateWorstCaseProtocolFeeAsync(orders, gasPrice), protocolFeeInWeiAmount: await protocolFeeUtils.calculateWorstCaseProtocolFeeAsync(orders, gasPrice),
}; };
const breakdown = {
[ERC20BridgeSource.Native]: new BigNumber(1),
};
const quoteBase = { const quoteBase = {
makerAssetData, makerAssetData,
takerAssetData, takerAssetData,
@ -33,6 +38,7 @@ export async function getFullyFillableSwapQuoteWithNoFeesAsync(
gasPrice, gasPrice,
bestCaseQuoteInfo: quoteInfo, bestCaseQuoteInfo: quoteInfo,
worstCaseQuoteInfo: quoteInfo, worstCaseQuoteInfo: quoteInfo,
sourceBreakdown: breakdown,
}; };
if (operation === MarketOperation.Buy) { if (operation === MarketOperation.Buy) {