feat: [asset-swapper] more hops via token adjacency (#24)

* feat: [asset-swapper] more hops via token adjacency

* fix lint

* CHANGELOG
This commit is contained in:
Jacob Evans 2020-11-03 07:48:37 +10:00 committed by GitHub
parent f4709ed1cb
commit e10a81023a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 135 additions and 56 deletions

View File

@ -1,10 +1,14 @@
[ [
{ {
"version": "4.9.0", "version": "5.0.0",
"changes": [ "changes": [
{ {
"note": "Support multiple `Shells` by supplying the `pool` address", "note": "Support multiple `Shells` by supplying the `pool` address",
"pr": 17 "pr": 17
},
{
"note": "Make use of Token Adjacency in more places. Moved as a parameter for the quote",
"pr": 24
} }
] ]
}, },

View File

@ -14,7 +14,7 @@ import {
SwapQuoteRequestOpts, SwapQuoteRequestOpts,
SwapQuoterOpts, SwapQuoterOpts,
} from './types'; } from './types';
import { DEFAULT_GET_MARKET_ORDERS_OPTS } from './utils/market_operation_utils/constants'; import { DEFAULT_GET_MARKET_ORDERS_OPTS, TOKENS } from './utils/market_operation_utils/constants';
const ETH_GAS_STATION_API_URL = 'https://ethgasstation.info/api/ethgasAPI.json'; const ETH_GAS_STATION_API_URL = 'https://ethgasstation.info/api/ethgasAPI.json';
const NULL_BYTES = '0x'; const NULL_BYTES = '0x';
@ -42,6 +42,7 @@ const PROTOCOL_FEE_MULTIPLIER = new BigNumber(70000);
// default 50% buffer for selecting native orders to be aggregated with other sources // default 50% buffer for selecting native orders to be aggregated with other sources
const MARKET_UTILS_AMOUNT_BUFFER_PERCENTAGE = 0.5; const MARKET_UTILS_AMOUNT_BUFFER_PERCENTAGE = 0.5;
const DEFAULT_INTERMEDIATE_TOKENS = [TOKENS.WETH, TOKENS.USDT, TOKENS.DAI, TOKENS.USDC];
const DEFAULT_SWAP_QUOTER_OPTS: SwapQuoterOpts = { const DEFAULT_SWAP_QUOTER_OPTS: SwapQuoterOpts = {
chainId: ChainId.Mainnet, chainId: ChainId.Mainnet,
orderRefreshIntervalMs: 10000, // 10 seconds orderRefreshIntervalMs: 10000, // 10 seconds
@ -125,6 +126,7 @@ export const constants = {
ONE_SECOND_MS, ONE_SECOND_MS,
ONE_MINUTE_MS, ONE_MINUTE_MS,
DEFAULT_SWAP_QUOTER_OPTS, DEFAULT_SWAP_QUOTER_OPTS,
DEFAULT_INTERMEDIATE_TOKENS,
DEFAULT_FORWARDER_SWAP_QUOTE_GET_OPTS, DEFAULT_FORWARDER_SWAP_QUOTE_GET_OPTS,
DEFAULT_FORWARDER_SWAP_QUOTE_EXECUTE_OPTS, DEFAULT_FORWARDER_SWAP_QUOTE_EXECUTE_OPTS,
DEFAULT_SWAP_QUOTE_REQUEST_OPTS, DEFAULT_SWAP_QUOTE_REQUEST_OPTS,

View File

@ -166,7 +166,6 @@ export class SwapQuoter {
samplerGasLimit, samplerGasLimit,
liquidityProviderRegistryAddress, liquidityProviderRegistryAddress,
rfqt, rfqt,
tokenAdjacencyGraph,
} = _.merge({}, constants.DEFAULT_SWAP_QUOTER_OPTS, options); } = _.merge({}, constants.DEFAULT_SWAP_QUOTER_OPTS, options);
const provider = providerUtils.standardizeOrThrow(supportedProvider); const provider = providerUtils.standardizeOrThrow(supportedProvider);
assert.isValidOrderbook('orderbook', orderbook); assert.isValidOrderbook('orderbook', orderbook);
@ -215,7 +214,6 @@ export class SwapQuoter {
exchangeAddress: this._contractAddresses.exchange, exchangeAddress: this._contractAddresses.exchange,
}, },
liquidityProviderRegistryAddress, liquidityProviderRegistryAddress,
tokenAdjacencyGraph,
); );
this._swapQuoteCalculator = new SwapQuoteCalculator(this._marketOperationUtils); this._swapQuoteCalculator = new SwapQuoteCalculator(this._marketOperationUtils);
} }

