use jayson for JSONRPC
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import axios from 'axios';
|
||||
import { Client } from 'jayson';
|
||||
|
||||
import {
|
||||
Address,
|
||||
@@ -7,12 +7,10 @@ import {
|
||||
TokenResponse,
|
||||
} from './utils/market_operation_utils/sampler_types';
|
||||
|
||||
const SAMPLER_SERVICE_URL = '';
|
||||
|
||||
export interface SamplerServiceInterface {
|
||||
getSellLiquidityAsync(reqs: RpcLiquidityRequest[]): Promise<LiquidityResponse[]>;
|
||||
getBuyLiquidityAsync(reqs: RpcLiquidityRequest[]): Promise<LiquidityResponse[]>;
|
||||
getTokensAsync(tokenAddresses: Address[]): Promise<TokenResponse[]>;
|
||||
// getBuyLiquidityAsync(reqs: RpcLiquidityRequest[]): Promise<LiquidityResponse[]>;
|
||||
// getTokensAsync(tokenAddresses: Address[]): Promise<TokenResponse[]>;
|
||||
// getPrices(tokenPaths: Address[][]): Promise<bigint[]>;
|
||||
}
|
||||
|
||||
@@ -20,42 +18,41 @@ export class RpcSamplerClient implements SamplerServiceInterface {
|
||||
// tslint:disable:prefer-function-over-method
|
||||
public async getSellLiquidityAsync(reqs: RpcLiquidityRequest[]): Promise<LiquidityResponse[]> {
|
||||
try {
|
||||
return await axios.post(`${SAMPLER_SERVICE_URL}/get_sell_liquidity`, reqs, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
timeout: 1000,
|
||||
const client = Client.http({ port: 7002});
|
||||
const response = client.request(`get_sell_liquidity`, [reqs], (callback: any) => {
|
||||
console.log(callback);
|
||||
});
|
||||
return [];
|
||||
} catch (err) {
|
||||
throw new Error(`error with sampler service: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
// tslint:disable:prefer-function-over-method
|
||||
public async getBuyLiquidityAsync(reqs: RpcLiquidityRequest[]): Promise<LiquidityResponse[]> {
|
||||
try {
|
||||
return await axios.post(`${SAMPLER_SERVICE_URL}/get_buy_liquidity`, reqs, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
timeout: 1000,
|
||||
});
|
||||
} catch (err) {
|
||||
throw new Error(`error with sampler service: ${err}`);
|
||||
}
|
||||
}
|
||||
// public async getBuyLiquidityAsync(reqs: RpcLiquidityRequest[]): Promise<LiquidityResponse[]> {
|
||||
// try {
|
||||
// return await axios.post(`${SAMPLER_SERVICE_URL}/get_buy_liquidity`, reqs, {
|
||||
// headers: {
|
||||
// 'Content-Type': 'application/json',
|
||||
// },
|
||||
// timeout: 1000,
|
||||
// });
|
||||
// } catch (err) {
|
||||
// throw new Error(`error with sampler service: ${err}`);
|
||||
// }
|
||||
// }
|
||||
|
||||
// tslint:disable:prefer-function-over-method
|
||||
public async getTokensAsync(tokenAddresses: Address[]): Promise<TokenResponse[]> {
|
||||
try {
|
||||
return await axios.post(`${SAMPLER_SERVICE_URL}/get_tokens`, tokenAddresses, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
timeout: 1000,
|
||||
});
|
||||
} catch (err) {
|
||||
throw new Error(`error with sampler service: ${err}`);
|
||||
}
|
||||
}
|
||||
// // tslint:disable:prefer-function-over-method
|
||||
// public async getTokensAsync(tokenAddresses: Address[]): Promise<TokenResponse[]> {
|
||||
// try {
|
||||
// return await axios.post(`${SAMPLER_SERVICE_URL}/get_tokens`, tokenAddresses, {
|
||||
// headers: {
|
||||
// 'Content-Type': 'application/json',
|
||||
// },
|
||||
// timeout: 1000,
|
||||
// });
|
||||
// } catch (err) {
|
||||
// throw new Error(`error with sampler service: ${err}`);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
@@ -124,43 +124,43 @@ export class MarketOperationUtils {
|
||||
): Promise<MarketSideLiquidity> {
|
||||
const _opts = { ...DEFAULT_GET_MARKET_ORDERS_OPTS, ...opts };
|
||||
const { makerToken, takerToken } = nativeOrders[0].order;
|
||||
const sampleAmounts = getSampleAmounts(takerAmount, _opts.numSamples, _opts.sampleDistributionBase);
|
||||
// const sampleAmounts = getSampleAmounts(takerAmount, _opts.numSamples, _opts.sampleDistributionBase);
|
||||
|
||||
const requestFilters = new SourceFilters().exclude(_opts.excludedSources).include(_opts.includedSources);
|
||||
const quoteSourceFilters = this._sellSources.merge(requestFilters);
|
||||
const feeSourceFilters = this._feeSources.exclude(_opts.excludedFeeSources);
|
||||
|
||||
// Used to determine whether the tx origin is an EOA or a contract
|
||||
const txOrigin = (_opts.rfqt && _opts.rfqt.txOrigin) || NULL_ADDRESS;
|
||||
// const txOrigin = (_opts.rfqt && _opts.rfqt.txOrigin) || NULL_ADDRESS;
|
||||
|
||||
// Call the sampler contract.
|
||||
const samplerPromise = this._sampler.executeAsync(
|
||||
this._sampler.getTokenDecimals([makerToken, takerToken]),
|
||||
// Get native order fillable amounts.
|
||||
this._sampler.getLimitOrderFillableTakerAmounts(nativeOrders, this.contractAddresses.exchangeProxy),
|
||||
// Get ETH -> maker token price.
|
||||
this._sampler.getMedianSellRate(
|
||||
feeSourceFilters.sources,
|
||||
makerToken,
|
||||
this._nativeFeeToken,
|
||||
this._nativeFeeTokenAmount,
|
||||
),
|
||||
// Get ETH -> taker token price.
|
||||
this._sampler.getMedianSellRate(
|
||||
feeSourceFilters.sources,
|
||||
takerToken,
|
||||
this._nativeFeeToken,
|
||||
this._nativeFeeTokenAmount,
|
||||
),
|
||||
// this._sampler.getTokenDecimals([makerToken, takerToken]),
|
||||
// // Get native order fillable amounts.
|
||||
// this._sampler.getLimitOrderFillableTakerAmounts(nativeOrders, this.contractAddresses.exchangeProxy),
|
||||
// // Get ETH -> maker token price.
|
||||
// this._sampler.getMedianSellRate(
|
||||
// feeSourceFilters.sources,
|
||||
// makerToken,
|
||||
// this._nativeFeeToken,
|
||||
// this._nativeFeeTokenAmount,
|
||||
// ),
|
||||
// // Get ETH -> taker token price.
|
||||
// this._sampler.getMedianSellRate(
|
||||
// feeSourceFilters.sources,
|
||||
// takerToken,
|
||||
// this._nativeFeeToken,
|
||||
// this._nativeFeeTokenAmount,
|
||||
// ),
|
||||
// Get sell quotes for taker -> maker.
|
||||
this._sampler.getSellQuotes(quoteSourceFilters.sources, makerToken, takerToken, sampleAmounts),
|
||||
this._sampler.getTwoHopSellQuotes(
|
||||
quoteSourceFilters.isAllowed(ERC20BridgeSource.MultiHop) ? quoteSourceFilters.sources : [],
|
||||
makerToken,
|
||||
takerToken,
|
||||
takerAmount,
|
||||
),
|
||||
this._sampler.isAddressContract(txOrigin),
|
||||
this._sampler.getSellQuotesAsync(quoteSourceFilters.sources, makerToken, takerToken, takerAmount),
|
||||
// this._sampler.getTwoHopSellQuotes(
|
||||
// quoteSourceFilters.isAllowed(ERC20BridgeSource.MultiHop) ? quoteSourceFilters.sources : [],
|
||||
// makerToken,
|
||||
// takerToken,
|
||||
// takerAmount,
|
||||
// ),
|
||||
// this._sampler.isAddressContract(txOrigin),
|
||||
);
|
||||
|
||||
// Refresh the cached pools asynchronously if required
|
||||
@@ -168,46 +168,46 @@ export class MarketOperationUtils {
|
||||
|
||||
const [
|
||||
[
|
||||
tokenDecimals,
|
||||
orderFillableTakerAmounts,
|
||||
outputAmountPerEth,
|
||||
inputAmountPerEth,
|
||||
// tokenDecimals,
|
||||
// orderFillableTakerAmounts,
|
||||
// outputAmountPerEth,
|
||||
// inputAmountPerEth,
|
||||
dexQuotes,
|
||||
rawTwoHopQuotes,
|
||||
isTxOriginContract,
|
||||
// rawTwoHopQuotes,
|
||||
// isTxOriginContract,
|
||||
],
|
||||
] = await Promise.all([samplerPromise]);
|
||||
|
||||
// Filter out any invalid two hop quotes where we couldn't find a route
|
||||
const twoHopQuotes = rawTwoHopQuotes.filter(
|
||||
q => q && q.fillData && q.fillData.firstHopSource && q.fillData.secondHopSource,
|
||||
);
|
||||
// const twoHopQuotes = rawTwoHopQuotes.filter(
|
||||
// q => q && q.fillData && q.fillData.firstHopSource && q.fillData.secondHopSource,
|
||||
// );
|
||||
|
||||
const [makerTokenDecimals, takerTokenDecimals] = tokenDecimals;
|
||||
// const [makerTokenDecimals, takerTokenDecimals] = tokenDecimals;
|
||||
|
||||
const isRfqSupported = !!(_opts.rfqt && !isTxOriginContract);
|
||||
const limitOrdersWithFillableAmounts = nativeOrders.map((order, i) => ({
|
||||
...order,
|
||||
...getNativeAdjustedFillableAmountsFromTakerAmount(order, orderFillableTakerAmounts[i]),
|
||||
}));
|
||||
// const isRfqSupported = !!(_opts.rfqt && !isTxOriginContract);
|
||||
// const limitOrdersWithFillableAmounts = nativeOrders.map((order, i) => ({
|
||||
// ...order,
|
||||
// ...getNativeAdjustedFillableAmountsFromTakerAmount(order, orderFillableTakerAmounts[i]),
|
||||
// }));
|
||||
|
||||
return {
|
||||
side: MarketOperation.Sell,
|
||||
inputAmount: takerAmount,
|
||||
inputToken: takerToken,
|
||||
outputToken: makerToken,
|
||||
outputAmountPerEth,
|
||||
inputAmountPerEth,
|
||||
outputAmountPerEth: new BigNumber(1),
|
||||
inputAmountPerEth: new BigNumber(1),
|
||||
quoteSourceFilters,
|
||||
makerTokenDecimals: makerTokenDecimals.toNumber(),
|
||||
takerTokenDecimals: takerTokenDecimals.toNumber(),
|
||||
makerTokenDecimals: 18,
|
||||
takerTokenDecimals: 18,
|
||||
quotes: {
|
||||
nativeOrders: limitOrdersWithFillableAmounts,
|
||||
nativeOrders: [],
|
||||
rfqtIndicativeQuotes: [],
|
||||
twoHopQuotes,
|
||||
twoHopQuotes: [],
|
||||
dexQuotes,
|
||||
},
|
||||
isRfqSupported,
|
||||
isRfqSupported: true,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -137,7 +137,8 @@ export class SamplerOperations {
|
||||
}
|
||||
|
||||
public async getTokenDecimalsAsync(tokens: Address[]): Promise<number[]> {
|
||||
return (await this.rpcSamplerClient.getTokensAsync(tokens)).map(t => t.decimals);
|
||||
return [];
|
||||
// return (await this.rpcSamplerClient.getTokensAsync(tokens)).map(t => t.decimals);
|
||||
}
|
||||
|
||||
public async getSellQuotesAsync(
|
||||
@@ -155,19 +156,20 @@ export class SamplerOperations {
|
||||
};
|
||||
});
|
||||
const rpcLiquidityResponse = await this.rpcSamplerClient.getSellLiquidityAsync(rpcLiquidityRequests);
|
||||
const dexQuotes: Array<Array<DexSample<FillData>>> = rpcLiquidityResponse.map((response, i) => {
|
||||
const dexSample: Array<DexSample<FillData>> = response.liquidityCurve.map((point, j) => {
|
||||
const fillData: DexSample = {
|
||||
source: response.source,
|
||||
fillData: point.encodedFillData,
|
||||
input: point.sellAmount,
|
||||
output: point.buyAmount,
|
||||
};
|
||||
return fillData;
|
||||
});
|
||||
return dexSample;
|
||||
});
|
||||
return dexQuotes;
|
||||
// const dexQuotes: Array<Array<DexSample<FillData>>> = rpcLiquidityResponse.map((response, i) => {
|
||||
// const dexSample: Array<DexSample<FillData>> = response.liquidityCurve.map((point, j) => {
|
||||
// const fillData: DexSample = {
|
||||
// source: response.source,
|
||||
// fillData: point.encodedFillData,
|
||||
// input: point.sellAmount,
|
||||
// output: point.buyAmount,
|
||||
// };
|
||||
// return fillData;
|
||||
// });
|
||||
// return dexSample;
|
||||
// });
|
||||
return [];
|
||||
// return dexQuotes;
|
||||
}
|
||||
|
||||
public async getBuyQuotesAsync(
|
||||
@@ -176,28 +178,29 @@ export class SamplerOperations {
|
||||
takerToken: string,
|
||||
takerAmount: BigNumber,
|
||||
): Promise<Array<Array<DexSample<FillData>>>> {
|
||||
const rpcLiquidityRequests: RpcLiquidityRequest[] = sources.map(source => {
|
||||
return {
|
||||
tokenPath: [makerToken, takerToken],
|
||||
inputAmount: takerAmount.toString(),
|
||||
source,
|
||||
demand: true,
|
||||
};
|
||||
});
|
||||
const rpcLiquidityResponse = await this.rpcSamplerClient.getBuyLiquidityAsync(rpcLiquidityRequests);
|
||||
const dexQuotes: Array<Array<DexSample<FillData>>> = rpcLiquidityResponse.map((response, i) => {
|
||||
const dexSample: Array<DexSample<FillData>> = response.liquidityCurve.map((point, j) => {
|
||||
const fillData: DexSample = {
|
||||
source: sources[i],
|
||||
fillData: point.encodedFillData,
|
||||
input: point.sellAmount,
|
||||
output: point.buyAmount,
|
||||
};
|
||||
return fillData;
|
||||
});
|
||||
return dexSample;
|
||||
});
|
||||
return dexQuotes;
|
||||
return [];
|
||||
// const rpcLiquidityRequests: RpcLiquidityRequest[] = sources.map(source => {
|
||||
// return {
|
||||
// tokenPath: [makerToken, takerToken],
|
||||
// inputAmount: takerAmount.toString(),
|
||||
// source,
|
||||
// demand: true,
|
||||
// };
|
||||
// });
|
||||
// const rpcLiquidityResponse = await this.rpcSamplerClient.getBuyLiquidityAsync(rpcLiquidityRequests);
|
||||
// const dexQuotes: Array<Array<DexSample<FillData>>> = rpcLiquidityResponse.map((response, i) => {
|
||||
// const dexSample: Array<DexSample<FillData>> = response.liquidityCurve.map((point, j) => {
|
||||
// const fillData: DexSample = {
|
||||
// source: sources[i],
|
||||
// fillData: point.encodedFillData,
|
||||
// input: point.sellAmount,
|
||||
// output: point.buyAmount,
|
||||
// };
|
||||
// return fillData;
|
||||
// });
|
||||
// return dexSample;
|
||||
// });
|
||||
// return dexQuotes;
|
||||
}
|
||||
|
||||
public async getMedianSellRateAsync(
|
||||
@@ -206,19 +209,20 @@ export class SamplerOperations {
|
||||
takerToken: string,
|
||||
takerFillAmount: BigNumber,
|
||||
): Promise<BigNumber> {
|
||||
const samples = await this.getSellQuotesAsync(sources, makerToken, takerToken, takerFillAmount);
|
||||
if (samples.length === 0) {
|
||||
return ZERO_AMOUNT;
|
||||
}
|
||||
const flatSortedSamples = samples
|
||||
.reduce((acc, v) => acc.concat(...v))
|
||||
.filter(v => !v.output.isZero())
|
||||
.sort((a, b) => a.output.comparedTo(b.output));
|
||||
if (flatSortedSamples.length === 0) {
|
||||
return ZERO_AMOUNT;
|
||||
}
|
||||
const medianSample = flatSortedSamples[Math.floor(flatSortedSamples.length / 2)];
|
||||
return medianSample.output.div(takerFillAmount);
|
||||
return new BigNumber(0);
|
||||
// const samples = await this.getSellQuotesAsync(sources, makerToken, takerToken, takerFillAmount);
|
||||
// if (samples.length === 0) {
|
||||
// return ZERO_AMOUNT;
|
||||
// }
|
||||
// const flatSortedSamples = samples
|
||||
// .reduce((acc, v) => acc.concat(...v))
|
||||
// .filter(v => !v.output.isZero())
|
||||
// .sort((a, b) => a.output.comparedTo(b.output));
|
||||
// if (flatSortedSamples.length === 0) {
|
||||
// return ZERO_AMOUNT;
|
||||
// }
|
||||
// const medianSample = flatSortedSamples[Math.floor(flatSortedSamples.length / 2)];
|
||||
// return medianSample.output.div(takerFillAmount);
|
||||
}
|
||||
|
||||
// Legacy
|
||||
|
||||
@@ -20,7 +20,7 @@ export interface LiquidityCurvePoint {
|
||||
|
||||
export interface LiquidityResponse {
|
||||
source: ERC20BridgeSource; //LiquiditySource;
|
||||
liquidityCurve: LiquidityCurvePoint[];
|
||||
liquidityCurve: LiquidityCurvePoint[][];
|
||||
}
|
||||
|
||||
export interface Market {
|
||||
|
||||
@@ -1,579 +0,0 @@
|
||||
import { ChainId, getContractAddressesForChainOrThrow } from '@0x/contract-addresses';
|
||||
import {
|
||||
constants,
|
||||
expect,
|
||||
getRandomFloat,
|
||||
getRandomInteger,
|
||||
randomAddress,
|
||||
toBaseUnitAmount,
|
||||
} from '@0x/contracts-test-utils';
|
||||
import { FillQuoteTransformerOrderType, LimitOrderFields, SignatureType } from '@0x/protocol-utils';
|
||||
import { BigNumber, hexUtils, NULL_ADDRESS } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
import { RpcSamplerClient } from '../src/rpc_sampler_client';
|
||||
|
||||
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 { MockSamplerContract } from './utils/mock_sampler_contract';
|
||||
import { generatePseudoRandomSalt } from './utils/utils';
|
||||
|
||||
const CHAIN_ID = 1;
|
||||
const EMPTY_BYTES32 = '0x0000000000000000000000000000000000000000000000000000000000000000';
|
||||
// tslint:disable: custom-no-magic-numbers
|
||||
describe('DexSampler tests', () => {
|
||||
const MAKER_TOKEN = randomAddress();
|
||||
const TAKER_TOKEN = randomAddress();
|
||||
const chainId = ChainId.Mainnet;
|
||||
|
||||
const wethAddress = getContractAddressesForChainOrThrow(CHAIN_ID).etherToken;
|
||||
const exchangeProxyAddress = getContractAddressesForChainOrThrow(CHAIN_ID).exchangeProxy;
|
||||
|
||||
const tokenAdjacencyGraph: TokenAdjacencyGraph = { default: [wethAddress] };
|
||||
|
||||
describe('getSampleAmounts()', () => {
|
||||
const FILL_AMOUNT = getRandomInteger(1, 1e18);
|
||||
const NUM_SAMPLES = 16;
|
||||
|
||||
it('generates the correct number of amounts', () => {
|
||||
const amounts = getSampleAmounts(FILL_AMOUNT, NUM_SAMPLES);
|
||||
expect(amounts).to.be.length(NUM_SAMPLES);
|
||||
});
|
||||
|
||||
it('first amount is nonzero', () => {
|
||||
const amounts = getSampleAmounts(FILL_AMOUNT, NUM_SAMPLES);
|
||||
expect(amounts[0]).to.not.bignumber.eq(0);
|
||||
});
|
||||
|
||||
it('last amount is the fill amount', () => {
|
||||
const amounts = getSampleAmounts(FILL_AMOUNT, NUM_SAMPLES);
|
||||
expect(amounts[NUM_SAMPLES - 1]).to.bignumber.eq(FILL_AMOUNT);
|
||||
});
|
||||
|
||||
it('can generate a single amount', () => {
|
||||
const amounts = getSampleAmounts(FILL_AMOUNT, 1);
|
||||
expect(amounts).to.be.length(1);
|
||||
expect(amounts[0]).to.bignumber.eq(FILL_AMOUNT);
|
||||
});
|
||||
|
||||
it('generates ascending amounts', () => {
|
||||
const amounts = getSampleAmounts(FILL_AMOUNT, NUM_SAMPLES);
|
||||
for (const i of _.times(NUM_SAMPLES).slice(1)) {
|
||||
const prev = amounts[i - 1];
|
||||
const amount = amounts[i];
|
||||
expect(prev).to.bignumber.lt(amount);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function createOrder(overrides?: Partial<LimitOrderFields>): SignedOrder<LimitOrderFields> {
|
||||
const o: SignedOrder<LimitOrderFields> = {
|
||||
order: {
|
||||
salt: generatePseudoRandomSalt(),
|
||||
expiry: getRandomInteger(0, 2 ** 64),
|
||||
makerToken: MAKER_TOKEN,
|
||||
takerToken: TAKER_TOKEN,
|
||||
makerAmount: getRandomInteger(1, 1e18),
|
||||
takerAmount: getRandomInteger(1, 1e18),
|
||||
takerTokenFeeAmount: constants.ZERO_AMOUNT,
|
||||
chainId: CHAIN_ID,
|
||||
pool: EMPTY_BYTES32,
|
||||
feeRecipient: NULL_ADDRESS,
|
||||
sender: NULL_ADDRESS,
|
||||
maker: NULL_ADDRESS,
|
||||
taker: NULL_ADDRESS,
|
||||
verifyingContract: exchangeProxyAddress,
|
||||
...overrides,
|
||||
},
|
||||
signature: { v: 1, r: hexUtils.random(), s: hexUtils.random(), signatureType: SignatureType.EthSign },
|
||||
type: FillQuoteTransformerOrderType.Limit,
|
||||
};
|
||||
return o;
|
||||
}
|
||||
const ORDERS = _.times(4, () => createOrder());
|
||||
const SIMPLE_ORDERS = ORDERS.map(o => _.omit(o.order, ['chainId', 'verifyingContract']));
|
||||
|
||||
describe('operations', () => {
|
||||
it('getLimitOrderFillableMakerAssetAmounts()', async () => {
|
||||
const expectedFillableAmounts = ORDERS.map(() => getRandomInteger(0, 100e18));
|
||||
const sampler = new MockSamplerContract({
|
||||
getLimitOrderFillableMakerAssetAmounts: (orders, signatures) => {
|
||||
expect(orders).to.deep.eq(SIMPLE_ORDERS);
|
||||
expect(signatures).to.deep.eq(ORDERS.map(o => o.signature));
|
||||
return expectedFillableAmounts;
|
||||
},
|
||||
});
|
||||
const dexOrderSampler = new DexOrderSampler(
|
||||
chainId,
|
||||
new RpcSamplerClient(),
|
||||
sampler,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
async () => undefined,
|
||||
);
|
||||
const [fillableAmounts] = await dexOrderSampler.executeAsync(
|
||||
dexOrderSampler.getLimitOrderFillableMakerAmounts(ORDERS, exchangeProxyAddress),
|
||||
);
|
||||
expect(fillableAmounts).to.deep.eq(expectedFillableAmounts);
|
||||
});
|
||||
|
||||
it('getLimitOrderFillableTakerAssetAmounts()', async () => {
|
||||
const expectedFillableAmounts = ORDERS.map(() => getRandomInteger(0, 100e18));
|
||||
const sampler = new MockSamplerContract({
|
||||
getLimitOrderFillableTakerAssetAmounts: (orders, signatures) => {
|
||||
expect(orders).to.deep.eq(SIMPLE_ORDERS);
|
||||
expect(signatures).to.deep.eq(ORDERS.map(o => o.signature));
|
||||
return expectedFillableAmounts;
|
||||
},
|
||||
});
|
||||
const dexOrderSampler = new DexOrderSampler(
|
||||
chainId,
|
||||
new RpcSamplerClient(),
|
||||
sampler,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
async () => undefined,
|
||||
);
|
||||
const [fillableAmounts] = await dexOrderSampler.executeAsync(
|
||||
dexOrderSampler.getLimitOrderFillableTakerAmounts(ORDERS, exchangeProxyAddress),
|
||||
);
|
||||
expect(fillableAmounts).to.deep.eq(expectedFillableAmounts);
|
||||
});
|
||||
|
||||
it('getKyberSellQuotes()', async () => {
|
||||
const expectedTakerToken = randomAddress();
|
||||
const expectedMakerToken = randomAddress();
|
||||
const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10);
|
||||
const expectedMakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10);
|
||||
const sampler = new MockSamplerContract({
|
||||
sampleSellsFromKyberNetwork: (_reserveOffset, takerToken, makerToken, fillAmounts) => {
|
||||
expect(takerToken).to.eq(expectedTakerToken);
|
||||
expect(makerToken).to.eq(expectedMakerToken);
|
||||
expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts);
|
||||
return ['0x', '0x', expectedMakerFillAmounts];
|
||||
},
|
||||
});
|
||||
const dexOrderSampler = new DexOrderSampler(
|
||||
chainId,
|
||||
new RpcSamplerClient(),
|
||||
sampler,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
async () => undefined,
|
||||
);
|
||||
const [fillableAmounts] = await dexOrderSampler.executeAsync(
|
||||
dexOrderSampler.getKyberSellQuotes(
|
||||
{ hintHandler: randomAddress(), networkProxy: randomAddress(), weth: randomAddress() },
|
||||
new BigNumber(0),
|
||||
expectedMakerToken,
|
||||
expectedTakerToken,
|
||||
expectedTakerFillAmounts,
|
||||
),
|
||||
);
|
||||
expect(fillableAmounts).to.deep.eq(expectedMakerFillAmounts);
|
||||
});
|
||||
|
||||
it('getLiquidityProviderSellQuotes()', async () => {
|
||||
const expectedMakerToken = randomAddress();
|
||||
const expectedTakerToken = randomAddress();
|
||||
const poolAddress = randomAddress();
|
||||
const gasCost = 123;
|
||||
const sampler = new MockSamplerContract({
|
||||
sampleSellsFromLiquidityProvider: (providerAddress, takerToken, makerToken, _fillAmounts) => {
|
||||
expect(providerAddress).to.eq(poolAddress);
|
||||
expect(takerToken).to.eq(expectedTakerToken);
|
||||
expect(makerToken).to.eq(expectedMakerToken);
|
||||
return [toBaseUnitAmount(1001)];
|
||||
},
|
||||
});
|
||||
const dexOrderSampler = new DexOrderSampler(
|
||||
chainId,
|
||||
new RpcSamplerClient(),
|
||||
sampler,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
[poolAddress]: { tokens: [expectedMakerToken, expectedTakerToken], gasCost },
|
||||
},
|
||||
async () => undefined,
|
||||
);
|
||||
const [result] = await dexOrderSampler.executeAsync(
|
||||
dexOrderSampler.getSellQuotes(
|
||||
[ERC20BridgeSource.LiquidityProvider],
|
||||
expectedMakerToken,
|
||||
expectedTakerToken,
|
||||
[toBaseUnitAmount(1000)],
|
||||
),
|
||||
);
|
||||
expect(result).to.deep.equal([
|
||||
[
|
||||
{
|
||||
source: 'LiquidityProvider',
|
||||
output: toBaseUnitAmount(1001),
|
||||
input: toBaseUnitAmount(1000),
|
||||
fillData: { poolAddress, gasCost },
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
it('getLiquidityProviderBuyQuotes()', async () => {
|
||||
const expectedMakerToken = randomAddress();
|
||||
const expectedTakerToken = randomAddress();
|
||||
const poolAddress = randomAddress();
|
||||
const gasCost = 321;
|
||||
const sampler = new MockSamplerContract({
|
||||
sampleBuysFromLiquidityProvider: (providerAddress, takerToken, makerToken, _fillAmounts) => {
|
||||
expect(providerAddress).to.eq(poolAddress);
|
||||
expect(takerToken).to.eq(expectedTakerToken);
|
||||
expect(makerToken).to.eq(expectedMakerToken);
|
||||
return [toBaseUnitAmount(999)];
|
||||
},
|
||||
});
|
||||
const dexOrderSampler = new DexOrderSampler(
|
||||
chainId,
|
||||
new RpcSamplerClient(),
|
||||
sampler,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
[poolAddress]: { tokens: [expectedMakerToken, expectedTakerToken], gasCost },
|
||||
},
|
||||
async () => undefined,
|
||||
);
|
||||
const [result] = await dexOrderSampler.executeAsync(
|
||||
dexOrderSampler.getBuyQuotes(
|
||||
[ERC20BridgeSource.LiquidityProvider],
|
||||
expectedMakerToken,
|
||||
expectedTakerToken,
|
||||
[toBaseUnitAmount(1000)],
|
||||
),
|
||||
);
|
||||
expect(result).to.deep.equal([
|
||||
[
|
||||
{
|
||||
source: 'LiquidityProvider',
|
||||
output: toBaseUnitAmount(999),
|
||||
input: toBaseUnitAmount(1000),
|
||||
fillData: { poolAddress, gasCost },
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
it('getUniswapSellQuotes()', async () => {
|
||||
const expectedTakerToken = randomAddress();
|
||||
const expectedMakerToken = randomAddress();
|
||||
const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10);
|
||||
const expectedMakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10);
|
||||
const sampler = new MockSamplerContract({
|
||||
sampleSellsFromUniswap: (_router, takerToken, makerToken, fillAmounts) => {
|
||||
expect(takerToken).to.eq(expectedTakerToken);
|
||||
expect(makerToken).to.eq(expectedMakerToken);
|
||||
expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts);
|
||||
return expectedMakerFillAmounts;
|
||||
},
|
||||
});
|
||||
const dexOrderSampler = new DexOrderSampler(
|
||||
chainId,
|
||||
new RpcSamplerClient(),
|
||||
sampler,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
async () => undefined,
|
||||
);
|
||||
const [fillableAmounts] = await dexOrderSampler.executeAsync(
|
||||
dexOrderSampler.getUniswapSellQuotes(
|
||||
randomAddress(),
|
||||
expectedMakerToken,
|
||||
expectedTakerToken,
|
||||
expectedTakerFillAmounts,
|
||||
),
|
||||
);
|
||||
expect(fillableAmounts).to.deep.eq(expectedMakerFillAmounts);
|
||||
});
|
||||
|
||||
it('getUniswapV2SellQuotes()', async () => {
|
||||
const expectedTakerToken = randomAddress();
|
||||
const expectedMakerToken = randomAddress();
|
||||
const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10);
|
||||
const expectedMakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10);
|
||||
const sampler = new MockSamplerContract({
|
||||
sampleSellsFromUniswapV2: (_router, path, fillAmounts) => {
|
||||
expect(path).to.deep.eq([expectedMakerToken, expectedTakerToken]);
|
||||
expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts);
|
||||
return expectedMakerFillAmounts;
|
||||
},
|
||||
});
|
||||
const dexOrderSampler = new DexOrderSampler(
|
||||
chainId,
|
||||
new RpcSamplerClient(),
|
||||
sampler,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
async () => undefined,
|
||||
);
|
||||
const [fillableAmounts] = await dexOrderSampler.executeAsync(
|
||||
dexOrderSampler.getUniswapV2SellQuotes(
|
||||
NULL_ADDRESS,
|
||||
[expectedMakerToken, expectedTakerToken],
|
||||
expectedTakerFillAmounts,
|
||||
),
|
||||
);
|
||||
expect(fillableAmounts).to.deep.eq(expectedMakerFillAmounts);
|
||||
});
|
||||
|
||||
it('getUniswapBuyQuotes()', async () => {
|
||||
const expectedTakerToken = randomAddress();
|
||||
const expectedMakerToken = randomAddress();
|
||||
const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10);
|
||||
const expectedMakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 10);
|
||||
const sampler = new MockSamplerContract({
|
||||
sampleBuysFromUniswap: (_router, takerToken, makerToken, fillAmounts) => {
|
||||
expect(takerToken).to.eq(expectedTakerToken);
|
||||
expect(makerToken).to.eq(expectedMakerToken);
|
||||
expect(fillAmounts).to.deep.eq(expectedMakerFillAmounts);
|
||||
return expectedTakerFillAmounts;
|
||||
},
|
||||
});
|
||||
const dexOrderSampler = new DexOrderSampler(
|
||||
chainId,
|
||||
new RpcSamplerClient(),
|
||||
sampler,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
async () => undefined,
|
||||
);
|
||||
const [fillableAmounts] = await dexOrderSampler.executeAsync(
|
||||
dexOrderSampler.getUniswapBuyQuotes(
|
||||
randomAddress(),
|
||||
expectedMakerToken,
|
||||
expectedTakerToken,
|
||||
expectedMakerFillAmounts,
|
||||
),
|
||||
);
|
||||
expect(fillableAmounts).to.deep.eq(expectedTakerFillAmounts);
|
||||
});
|
||||
|
||||
interface RatesBySource {
|
||||
[src: string]: BigNumber;
|
||||
}
|
||||
|
||||
it('getSellQuotes()', async () => {
|
||||
const expectedTakerToken = randomAddress();
|
||||
const expectedMakerToken = randomAddress();
|
||||
const sources = [ERC20BridgeSource.Uniswap, ERC20BridgeSource.UniswapV2];
|
||||
const ratesBySource: RatesBySource = {
|
||||
[ERC20BridgeSource.Kyber]: getRandomFloat(0, 100),
|
||||
[ERC20BridgeSource.Uniswap]: getRandomFloat(0, 100),
|
||||
[ERC20BridgeSource.UniswapV2]: getRandomFloat(0, 100),
|
||||
};
|
||||
const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 3);
|
||||
let uniswapRouter: string;
|
||||
let uniswapV2Router: string;
|
||||
const sampler = new MockSamplerContract({
|
||||
sampleSellsFromUniswap: (router, takerToken, makerToken, fillAmounts) => {
|
||||
uniswapRouter = router;
|
||||
expect(takerToken).to.eq(expectedTakerToken);
|
||||
expect(makerToken).to.eq(expectedMakerToken);
|
||||
expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts);
|
||||
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.Uniswap]).integerValue());
|
||||
},
|
||||
sampleSellsFromUniswapV2: (router, path, fillAmounts) => {
|
||||
uniswapV2Router = router;
|
||||
if (path.length === 2) {
|
||||
expect(path).to.deep.eq([expectedTakerToken, expectedMakerToken]);
|
||||
} else if (path.length === 3) {
|
||||
expect(path).to.deep.eq([expectedTakerToken, wethAddress, expectedMakerToken]);
|
||||
} else {
|
||||
expect(path).to.have.lengthOf.within(2, 3);
|
||||
}
|
||||
expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts);
|
||||
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.UniswapV2]).integerValue());
|
||||
},
|
||||
});
|
||||
const dexOrderSampler = new DexOrderSampler(
|
||||
chainId,
|
||||
new RpcSamplerClient(),
|
||||
sampler,
|
||||
undefined,
|
||||
undefined,
|
||||
tokenAdjacencyGraph,
|
||||
undefined,
|
||||
async () => undefined,
|
||||
);
|
||||
const [quotes] = await dexOrderSampler.executeAsync(
|
||||
dexOrderSampler.getSellQuotes(
|
||||
sources,
|
||||
expectedMakerToken,
|
||||
expectedTakerToken,
|
||||
expectedTakerFillAmounts,
|
||||
),
|
||||
);
|
||||
const expectedQuotes = sources.map(s =>
|
||||
expectedTakerFillAmounts.map(a => ({
|
||||
source: s,
|
||||
input: a,
|
||||
output: a.times(ratesBySource[s]).integerValue(),
|
||||
fillData: (() => {
|
||||
if (s === ERC20BridgeSource.UniswapV2) {
|
||||
return {
|
||||
router: uniswapV2Router,
|
||||
tokenAddressPath: [expectedTakerToken, expectedMakerToken],
|
||||
};
|
||||
}
|
||||
// TODO jacob pass through
|
||||
if (s === ERC20BridgeSource.Uniswap) {
|
||||
return { router: uniswapRouter };
|
||||
}
|
||||
return {};
|
||||
})(),
|
||||
})),
|
||||
);
|
||||
const uniswapV2ETHQuotes = [
|
||||
expectedTakerFillAmounts.map(a => ({
|
||||
source: ERC20BridgeSource.UniswapV2,
|
||||
input: a,
|
||||
output: a.times(ratesBySource[ERC20BridgeSource.UniswapV2]).integerValue(),
|
||||
fillData: {
|
||||
router: uniswapV2Router,
|
||||
tokenAddressPath: [expectedTakerToken, wethAddress, expectedMakerToken],
|
||||
},
|
||||
})),
|
||||
];
|
||||
// extra quote for Uniswap V2, which provides a direct quote (tokenA -> tokenB) AND an ETH quote (tokenA -> ETH -> tokenB)
|
||||
const additionalSourceCount = 1;
|
||||
expect(quotes).to.have.lengthOf(sources.length + additionalSourceCount);
|
||||
expect(quotes).to.deep.eq(expectedQuotes.concat(uniswapV2ETHQuotes));
|
||||
});
|
||||
it('getBuyQuotes()', async () => {
|
||||
const expectedTakerToken = randomAddress();
|
||||
const expectedMakerToken = randomAddress();
|
||||
const sources = [ERC20BridgeSource.Uniswap, ERC20BridgeSource.UniswapV2];
|
||||
const ratesBySource: RatesBySource = {
|
||||
[ERC20BridgeSource.Uniswap]: getRandomFloat(0, 100),
|
||||
[ERC20BridgeSource.UniswapV2]: getRandomFloat(0, 100),
|
||||
};
|
||||
const expectedMakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 3);
|
||||
let uniswapRouter: string;
|
||||
let uniswapV2Router: string;
|
||||
const sampler = new MockSamplerContract({
|
||||
sampleBuysFromUniswap: (router, takerToken, makerToken, fillAmounts) => {
|
||||
uniswapRouter = router;
|
||||
expect(takerToken).to.eq(expectedTakerToken);
|
||||
expect(makerToken).to.eq(expectedMakerToken);
|
||||
expect(fillAmounts).to.deep.eq(expectedMakerFillAmounts);
|
||||
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.Uniswap]).integerValue());
|
||||
},
|
||||
sampleBuysFromUniswapV2: (router, path, fillAmounts) => {
|
||||
uniswapV2Router = router;
|
||||
if (path.length === 2) {
|
||||
expect(path).to.deep.eq([expectedTakerToken, expectedMakerToken]);
|
||||
} else if (path.length === 3) {
|
||||
expect(path).to.deep.eq([expectedTakerToken, wethAddress, expectedMakerToken]);
|
||||
} else {
|
||||
expect(path).to.have.lengthOf.within(2, 3);
|
||||
}
|
||||
expect(fillAmounts).to.deep.eq(expectedMakerFillAmounts);
|
||||
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.UniswapV2]).integerValue());
|
||||
},
|
||||
});
|
||||
const dexOrderSampler = new DexOrderSampler(
|
||||
chainId,
|
||||
new RpcSamplerClient(),
|
||||
sampler,
|
||||
undefined,
|
||||
undefined,
|
||||
tokenAdjacencyGraph,
|
||||
undefined,
|
||||
async () => undefined,
|
||||
);
|
||||
const [quotes] = await dexOrderSampler.executeAsync(
|
||||
dexOrderSampler.getBuyQuotes(sources, expectedMakerToken, expectedTakerToken, expectedMakerFillAmounts),
|
||||
);
|
||||
const expectedQuotes = sources.map(s =>
|
||||
expectedMakerFillAmounts.map(a => ({
|
||||
source: s,
|
||||
input: a,
|
||||
output: a.times(ratesBySource[s]).integerValue(),
|
||||
fillData: (() => {
|
||||
if (s === ERC20BridgeSource.UniswapV2) {
|
||||
return {
|
||||
router: uniswapV2Router,
|
||||
tokenAddressPath: [expectedTakerToken, expectedMakerToken],
|
||||
};
|
||||
}
|
||||
if (s === ERC20BridgeSource.Uniswap) {
|
||||
return { router: uniswapRouter };
|
||||
}
|
||||
return {};
|
||||
})(),
|
||||
})),
|
||||
);
|
||||
const uniswapV2ETHQuotes = [
|
||||
expectedMakerFillAmounts.map(a => ({
|
||||
source: ERC20BridgeSource.UniswapV2,
|
||||
input: a,
|
||||
output: a.times(ratesBySource[ERC20BridgeSource.UniswapV2]).integerValue(),
|
||||
fillData: {
|
||||
router: uniswapV2Router,
|
||||
tokenAddressPath: [expectedTakerToken, wethAddress, expectedMakerToken],
|
||||
},
|
||||
})),
|
||||
];
|
||||
// extra quote for Uniswap V2, which provides a direct quote (tokenA -> tokenB) AND an ETH quote (tokenA -> ETH -> tokenB)
|
||||
expect(quotes).to.have.lengthOf(sources.length + 1);
|
||||
expect(quotes).to.deep.eq(expectedQuotes.concat(uniswapV2ETHQuotes));
|
||||
});
|
||||
describe('batched operations', () => {
|
||||
it('getLimitOrderFillableMakerAssetAmounts(), getLimitOrderFillableTakerAssetAmounts()', async () => {
|
||||
const expectedFillableTakerAmounts = ORDERS.map(() => getRandomInteger(0, 100e18));
|
||||
const expectedFillableMakerAmounts = ORDERS.map(() => getRandomInteger(0, 100e18));
|
||||
const sampler = new MockSamplerContract({
|
||||
getLimitOrderFillableMakerAssetAmounts: (orders, signatures) => {
|
||||
expect(orders).to.deep.eq(SIMPLE_ORDERS);
|
||||
expect(signatures).to.deep.eq(ORDERS.map(o => o.signature));
|
||||
return expectedFillableMakerAmounts;
|
||||
},
|
||||
getLimitOrderFillableTakerAssetAmounts: (orders, signatures) => {
|
||||
expect(orders).to.deep.eq(SIMPLE_ORDERS);
|
||||
expect(signatures).to.deep.eq(ORDERS.map(o => o.signature));
|
||||
return expectedFillableTakerAmounts;
|
||||
},
|
||||
});
|
||||
const dexOrderSampler = new DexOrderSampler(
|
||||
chainId,
|
||||
new RpcSamplerClient(),
|
||||
sampler,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
async () => undefined,
|
||||
);
|
||||
const [fillableMakerAmounts, fillableTakerAmounts] = await dexOrderSampler.executeAsync(
|
||||
dexOrderSampler.getLimitOrderFillableMakerAmounts(ORDERS, exchangeProxyAddress),
|
||||
dexOrderSampler.getLimitOrderFillableTakerAmounts(ORDERS, exchangeProxyAddress),
|
||||
);
|
||||
expect(fillableMakerAmounts).to.deep.eq(expectedFillableMakerAmounts);
|
||||
expect(fillableTakerAmounts).to.deep.eq(expectedFillableTakerAmounts);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
// tslint:disable-next-line: max-file-line-count
|
||||
Reference in New Issue
Block a user