Refactor TokenAdjacency and TokenAdjacencyBuilder [TKR-324] (#517)
* Add a new TokenAdjacencyGraph implementation * Replace old TokenAdjacencyGraph with new implementation * Simplify token adjacency graph in constants.ts * Fix lint error * Update CHANGELOG.json
This commit is contained in:
@@ -13,7 +13,8 @@ import * as _ from 'lodash';
|
||||
|
||||
import { SignedOrder } from '../src/types';
|
||||
import { DexOrderSampler, getSampleAmounts } from '../src/utils/market_operation_utils/sampler';
|
||||
import { ERC20BridgeSource, TokenAdjacencyGraph } from '../src/utils/market_operation_utils/types';
|
||||
import { ERC20BridgeSource } from '../src/utils/market_operation_utils/types';
|
||||
import { TokenAdjacencyGraphBuilder } from '../src/utils/token_adjacency_graph';
|
||||
|
||||
import { MockSamplerContract } from './utils/mock_sampler_contract';
|
||||
import { generatePseudoRandomSalt } from './utils/utils';
|
||||
@@ -29,7 +30,7 @@ describe('DexSampler tests', () => {
|
||||
const wethAddress = getContractAddressesForChainOrThrow(CHAIN_ID).etherToken;
|
||||
const exchangeProxyAddress = getContractAddressesForChainOrThrow(CHAIN_ID).exchangeProxy;
|
||||
|
||||
const tokenAdjacencyGraph: TokenAdjacencyGraph = { default: [wethAddress] };
|
||||
const tokenAdjacencyGraph = new TokenAdjacencyGraphBuilder([wethAddress]).build();
|
||||
|
||||
describe('getSampleAmounts()', () => {
|
||||
const FILL_AMOUNT = getRandomInteger(1, 1e18);
|
||||
|
||||
@@ -15,7 +15,7 @@ import { Pool } from 'balancer-labs-sor-v1/dist/types';
|
||||
import * as _ from 'lodash';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
|
||||
import { MarketOperation, QuoteRequestor, RfqRequestOpts, SignedNativeOrder } from '../src';
|
||||
import { MarketOperation, QuoteRequestor, RfqRequestOpts, SignedNativeOrder, TokenAdjacencyGraph } from '../src';
|
||||
import { Integrator } from '../src/types';
|
||||
import { MarketOperationUtils } from '../src/utils/market_operation_utils/';
|
||||
import {
|
||||
@@ -39,7 +39,6 @@ import {
|
||||
MarketSideLiquidity,
|
||||
OptimizedMarketBridgeOrder,
|
||||
OptimizerResultWithReport,
|
||||
TokenAdjacencyGraph,
|
||||
} from '../src/utils/market_operation_utils/types';
|
||||
|
||||
const MAKER_TOKEN = randomAddress();
|
||||
@@ -57,7 +56,7 @@ const DEFAULT_EXCLUDED = SELL_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Mainnet].sources
|
||||
);
|
||||
const BUY_SOURCES = BUY_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Mainnet].sources;
|
||||
const SELL_SOURCES = SELL_SOURCE_FILTER_BY_CHAIN_ID[ChainId.Mainnet].sources;
|
||||
const TOKEN_ADJACENCY_GRAPH: TokenAdjacencyGraph = { default: [] };
|
||||
const TOKEN_ADJACENCY_GRAPH = TokenAdjacencyGraph.getEmptyGraph();
|
||||
|
||||
const SIGNATURE = { v: 1, r: NULL_BYTES, s: NULL_BYTES, signatureType: SignatureType.EthSign };
|
||||
const FOO_INTEGRATOR: Integrator = {
|
||||
|
||||
108
packages/asset-swapper/test/token_adjacency_graph_test.ts
Normal file
108
packages/asset-swapper/test/token_adjacency_graph_test.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import * as chai from 'chai';
|
||||
import 'mocha';
|
||||
|
||||
import { TokenAdjacencyGraphBuilder } from '../src/utils/token_adjacency_graph';
|
||||
|
||||
import { chaiSetup } from './utils/chai_setup';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
|
||||
describe('TokenAdjacencyGraphBuilder and TokenAdjacencyGraph', () => {
|
||||
describe('constructor', () => {
|
||||
it('sanitizes passed default tokens to lower case', async () => {
|
||||
const graph = new TokenAdjacencyGraphBuilder(['DEFAULT_1', 'DEFAULT_2']).build();
|
||||
|
||||
expect(graph.getAdjacentTokens('random_token')).to.deep.eq(['default_1', 'default_2']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('add', () => {
|
||||
it('adds a new token path to the graph', async () => {
|
||||
const graph = new TokenAdjacencyGraphBuilder(['default_1', 'default_2']).add('token_a', 'token_b').build();
|
||||
|
||||
expect(graph.getAdjacentTokens('token_a')).to.deep.eq(['default_1', 'default_2', 'token_b']);
|
||||
});
|
||||
|
||||
it('adds lower-cased token path to the graph', async () => {
|
||||
const graph = new TokenAdjacencyGraphBuilder(['default_1', 'default_2']).add('TOKEN_A', 'TOKEN_B').build();
|
||||
|
||||
expect(graph.getAdjacentTokens('token_a')).to.deep.eq(['default_1', 'default_2', 'token_b']);
|
||||
});
|
||||
|
||||
it('ignores an existing to token', async () => {
|
||||
const graph = new TokenAdjacencyGraphBuilder()
|
||||
.add('token_a', 'token_b')
|
||||
.add('token_a', 'token_b')
|
||||
.build();
|
||||
|
||||
expect(graph.getAdjacentTokens('token_a')).to.deep.eq(['token_b']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addBidirectional', () => {
|
||||
it('adds a bidirectional path to the graph', async () => {
|
||||
const graph = new TokenAdjacencyGraphBuilder(['default_1']).addBidirectional('token_a', 'token_b').build();
|
||||
|
||||
expect(graph.getAdjacentTokens('token_a')).to.deep.eq(['default_1', 'token_b']);
|
||||
expect(graph.getAdjacentTokens('token_b')).to.deep.eq(['default_1', 'token_a']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addCompleteSubgraph', () => {
|
||||
it('adds a complete subgraph to the graph', async () => {
|
||||
const graph = new TokenAdjacencyGraphBuilder(['default_1'])
|
||||
.addCompleteSubgraph(['token_a', 'token_b', 'token_c', 'token_d'])
|
||||
.build();
|
||||
|
||||
expect(graph.getAdjacentTokens('token_a')).to.deep.eq(['default_1', 'token_b', 'token_c', 'token_d']);
|
||||
expect(graph.getAdjacentTokens('token_b')).to.deep.eq(['default_1', 'token_a', 'token_c', 'token_d']);
|
||||
expect(graph.getAdjacentTokens('token_c')).to.deep.eq(['default_1', 'token_a', 'token_b', 'token_d']);
|
||||
expect(graph.getAdjacentTokens('token_d')).to.deep.eq(['default_1', 'token_a', 'token_b', 'token_c']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('tap', () => {
|
||||
it('applies callback correctly', async () => {
|
||||
const graph = new TokenAdjacencyGraphBuilder(['default_1'])
|
||||
.tap(g => {
|
||||
g.add('token_a', 'token_b');
|
||||
g.add('token_c', 'token_d');
|
||||
})
|
||||
.build();
|
||||
|
||||
expect(graph.getAdjacentTokens('token_a')).to.deep.eq(['default_1', 'token_b']);
|
||||
expect(graph.getAdjacentTokens('token_c')).to.deep.eq(['default_1', 'token_d']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getIntermediateTokens', () => {
|
||||
it('returns intermediate tokens without a duplicate ', async () => {
|
||||
const graph = new TokenAdjacencyGraphBuilder(['default_1'])
|
||||
.add('token_a', 'token_b')
|
||||
.add('token_c', 'token_b')
|
||||
.build();
|
||||
|
||||
expect(graph.getIntermediateTokens('token_a', 'token_c')).to.deep.eq(['default_1', 'token_b']);
|
||||
});
|
||||
|
||||
it('returns intermediate tokens after lower-casing taker and maker tokens', async () => {
|
||||
const graph = new TokenAdjacencyGraphBuilder(['default_1'])
|
||||
.add('token_a', 'token_b')
|
||||
.add('token_c', 'token_d')
|
||||
.build();
|
||||
|
||||
expect(graph.getIntermediateTokens('TOKEN_a', 'token_C')).to.deep.eq(['default_1', 'token_b', 'token_d']);
|
||||
});
|
||||
|
||||
it('returns intermediate tokens excluding taker token or maker token ', async () => {
|
||||
const graph = new TokenAdjacencyGraphBuilder(['default_1'])
|
||||
.addBidirectional('token_a', 'token_b')
|
||||
.addBidirectional('token_b', 'token_c')
|
||||
.addBidirectional('token_c', 'token_a')
|
||||
.build();
|
||||
|
||||
expect(graph.getIntermediateTokens('token_a', 'token_c')).to.deep.eq(['default_1', 'token_b']);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user