View File

@ -4,12 +4,7 @@ import { TakerRequestQueryParams } from '@0x/quote-server';
import { SignedOrder } from '@0x/types'; import { SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils'; import { BigNumber } from '@0x/utils';
import { import { ERC20BridgeSource, GetMarketOrdersOpts, OptimizedMarketOrder } from './utils/market_operation_utils/types';
ERC20BridgeSource,
GetMarketOrdersOpts,
OptimizedMarketOrder,
TokenAdjacencyGraph,
} from './utils/market_operation_utils/types';
import { QuoteReport } from './utils/quote_report_generator'; import { QuoteReport } from './utils/quote_report_generator';
/** /**
@ -315,7 +310,6 @@ export interface SwapQuoterOpts extends OrderPrunerOpts {
ethGasStationUrl?: string; ethGasStationUrl?: string;
rfqt?: SwapQuoterRfqtOpts; rfqt?: SwapQuoterRfqtOpts;
samplerOverrides?: SamplerOverrides; samplerOverrides?: SamplerOverrides;
tokenAdjacencyGraph?: TokenAdjacencyGraph;
} }
/** /**

View File

@ -459,4 +459,5 @@ export const DEFAULT_GET_MARKET_ORDERS_OPTS: GetMarketOrdersOpts = {
exchangeProxyOverhead: () => ZERO_AMOUNT, exchangeProxyOverhead: () => ZERO_AMOUNT,
allowFallback: true, allowFallback: true,
shouldGenerateQuoteReport: false, shouldGenerateQuoteReport: false,
tokenAdjacencyGraph: {},
}; };

View File

@ -41,7 +41,6 @@ import {
OptimizerResult, OptimizerResult,
OptimizerResultWithReport, OptimizerResultWithReport,
OrderDomain, OrderDomain,
TokenAdjacencyGraph,
} from './types'; } from './types';
// tslint:disable:boolean-naming // tslint:disable:boolean-naming
@ -109,7 +108,6 @@ export class MarketOperationUtils {
private readonly contractAddresses: AssetSwapperContractAddresses, private readonly contractAddresses: AssetSwapperContractAddresses,
private readonly _orderDomain: OrderDomain, private readonly _orderDomain: OrderDomain,
private readonly _liquidityProviderRegistry: string = NULL_ADDRESS, private readonly _liquidityProviderRegistry: string = NULL_ADDRESS,
private readonly _tokenAdjacencyGraph: TokenAdjacencyGraph = {},
) { ) {
this._wethAddress = contractAddresses.etherToken.toLowerCase(); this._wethAddress = contractAddresses.etherToken.toLowerCase();
this._multiBridge = contractAddresses.multiBridge.toLowerCase(); this._multiBridge = contractAddresses.multiBridge.toLowerCase();
@ -182,7 +180,6 @@ export class MarketOperationUtils {
makerToken, makerToken,
this._wethAddress, this._wethAddress,
ONE_ETHER, ONE_ETHER,
this._wethAddress,
this._liquidityProviderRegistry, this._liquidityProviderRegistry,
this._multiBridge, this._multiBridge,
), ),
@ -192,7 +189,6 @@ export class MarketOperationUtils {
takerToken, takerToken,
this._wethAddress, this._wethAddress,
ONE_ETHER, ONE_ETHER,
this._wethAddress,
this._liquidityProviderRegistry, this._liquidityProviderRegistry,
this._multiBridge, this._multiBridge,
), ),
@ -203,6 +199,7 @@ export class MarketOperationUtils {
takerToken, takerToken,
sampleAmounts, sampleAmounts,
this._wethAddress, this._wethAddress,
_opts.tokenAdjacencyGraph,
this._liquidityProviderRegistry, this._liquidityProviderRegistry,
this._multiBridge, this._multiBridge,
), ),
@ -211,8 +208,8 @@ export class MarketOperationUtils {
makerToken, makerToken,
takerToken, takerToken,
takerAmount, takerAmount,
this._tokenAdjacencyGraph,
this._wethAddress, this._wethAddress,
_opts.tokenAdjacencyGraph,
this._liquidityProviderRegistry, this._liquidityProviderRegistry,
), ),
); );
@ -333,7 +330,6 @@ export class MarketOperationUtils {
makerToken, makerToken,
this._wethAddress, this._wethAddress,
ONE_ETHER, ONE_ETHER,
this._wethAddress,
this._liquidityProviderRegistry, this._liquidityProviderRegistry,
this._multiBridge, this._multiBridge,
), ),
@ -343,7 +339,6 @@ export class MarketOperationUtils {
takerToken, takerToken,
this._wethAddress, this._wethAddress,
ONE_ETHER, ONE_ETHER,
this._wethAddress,
this._liquidityProviderRegistry, this._liquidityProviderRegistry,
this._multiBridge, this._multiBridge,
), ),
@ -354,6 +349,7 @@ export class MarketOperationUtils {
takerToken, takerToken,
sampleAmounts, sampleAmounts,
this._wethAddress, this._wethAddress,
_opts.tokenAdjacencyGraph,
this._liquidityProviderRegistry, this._liquidityProviderRegistry,
), ),
this._sampler.getTwoHopBuyQuotes( this._sampler.getTwoHopBuyQuotes(
@ -361,8 +357,8 @@ export class MarketOperationUtils {
makerToken, makerToken,
takerToken, takerToken,
makerAmount, makerAmount,
this._tokenAdjacencyGraph,
this._wethAddress, this._wethAddress,
_opts.tokenAdjacencyGraph,
this._liquidityProviderRegistry, this._liquidityProviderRegistry,
), ),
); );
@ -493,6 +489,7 @@ export class MarketOperationUtils {
getNativeOrderTokens(orders[0])[1], getNativeOrderTokens(orders[0])[1],
[makerAmounts[i]], [makerAmounts[i]],
this._wethAddress, this._wethAddress,
_opts.tokenAdjacencyGraph,
), ),
), ),
]; ];

View File

@ -34,7 +34,7 @@ export function getIntermediateTokens(
[wethAddress], [wethAddress],
); );
} }
return intermediateTokens.filter( return _.uniqBy(intermediateTokens, a => a.toLowerCase()).filter(
token => token.toLowerCase() !== makerToken.toLowerCase() && token.toLowerCase() !== takerToken.toLowerCase(), token => token.toLowerCase() !== makerToken.toLowerCase() && token.toLowerCase() !== takerToken.toLowerCase(),
); );
} }

View File

@ -669,8 +669,8 @@ export class SamplerOperations {
makerToken: string, makerToken: string,
takerToken: string, takerToken: string,
sellAmount: BigNumber, sellAmount: BigNumber,
tokenAdjacencyGraph: TokenAdjacencyGraph,
wethAddress: string, wethAddress: string,
tokenAdjacencyGraph: TokenAdjacencyGraph,
liquidityProviderRegistryAddress?: string, liquidityProviderRegistryAddress?: string,
): BatchedOperation<Array<DexSample<MultiHopFillData>>> { ): BatchedOperation<Array<DexSample<MultiHopFillData>>> {
const _sources = TWO_HOP_SOURCE_FILTERS.getAllowed(sources); const _sources = TWO_HOP_SOURCE_FILTERS.getAllowed(sources);
@ -685,6 +685,7 @@ export class SamplerOperations {
takerToken, takerToken,
[ZERO_AMOUNT], [ZERO_AMOUNT],
wethAddress, wethAddress,
tokenAdjacencyGraph,
liquidityProviderRegistryAddress, liquidityProviderRegistryAddress,
); );
const secondHopOps = this._getSellQuoteOperations( const secondHopOps = this._getSellQuoteOperations(
@ -693,6 +694,7 @@ export class SamplerOperations {
intermediateToken, intermediateToken,
[ZERO_AMOUNT], [ZERO_AMOUNT],
wethAddress, wethAddress,
tokenAdjacencyGraph,
liquidityProviderRegistryAddress, liquidityProviderRegistryAddress,
); );
return new SamplerContractOperation({ return new SamplerContractOperation({
@ -745,8 +747,8 @@ export class SamplerOperations {
makerToken: string, makerToken: string,
takerToken: string, takerToken: string,
buyAmount: BigNumber, buyAmount: BigNumber,
tokenAdjacencyGraph: TokenAdjacencyGraph,
wethAddress: string, wethAddress: string,
tokenAdjacencyGraph: TokenAdjacencyGraph,
liquidityProviderRegistryAddress?: string, liquidityProviderRegistryAddress?: string,
): BatchedOperation<Array<DexSample<MultiHopFillData>>> { ): BatchedOperation<Array<DexSample<MultiHopFillData>>> {
const _sources = TWO_HOP_SOURCE_FILTERS.getAllowed(sources); const _sources = TWO_HOP_SOURCE_FILTERS.getAllowed(sources);
@ -761,6 +763,7 @@ export class SamplerOperations {
takerToken, takerToken,
[new BigNumber(0)], [new BigNumber(0)],
wethAddress, wethAddress,
tokenAdjacencyGraph, // TODO is this a bad idea?
liquidityProviderRegistryAddress, liquidityProviderRegistryAddress,
); );
const secondHopOps = this._getBuyQuoteOperations( const secondHopOps = this._getBuyQuoteOperations(
@ -769,6 +772,7 @@ export class SamplerOperations {
intermediateToken, intermediateToken,
[new BigNumber(0)], [new BigNumber(0)],
wethAddress, wethAddress,
tokenAdjacencyGraph,
liquidityProviderRegistryAddress, liquidityProviderRegistryAddress,
); );
return new SamplerContractOperation({ return new SamplerContractOperation({
@ -932,7 +936,6 @@ export class SamplerOperations {
makerToken: string, makerToken: string,
takerToken: string, takerToken: string,
takerFillAmount: BigNumber, takerFillAmount: BigNumber,
wethAddress: string,
liquidityProviderRegistryAddress?: string, liquidityProviderRegistryAddress?: string,
multiBridgeAddress?: string, multiBridgeAddress?: string,
): BatchedOperation<BigNumber> { ): BatchedOperation<BigNumber> {
@ -944,7 +947,8 @@ export class SamplerOperations {
makerToken, makerToken,
takerToken, takerToken,
[takerFillAmount], [takerFillAmount],
wethAddress, NULL_ADDRESS, // weth address
{}, // token adjacency
liquidityProviderRegistryAddress, liquidityProviderRegistryAddress,
multiBridgeAddress, multiBridgeAddress,
); );
@ -988,6 +992,7 @@ export class SamplerOperations {
takerToken: string, takerToken: string,
takerFillAmounts: BigNumber[], takerFillAmounts: BigNumber[],
wethAddress: string, wethAddress: string,
tokenAdjacencyGraph: TokenAdjacencyGraph,
liquidityProviderRegistryAddress?: string, liquidityProviderRegistryAddress?: string,
multiBridgeAddress?: string, multiBridgeAddress?: string,
): BatchedOperation<DexSample[][]> { ): BatchedOperation<DexSample[][]> {
@ -997,6 +1002,7 @@ export class SamplerOperations {
takerToken, takerToken,
takerFillAmounts, takerFillAmounts,
wethAddress, wethAddress,
tokenAdjacencyGraph,
liquidityProviderRegistryAddress, liquidityProviderRegistryAddress,
multiBridgeAddress, multiBridgeAddress,
); );
@ -1029,6 +1035,7 @@ export class SamplerOperations {
takerToken: string, takerToken: string,
makerFillAmounts: BigNumber[], makerFillAmounts: BigNumber[],
wethAddress: string, wethAddress: string,
tokenAdjacencyGraph: TokenAdjacencyGraph,
liquidityProviderRegistryAddress?: string, liquidityProviderRegistryAddress?: string,
): BatchedOperation<DexSample[][]> { ): BatchedOperation<DexSample[][]> {
const subOps = this._getBuyQuoteOperations( const subOps = this._getBuyQuoteOperations(
@ -1037,6 +1044,7 @@ export class SamplerOperations {
takerToken, takerToken,
makerFillAmounts, makerFillAmounts,
wethAddress, wethAddress,
tokenAdjacencyGraph,
liquidityProviderRegistryAddress, liquidityProviderRegistryAddress,
); );
return { return {
@ -1068,6 +1076,7 @@ export class SamplerOperations {
takerToken: string, takerToken: string,
takerFillAmounts: BigNumber[], takerFillAmounts: BigNumber[],
wethAddress: string, wethAddress: string,
tokenAdjacencyGraph: TokenAdjacencyGraph,
liquidityProviderRegistryAddress?: string, liquidityProviderRegistryAddress?: string,
multiBridgeAddress?: string, multiBridgeAddress?: string,
): SourceQuoteOperation[] { ): SourceQuoteOperation[] {
@ -1076,6 +1085,11 @@ export class SamplerOperations {
) )
.exclude(multiBridgeAddress || multiBridgeAddress === NULL_ADDRESS ? [] : [ERC20BridgeSource.MultiBridge]) .exclude(multiBridgeAddress || multiBridgeAddress === NULL_ADDRESS ? [] : [ERC20BridgeSource.MultiBridge])
.getAllowed(sources); .getAllowed(sources);
// Find the adjacent tokens in the provided tooken adjacency graph,
// e.g if this is DAI->USDC we may check for DAI->WETH->USDC
const intermediateTokens = getIntermediateTokens(makerToken, takerToken, tokenAdjacencyGraph, wethAddress);
return _.flatten( return _.flatten(
_sources.map( _sources.map(
(source): SourceQuoteOperation | SourceQuoteOperation[] => { (source): SourceQuoteOperation | SourceQuoteOperation[] => {
@ -1086,25 +1100,17 @@ export class SamplerOperations {
return this.getUniswapSellQuotes(makerToken, takerToken, takerFillAmounts); return this.getUniswapSellQuotes(makerToken, takerToken, takerFillAmounts);
case ERC20BridgeSource.UniswapV2: case ERC20BridgeSource.UniswapV2:
const ops = [this.getUniswapV2SellQuotes([takerToken, makerToken], takerFillAmounts)]; const ops = [this.getUniswapV2SellQuotes([takerToken, makerToken], takerFillAmounts)];
if (takerToken !== wethAddress && makerToken !== wethAddress) { intermediateTokens.forEach(t => {
ops.push( ops.push(this.getUniswapV2SellQuotes([takerToken, t, makerToken], takerFillAmounts));
this.getUniswapV2SellQuotes( });
[takerToken, wethAddress, makerToken],
takerFillAmounts,
),
);
}
return ops; return ops;
case ERC20BridgeSource.SushiSwap: case ERC20BridgeSource.SushiSwap:
const sushiOps = [this.getSushiSwapSellQuotes([takerToken, makerToken], takerFillAmounts)]; const sushiOps = [this.getSushiSwapSellQuotes([takerToken, makerToken], takerFillAmounts)];
if (takerToken !== wethAddress && makerToken !== wethAddress) { intermediateTokens.forEach(t => {
sushiOps.push( sushiOps.push(
this.getSushiSwapSellQuotes( this.getSushiSwapSellQuotes([takerToken, t, makerToken], takerFillAmounts),
[takerToken, wethAddress, makerToken],
takerFillAmounts,
),
); );
} });
return sushiOps; return sushiOps;
case ERC20BridgeSource.Kyber: case ERC20BridgeSource.Kyber:
return getKyberReserveIdsForPair(takerToken, makerToken).map(reserveId => return getKyberReserveIdsForPair(takerToken, makerToken).map(reserveId =>
@ -1211,11 +1217,17 @@ export class SamplerOperations {
takerToken: string, takerToken: string,
makerFillAmounts: BigNumber[], makerFillAmounts: BigNumber[],
wethAddress: string, wethAddress: string,
tokenAdjacencyGraph: TokenAdjacencyGraph,
liquidityProviderRegistryAddress?: string, liquidityProviderRegistryAddress?: string,
): SourceQuoteOperation[] { ): SourceQuoteOperation[] {
const _sources = BATCH_SOURCE_FILTERS.exclude( const _sources = BATCH_SOURCE_FILTERS.exclude(
liquidityProviderRegistryAddress ? [] : [ERC20BridgeSource.LiquidityProvider], liquidityProviderRegistryAddress ? [] : [ERC20BridgeSource.LiquidityProvider],
).getAllowed(sources); ).getAllowed(sources);
// Find the adjacent tokens in the provided tooken adjacency graph,
// e.g if this is DAI->USDC we may check for DAI->WETH->USDC
const intermediateTokens = getIntermediateTokens(makerToken, takerToken, tokenAdjacencyGraph, wethAddress);
return _.flatten( return _.flatten(
_sources.map( _sources.map(
(source): SourceQuoteOperation | SourceQuoteOperation[] => { (source): SourceQuoteOperation | SourceQuoteOperation[] => {
@ -1226,19 +1238,17 @@ export class SamplerOperations {
return this.getUniswapBuyQuotes(makerToken, takerToken, makerFillAmounts); return this.getUniswapBuyQuotes(makerToken, takerToken, makerFillAmounts);
case ERC20BridgeSource.UniswapV2: case ERC20BridgeSource.UniswapV2:
const ops = [this.getUniswapV2BuyQuotes([takerToken, makerToken], makerFillAmounts)]; const ops = [this.getUniswapV2BuyQuotes([takerToken, makerToken], makerFillAmounts)];
if (takerToken !== wethAddress && makerToken !== wethAddress) { intermediateTokens.forEach(t => {
ops.push( ops.push(this.getUniswapV2BuyQuotes([takerToken, t, makerToken], makerFillAmounts));
this.getUniswapV2BuyQuotes([takerToken, wethAddress, makerToken], makerFillAmounts), });
);
}
return ops; return ops;
case ERC20BridgeSource.SushiSwap: case ERC20BridgeSource.SushiSwap:
const sushiOps = [this.getSushiSwapBuyQuotes([takerToken, makerToken], makerFillAmounts)]; const sushiOps = [this.getSushiSwapBuyQuotes([takerToken, makerToken], makerFillAmounts)];
if (takerToken !== wethAddress && makerToken !== wethAddress) { intermediateTokens.forEach(t => {
sushiOps.push( sushiOps.push(
this.getSushiSwapBuyQuotes([takerToken, wethAddress, makerToken], makerFillAmounts), this.getSushiSwapBuyQuotes([takerToken, t, makerToken], makerFillAmounts),
); );
} });
return sushiOps; return sushiOps;
case ERC20BridgeSource.Kyber: case ERC20BridgeSource.Kyber:
return getKyberReserveIdsForPair(takerToken, makerToken).map(reserveId => return getKyberReserveIdsForPair(takerToken, makerToken).map(reserveId =>

View File

@ -317,6 +317,11 @@ export interface GetMarketOrdersOpts {
* Whether to generate a quote report * Whether to generate a quote report
*/ */
shouldGenerateQuoteReport: boolean; shouldGenerateQuoteReport: boolean;
/**
* Token addresses with a list of adjacent intermediary tokens to consider
* hopping to. E.g DAI->USDC via an adjacent token WETH
*/
tokenAdjacencyGraph: TokenAdjacencyGraph;
} }
/** /**

View File

@ -18,7 +18,7 @@ import {
computeBalancerSellQuote, computeBalancerSellQuote,
} from '../src/utils/market_operation_utils/balancer_utils'; } from '../src/utils/market_operation_utils/balancer_utils';
import { DexOrderSampler, getSampleAmounts } from '../src/utils/market_operation_utils/sampler'; import { DexOrderSampler, getSampleAmounts } from '../src/utils/market_operation_utils/sampler';
import { ERC20BridgeSource } from '../src/utils/market_operation_utils/types'; import { ERC20BridgeSource, TokenAdjacencyGraph } from '../src/utils/market_operation_utils/types';
import { MockBalancerPoolsCache } from './utils/mock_balancer_pools_cache'; import { MockBalancerPoolsCache } from './utils/mock_balancer_pools_cache';
import { MockBancorService } from './utils/mock_bancor_service'; import { MockBancorService } from './utils/mock_bancor_service';
@ -36,6 +36,8 @@ describe('DexSampler tests', () => {
const wethAddress = getContractAddressesForChainOrThrow(CHAIN_ID).etherToken; const wethAddress = getContractAddressesForChainOrThrow(CHAIN_ID).etherToken;
const exchangeAddress = getContractAddressesForChainOrThrow(CHAIN_ID).exchange; const exchangeAddress = getContractAddressesForChainOrThrow(CHAIN_ID).exchange;
const tokenAdjacencyGraph: TokenAdjacencyGraph = {};
describe('getSampleAmounts()', () => { describe('getSampleAmounts()', () => {
const FILL_AMOUNT = getRandomInteger(1, 1e18); const FILL_AMOUNT = getRandomInteger(1, 1e18);
const NUM_SAMPLES = 16; const NUM_SAMPLES = 16;
@ -175,6 +177,7 @@ describe('DexSampler tests', () => {
expectedTakerToken, expectedTakerToken,
[toBaseUnitAmount(1000)], [toBaseUnitAmount(1000)],
wethAddress, wethAddress,
tokenAdjacencyGraph,
registry, registry,
), ),
); );
@ -211,6 +214,7 @@ describe('DexSampler tests', () => {
expectedTakerToken, expectedTakerToken,
[toBaseUnitAmount(1000)], [toBaseUnitAmount(1000)],
wethAddress, wethAddress,
tokenAdjacencyGraph,
registry, registry,
), ),
); );
@ -252,7 +256,8 @@ describe('DexSampler tests', () => {
expectedMakerToken, expectedMakerToken,
expectedTakerToken, expectedTakerToken,
[toBaseUnitAmount(1000)], [toBaseUnitAmount(1000)],
randomAddress(), wethAddress,
tokenAdjacencyGraph,
randomAddress(), randomAddress(),
multiBridge, multiBridge,
), ),
@ -419,6 +424,7 @@ describe('DexSampler tests', () => {
expectedTakerToken, expectedTakerToken,
expectedTakerFillAmounts, expectedTakerFillAmounts,
wethAddress, wethAddress,
tokenAdjacencyGraph,
), ),
); );
const expectedQuotes = sources.map(s => const expectedQuotes = sources.map(s =>
@ -563,6 +569,7 @@ describe('DexSampler tests', () => {
expectedTakerToken, expectedTakerToken,
expectedMakerFillAmounts, expectedMakerFillAmounts,
wethAddress, wethAddress,
tokenAdjacencyGraph,
), ),
); );
const expectedQuotes = sources.map(s => const expectedQuotes = sources.map(s =>

View File

@ -41,6 +41,7 @@ import {
GetMarketOrdersOpts, GetMarketOrdersOpts,
MarketSideLiquidity, MarketSideLiquidity,
NativeFillData, NativeFillData,
TokenAdjacencyGraph,
} from '../src/utils/market_operation_utils/types'; } from '../src/utils/market_operation_utils/types';
const MAKER_TOKEN = randomAddress(); const MAKER_TOKEN = randomAddress();
@ -64,6 +65,7 @@ const DEFAULT_EXCLUDED = [
]; ];
const BUY_SOURCES = BUY_SOURCE_FILTER.sources; const BUY_SOURCES = BUY_SOURCE_FILTER.sources;
const SELL_SOURCES = SELL_SOURCE_FILTER.sources; const SELL_SOURCES = SELL_SOURCE_FILTER.sources;
const TOKEN_ADJACENCY_GRAPH: TokenAdjacencyGraph = {};
// tslint:disable: custom-no-magic-numbers promise-function-async // tslint:disable: custom-no-magic-numbers promise-function-async
describe('MarketOperationUtils tests', () => { describe('MarketOperationUtils tests', () => {
@ -219,6 +221,7 @@ describe('MarketOperationUtils tests', () => {
takerToken: string, takerToken: string,
fillAmounts: BigNumber[], fillAmounts: BigNumber[],
wethAddress: string, wethAddress: string,
tokenAdjacencyGraph: TokenAdjacencyGraph,
liquidityProviderAddress?: string, liquidityProviderAddress?: string,
) => DexSample[][]; ) => DexSample[][];
@ -248,6 +251,7 @@ describe('MarketOperationUtils tests', () => {
takerToken: string, takerToken: string,
fillAmounts: BigNumber[], fillAmounts: BigNumber[],
wethAddress: string, wethAddress: string,
tokenAdjacencyGraph: TokenAdjacencyGraph = TOKEN_ADJACENCY_GRAPH,
liquidityProviderAddress?: string, liquidityProviderAddress?: string,
) => { ) => {
liquidityPoolParams.liquidityProviderAddress = liquidityProviderAddress; liquidityPoolParams.liquidityProviderAddress = liquidityProviderAddress;
@ -258,6 +262,7 @@ describe('MarketOperationUtils tests', () => {
takerToken, takerToken,
fillAmounts, fillAmounts,
wethAddress, wethAddress,
TOKEN_ADJACENCY_GRAPH,
liquidityProviderAddress, liquidityProviderAddress,
); );
}; };
@ -548,7 +553,14 @@ describe('MarketOperationUtils tests', () => {
replaceSamplerOps({ replaceSamplerOps({
getSellQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => { getSellQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => {
actualNumSamples = amounts.length; actualNumSamples = amounts.length;
return DEFAULT_OPS.getSellQuotes(sources, makerToken, takerToken, amounts, wethAddress); return DEFAULT_OPS.getSellQuotes(
sources,
makerToken,
takerToken,
amounts,
wethAddress,
TOKEN_ADJACENCY_GRAPH,
);
}, },
}); });
await marketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, { await marketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, {
@ -563,7 +575,14 @@ describe('MarketOperationUtils tests', () => {
replaceSamplerOps({ replaceSamplerOps({
getSellQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => { getSellQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => {
sourcesPolled = sourcesPolled.concat(sources.slice()); sourcesPolled = sourcesPolled.concat(sources.slice());
return DEFAULT_OPS.getSellQuotes(sources, makerToken, takerToken, amounts, wethAddress); return DEFAULT_OPS.getSellQuotes(
sources,
makerToken,
takerToken,
amounts,
wethAddress,
TOKEN_ADJACENCY_GRAPH,
);
}, },
getTwoHopSellQuotes: (...args: any[]) => { getTwoHopSellQuotes: (...args: any[]) => {
sourcesPolled.push(ERC20BridgeSource.MultiHop); sourcesPolled.push(ERC20BridgeSource.MultiHop);
@ -647,7 +666,14 @@ describe('MarketOperationUtils tests', () => {
replaceSamplerOps({ replaceSamplerOps({
getSellQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => { getSellQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => {
sourcesPolled = sourcesPolled.concat(sources.slice()); sourcesPolled = sourcesPolled.concat(sources.slice());
return DEFAULT_OPS.getSellQuotes(sources, makerToken, takerToken, amounts, wethAddress); return DEFAULT_OPS.getSellQuotes(
sources,
makerToken,
takerToken,
amounts,
wethAddress,
TOKEN_ADJACENCY_GRAPH,
);
}, },
getTwoHopSellQuotes: (sources: ERC20BridgeSource[], ...args: any[]) => { getTwoHopSellQuotes: (sources: ERC20BridgeSource[], ...args: any[]) => {
if (sources.length !== 0) { if (sources.length !== 0) {
@ -686,7 +712,14 @@ describe('MarketOperationUtils tests', () => {
replaceSamplerOps({ replaceSamplerOps({
getSellQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => { getSellQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => {
sourcesPolled = sourcesPolled.concat(sources.slice()); sourcesPolled = sourcesPolled.concat(sources.slice());
return DEFAULT_OPS.getSellQuotes(sources, makerToken, takerToken, amounts, wethAddress); return DEFAULT_OPS.getSellQuotes(
sources,
makerToken,
takerToken,
amounts,
wethAddress,
TOKEN_ADJACENCY_GRAPH,
);
}, },
getTwoHopSellQuotes: (sources: ERC20BridgeSource[], ...args: any[]) => { getTwoHopSellQuotes: (sources: ERC20BridgeSource[], ...args: any[]) => {
if (sources.length !== 0) { if (sources.length !== 0) {
@ -1429,7 +1462,14 @@ describe('MarketOperationUtils tests', () => {
replaceSamplerOps({ replaceSamplerOps({
getBuyQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => { getBuyQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => {
actualNumSamples = amounts.length; actualNumSamples = amounts.length;
return DEFAULT_OPS.getBuyQuotes(sources, makerToken, takerToken, amounts, wethAddress); return DEFAULT_OPS.getBuyQuotes(
sources,
makerToken,
takerToken,
amounts,
wethAddress,
TOKEN_ADJACENCY_GRAPH,
);
}, },
}); });
await marketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, { await marketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, {
@ -1444,7 +1484,14 @@ describe('MarketOperationUtils tests', () => {
replaceSamplerOps({ replaceSamplerOps({
getBuyQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => { getBuyQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => {
sourcesPolled = sourcesPolled.concat(sources.slice()); sourcesPolled = sourcesPolled.concat(sources.slice());
return DEFAULT_OPS.getBuyQuotes(sources, makerToken, takerToken, amounts, wethAddress); return DEFAULT_OPS.getBuyQuotes(
sources,
makerToken,
takerToken,
amounts,
wethAddress,
TOKEN_ADJACENCY_GRAPH,
);
}, },
getTwoHopBuyQuotes: (sources: ERC20BridgeSource[], ..._args: any[]) => { getTwoHopBuyQuotes: (sources: ERC20BridgeSource[], ..._args: any[]) => {
if (sources.length !== 0) { if (sources.length !== 0) {
@ -1531,7 +1578,14 @@ describe('MarketOperationUtils tests', () => {
replaceSamplerOps({ replaceSamplerOps({
getBuyQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => { getBuyQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => {
sourcesPolled = sourcesPolled.concat(sources.slice()); sourcesPolled = sourcesPolled.concat(sources.slice());
return DEFAULT_OPS.getBuyQuotes(sources, makerToken, takerToken, amounts, wethAddress); return DEFAULT_OPS.getBuyQuotes(
sources,
makerToken,
takerToken,
amounts,
wethAddress,
TOKEN_ADJACENCY_GRAPH,
);
}, },
getTwoHopBuyQuotes: (sources: ERC20BridgeSource[], ..._args: any[]) => { getTwoHopBuyQuotes: (sources: ERC20BridgeSource[], ..._args: any[]) => {
if (sources.length !== 0) { if (sources.length !== 0) {
@ -1570,7 +1624,14 @@ describe('MarketOperationUtils tests', () => {
replaceSamplerOps({ replaceSamplerOps({
getBuyQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => { getBuyQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => {
sourcesPolled = sourcesPolled.concat(sources.slice()); sourcesPolled = sourcesPolled.concat(sources.slice());
return DEFAULT_OPS.getBuyQuotes(sources, makerToken, takerToken, amounts, wethAddress); return DEFAULT_OPS.getBuyQuotes(
sources,
makerToken,
takerToken,
amounts,
wethAddress,
TOKEN_ADJACENCY_GRAPH,
);
}, },
getTwoHopBuyQuotes: (sources: ERC20BridgeSource[], ..._args: any[]) => { getTwoHopBuyQuotes: (sources: ERC20BridgeSource[], ..._args: any[]) => {
if (sources.length !== 0) { if (sources.length !== 0) {