Add Uniswap V2 support to @0x/asset-swapper (#2599)
* add uniswapV2 * update changelogs * remove unused import * add tests for Uniswap V2 ETH * rename UniswapV2 and UniswapV2Eth * use correct token address path * update contract addresses after deploy
This commit is contained in:
parent
b39189fde3
commit
0fbbabe208
@ -649,7 +649,7 @@ contract ERC20BridgeSampler is
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Sample sell quotes from UniswapV2.
|
/// @dev Sample sell quotes from UniswapV2.
|
||||||
/// @param path Token route.
|
/// @param path Token route. Should be takerToken -> makerToken
|
||||||
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
/// @param takerTokenAmounts Taker token sell amount for each sample.
|
||||||
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
/// @return makerTokenAmounts Maker amounts bought at each taker token
|
||||||
/// amount.
|
/// amount.
|
||||||
@ -683,7 +683,7 @@ contract ERC20BridgeSampler is
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Sample buy quotes from UniswapV2.
|
/// @dev Sample buy quotes from UniswapV2.
|
||||||
/// @param path Token route.
|
/// @param path Token route. Should be takerToken -> makerToken.
|
||||||
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
/// @param makerTokenAmounts Maker token buy amount for each sample.
|
||||||
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
/// @return takerTokenAmounts Taker amounts sold at each maker token
|
||||||
/// amount.
|
/// amount.
|
||||||
|
@ -77,6 +77,10 @@
|
|||||||
{
|
{
|
||||||
"note": "Increase timeout for tests",
|
"note": "Increase timeout for tests",
|
||||||
"pr": 2587
|
"pr": 2587
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Add support for Uniswap V2",
|
||||||
|
"pr": 2599
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -9,6 +9,8 @@ import { ERC20BridgeSource, FakeBuyOpts, GetMarketOrdersOpts } from './types';
|
|||||||
*/
|
*/
|
||||||
export const SELL_SOURCES = [
|
export const SELL_SOURCES = [
|
||||||
ERC20BridgeSource.Uniswap,
|
ERC20BridgeSource.Uniswap,
|
||||||
|
ERC20BridgeSource.UniswapV2,
|
||||||
|
ERC20BridgeSource.UniswapV2Eth,
|
||||||
ERC20BridgeSource.Eth2Dai,
|
ERC20BridgeSource.Eth2Dai,
|
||||||
ERC20BridgeSource.Kyber,
|
ERC20BridgeSource.Kyber,
|
||||||
// All Curve Sources
|
// All Curve Sources
|
||||||
@ -24,6 +26,8 @@ export const SELL_SOURCES = [
|
|||||||
*/
|
*/
|
||||||
export const BUY_SOURCES = [
|
export const BUY_SOURCES = [
|
||||||
ERC20BridgeSource.Uniswap,
|
ERC20BridgeSource.Uniswap,
|
||||||
|
ERC20BridgeSource.UniswapV2,
|
||||||
|
ERC20BridgeSource.UniswapV2Eth,
|
||||||
ERC20BridgeSource.Eth2Dai,
|
ERC20BridgeSource.Eth2Dai,
|
||||||
ERC20BridgeSource.Kyber,
|
ERC20BridgeSource.Kyber,
|
||||||
// All Curve sources
|
// All Curve sources
|
||||||
|
@ -93,6 +93,7 @@ export class MarketOperationUtils {
|
|||||||
makerToken,
|
makerToken,
|
||||||
this._wethAddress,
|
this._wethAddress,
|
||||||
ONE_ETHER,
|
ONE_ETHER,
|
||||||
|
this._wethAddress,
|
||||||
this._liquidityProviderRegistry,
|
this._liquidityProviderRegistry,
|
||||||
),
|
),
|
||||||
// Get sell quotes for taker -> maker.
|
// Get sell quotes for taker -> maker.
|
||||||
@ -103,6 +104,7 @@ export class MarketOperationUtils {
|
|||||||
makerToken,
|
makerToken,
|
||||||
takerToken,
|
takerToken,
|
||||||
getSampleAmounts(takerAmount, _opts.numSamples, _opts.sampleDistributionBase),
|
getSampleAmounts(takerAmount, _opts.numSamples, _opts.sampleDistributionBase),
|
||||||
|
this._wethAddress,
|
||||||
this._liquidityProviderRegistry,
|
this._liquidityProviderRegistry,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -173,6 +175,7 @@ export class MarketOperationUtils {
|
|||||||
takerToken,
|
takerToken,
|
||||||
this._wethAddress,
|
this._wethAddress,
|
||||||
ONE_ETHER,
|
ONE_ETHER,
|
||||||
|
this._wethAddress,
|
||||||
this._liquidityProviderRegistry,
|
this._liquidityProviderRegistry,
|
||||||
),
|
),
|
||||||
// Get buy quotes for taker -> maker.
|
// Get buy quotes for taker -> maker.
|
||||||
@ -183,6 +186,7 @@ export class MarketOperationUtils {
|
|||||||
makerToken,
|
makerToken,
|
||||||
takerToken,
|
takerToken,
|
||||||
getSampleAmounts(makerAmount, _opts.numSamples, _opts.sampleDistributionBase),
|
getSampleAmounts(makerAmount, _opts.numSamples, _opts.sampleDistributionBase),
|
||||||
|
this._wethAddress,
|
||||||
this._liquidityProviderRegistry,
|
this._liquidityProviderRegistry,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -248,6 +252,7 @@ export class MarketOperationUtils {
|
|||||||
getNativeOrderTokens(orders[0])[1],
|
getNativeOrderTokens(orders[0])[1],
|
||||||
this._wethAddress,
|
this._wethAddress,
|
||||||
ONE_ETHER,
|
ONE_ETHER,
|
||||||
|
this._wethAddress,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
...batchNativeOrders.map((orders, i) =>
|
...batchNativeOrders.map((orders, i) =>
|
||||||
@ -256,6 +261,7 @@ export class MarketOperationUtils {
|
|||||||
getNativeOrderTokens(orders[0])[0],
|
getNativeOrderTokens(orders[0])[0],
|
||||||
getNativeOrderTokens(orders[0])[1],
|
getNativeOrderTokens(orders[0])[1],
|
||||||
[makerAmounts[i]],
|
[makerAmounts[i]],
|
||||||
|
this._wethAddress,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
@ -5,7 +5,7 @@ import { AbiEncoder, BigNumber } from '@0x/utils';
|
|||||||
|
|
||||||
import { MarketOperation, SignedOrderWithFillableAmounts } from '../../types';
|
import { MarketOperation, SignedOrderWithFillableAmounts } from '../../types';
|
||||||
import { RfqtIndicativeQuoteResponse } from '../quote_requestor';
|
import { RfqtIndicativeQuoteResponse } from '../quote_requestor';
|
||||||
import { getCurveInfo, isCurveSource } from '../source_utils';
|
import { getCurveInfo } from '../source_utils';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ERC20_PROXY_ID,
|
ERC20_PROXY_ID,
|
||||||
@ -181,6 +181,9 @@ function getBridgeAddressFromSource(source: ERC20BridgeSource, opts: CreateOrder
|
|||||||
return opts.contractAddresses.kyberBridge;
|
return opts.contractAddresses.kyberBridge;
|
||||||
case ERC20BridgeSource.Uniswap:
|
case ERC20BridgeSource.Uniswap:
|
||||||
return opts.contractAddresses.uniswapBridge;
|
return opts.contractAddresses.uniswapBridge;
|
||||||
|
case ERC20BridgeSource.UniswapV2:
|
||||||
|
case ERC20BridgeSource.UniswapV2Eth:
|
||||||
|
return opts.contractAddresses.uniswapV2Bridge;
|
||||||
case ERC20BridgeSource.CurveUsdcDai:
|
case ERC20BridgeSource.CurveUsdcDai:
|
||||||
case ERC20BridgeSource.CurveUsdcDaiUsdt:
|
case ERC20BridgeSource.CurveUsdcDaiUsdt:
|
||||||
case ERC20BridgeSource.CurveUsdcDaiUsdtTusd:
|
case ERC20BridgeSource.CurveUsdcDaiUsdtTusd:
|
||||||
@ -203,19 +206,48 @@ function createBridgeOrder(fill: CollapsedFill, opts: CreateOrderFromPathOpts):
|
|||||||
const bridgeAddress = getBridgeAddressFromSource(fill.source, opts);
|
const bridgeAddress = getBridgeAddressFromSource(fill.source, opts);
|
||||||
|
|
||||||
let makerAssetData;
|
let makerAssetData;
|
||||||
if (isCurveSource(fill.source)) {
|
switch (fill.source) {
|
||||||
const { curveAddress, fromTokenIdx, toTokenIdx, version } = getCurveInfo(fill.source, takerToken, makerToken);
|
case ERC20BridgeSource.CurveUsdcDai:
|
||||||
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
|
case ERC20BridgeSource.CurveUsdcDaiUsdt:
|
||||||
makerToken,
|
case ERC20BridgeSource.CurveUsdcDaiUsdtTusd:
|
||||||
bridgeAddress,
|
case ERC20BridgeSource.CurveUsdcDaiUsdtBusd:
|
||||||
createCurveBridgeData(curveAddress, fromTokenIdx, toTokenIdx, version),
|
case ERC20BridgeSource.CurveUsdcDaiUsdtSusd:
|
||||||
);
|
const { curveAddress, fromTokenIdx, toTokenIdx, version } = getCurveInfo(
|
||||||
} else {
|
fill.source,
|
||||||
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
|
takerToken,
|
||||||
makerToken,
|
makerToken,
|
||||||
bridgeAddress,
|
);
|
||||||
createBridgeData(takerToken),
|
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
|
||||||
);
|
makerToken,
|
||||||
|
bridgeAddress,
|
||||||
|
createCurveBridgeData(curveAddress, fromTokenIdx, toTokenIdx, version),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case ERC20BridgeSource.UniswapV2:
|
||||||
|
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
|
||||||
|
makerToken,
|
||||||
|
bridgeAddress,
|
||||||
|
createUniswapV2BridgeData([makerToken, takerToken]),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case ERC20BridgeSource.UniswapV2Eth:
|
||||||
|
if (opts.contractAddresses.etherToken === NULL_ADDRESS) {
|
||||||
|
throw new Error(
|
||||||
|
`Cannot create a ${ERC20BridgeSource.UniswapV2Eth.toString()} order without a WETH address`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
|
||||||
|
makerToken,
|
||||||
|
bridgeAddress,
|
||||||
|
createUniswapV2BridgeData([makerToken, opts.contractAddresses.etherToken, takerToken]),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
|
||||||
|
makerToken,
|
||||||
|
bridgeAddress,
|
||||||
|
createBridgeData(takerToken),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const [slippedMakerAssetAmount, slippedTakerAssetAmount] = getSlippedBridgeAssetAmounts(fill, opts);
|
const [slippedMakerAssetAmount, slippedTakerAssetAmount] = getSlippedBridgeAssetAmounts(fill, opts);
|
||||||
return {
|
return {
|
||||||
@ -298,6 +330,11 @@ function createCurveBridgeData(
|
|||||||
return curveBridgeDataEncoder.encode([curveAddress, fromTokenIdx, toTokenIdx, version]);
|
return curveBridgeDataEncoder.encode([curveAddress, fromTokenIdx, toTokenIdx, version]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createUniswapV2BridgeData(tokenAddressPath: string[]): string {
|
||||||
|
const uniswapV2BridgeDataEncoder = AbiEncoder.create('(address[])');
|
||||||
|
return uniswapV2BridgeDataEncoder.encode([tokenAddressPath]);
|
||||||
|
}
|
||||||
|
|
||||||
function getSlippedBridgeAssetAmounts(fill: CollapsedFill, opts: CreateOrderFromPathOpts): [BigNumber, BigNumber] {
|
function getSlippedBridgeAssetAmounts(fill: CollapsedFill, opts: CreateOrderFromPathOpts): [BigNumber, BigNumber] {
|
||||||
return [
|
return [
|
||||||
// Maker asset amount.
|
// Maker asset amount.
|
||||||
|
@ -98,6 +98,30 @@ export const samplerOperations = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
getUniswapV2SellQuotes(tokenAddressPath: string[], takerFillAmounts: BigNumber[]): BatchedOperation<BigNumber[]> {
|
||||||
|
return {
|
||||||
|
encodeCall: contract => {
|
||||||
|
return contract
|
||||||
|
.sampleSellsFromUniswapV2(tokenAddressPath, takerFillAmounts)
|
||||||
|
.getABIEncodedTransactionData();
|
||||||
|
},
|
||||||
|
handleCallResultsAsync: async (contract, callResults) => {
|
||||||
|
return contract.getABIDecodedReturnData<BigNumber[]>('sampleSellsFromUniswapV2', callResults);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
getUniswapV2BuyQuotes(tokenAddressPath: string[], makerFillAmounts: BigNumber[]): BatchedOperation<BigNumber[]> {
|
||||||
|
return {
|
||||||
|
encodeCall: contract => {
|
||||||
|
return contract
|
||||||
|
.sampleBuysFromUniswapV2(tokenAddressPath, makerFillAmounts)
|
||||||
|
.getABIEncodedTransactionData();
|
||||||
|
},
|
||||||
|
handleCallResultsAsync: async (contract, callResults) => {
|
||||||
|
return contract.getABIDecodedReturnData<BigNumber[]>('sampleBuysFromUniswapV2', callResults);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
getLiquidityProviderSellQuotes(
|
getLiquidityProviderSellQuotes(
|
||||||
liquidityProviderRegistryAddress: string,
|
liquidityProviderRegistryAddress: string,
|
||||||
makerToken: string,
|
makerToken: string,
|
||||||
@ -231,6 +255,7 @@ export const samplerOperations = {
|
|||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
takerFillAmount: BigNumber,
|
takerFillAmount: BigNumber,
|
||||||
|
wethAddress: string,
|
||||||
liquidityProviderRegistryAddress?: string | undefined,
|
liquidityProviderRegistryAddress?: string | undefined,
|
||||||
): BatchedOperation<BigNumber> {
|
): BatchedOperation<BigNumber> {
|
||||||
if (makerToken.toLowerCase() === takerToken.toLowerCase()) {
|
if (makerToken.toLowerCase() === takerToken.toLowerCase()) {
|
||||||
@ -241,6 +266,7 @@ export const samplerOperations = {
|
|||||||
makerToken,
|
makerToken,
|
||||||
takerToken,
|
takerToken,
|
||||||
[takerFillAmount],
|
[takerFillAmount],
|
||||||
|
wethAddress,
|
||||||
liquidityProviderRegistryAddress,
|
liquidityProviderRegistryAddress,
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
@ -297,6 +323,7 @@ export const samplerOperations = {
|
|||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
takerFillAmounts: BigNumber[],
|
takerFillAmounts: BigNumber[],
|
||||||
|
wethAddress: string,
|
||||||
liquidityProviderRegistryAddress?: string | undefined,
|
liquidityProviderRegistryAddress?: string | undefined,
|
||||||
): BatchedOperation<DexSample[][]> {
|
): BatchedOperation<DexSample[][]> {
|
||||||
const subOps = sources
|
const subOps = sources
|
||||||
@ -306,6 +333,16 @@ export const samplerOperations = {
|
|||||||
batchedOperation = samplerOperations.getEth2DaiSellQuotes(makerToken, takerToken, takerFillAmounts);
|
batchedOperation = samplerOperations.getEth2DaiSellQuotes(makerToken, takerToken, takerFillAmounts);
|
||||||
} else if (source === ERC20BridgeSource.Uniswap) {
|
} else if (source === ERC20BridgeSource.Uniswap) {
|
||||||
batchedOperation = samplerOperations.getUniswapSellQuotes(makerToken, takerToken, takerFillAmounts);
|
batchedOperation = samplerOperations.getUniswapSellQuotes(makerToken, takerToken, takerFillAmounts);
|
||||||
|
} else if (source === ERC20BridgeSource.UniswapV2) {
|
||||||
|
batchedOperation = samplerOperations.getUniswapV2SellQuotes(
|
||||||
|
[takerToken, makerToken],
|
||||||
|
takerFillAmounts,
|
||||||
|
);
|
||||||
|
} else if (source === ERC20BridgeSource.UniswapV2Eth) {
|
||||||
|
batchedOperation = samplerOperations.getUniswapV2SellQuotes(
|
||||||
|
[takerToken, wethAddress, makerToken],
|
||||||
|
takerFillAmounts,
|
||||||
|
);
|
||||||
} else if (source === ERC20BridgeSource.Kyber) {
|
} else if (source === ERC20BridgeSource.Kyber) {
|
||||||
batchedOperation = samplerOperations.getKyberSellQuotes(makerToken, takerToken, takerFillAmounts);
|
batchedOperation = samplerOperations.getKyberSellQuotes(makerToken, takerToken, takerFillAmounts);
|
||||||
} else if (isCurveSource(source)) {
|
} else if (isCurveSource(source)) {
|
||||||
@ -366,6 +403,7 @@ export const samplerOperations = {
|
|||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
makerFillAmounts: BigNumber[],
|
makerFillAmounts: BigNumber[],
|
||||||
|
wethAddress: string,
|
||||||
liquidityProviderRegistryAddress?: string | undefined,
|
liquidityProviderRegistryAddress?: string | undefined,
|
||||||
fakeBuyOpts: FakeBuyOpts = DEFAULT_FAKE_BUY_OPTS,
|
fakeBuyOpts: FakeBuyOpts = DEFAULT_FAKE_BUY_OPTS,
|
||||||
): BatchedOperation<DexSample[][]> {
|
): BatchedOperation<DexSample[][]> {
|
||||||
@ -376,6 +414,16 @@ export const samplerOperations = {
|
|||||||
batchedOperation = samplerOperations.getEth2DaiBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
batchedOperation = samplerOperations.getEth2DaiBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
||||||
} else if (source === ERC20BridgeSource.Uniswap) {
|
} else if (source === ERC20BridgeSource.Uniswap) {
|
||||||
batchedOperation = samplerOperations.getUniswapBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
batchedOperation = samplerOperations.getUniswapBuyQuotes(makerToken, takerToken, makerFillAmounts);
|
||||||
|
} else if (source === ERC20BridgeSource.UniswapV2) {
|
||||||
|
batchedOperation = samplerOperations.getUniswapV2BuyQuotes(
|
||||||
|
[takerToken, makerToken],
|
||||||
|
makerFillAmounts,
|
||||||
|
);
|
||||||
|
} else if (source === ERC20BridgeSource.UniswapV2Eth) {
|
||||||
|
batchedOperation = samplerOperations.getUniswapV2BuyQuotes(
|
||||||
|
[takerToken, wethAddress, makerToken],
|
||||||
|
makerFillAmounts,
|
||||||
|
);
|
||||||
} else if (source === ERC20BridgeSource.Kyber) {
|
} else if (source === ERC20BridgeSource.Kyber) {
|
||||||
batchedOperation = samplerOperations.getKyberBuyQuotes(
|
batchedOperation = samplerOperations.getKyberBuyQuotes(
|
||||||
makerToken,
|
makerToken,
|
||||||
|
@ -28,6 +28,8 @@ export enum AggregationError {
|
|||||||
export enum ERC20BridgeSource {
|
export enum ERC20BridgeSource {
|
||||||
Native = 'Native',
|
Native = 'Native',
|
||||||
Uniswap = 'Uniswap',
|
Uniswap = 'Uniswap',
|
||||||
|
UniswapV2 = 'Uniswap_V2',
|
||||||
|
UniswapV2Eth = 'Uniswap_V2_ETH',
|
||||||
Eth2Dai = 'Eth2Dai',
|
Eth2Dai = 'Eth2Dai',
|
||||||
Kyber = 'Kyber',
|
Kyber = 'Kyber',
|
||||||
CurveUsdcDai = 'Curve_USDC_DAI',
|
CurveUsdcDai = 'Curve_USDC_DAI',
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { getContractAddressesForChainOrThrow } from '@0x/contract-addresses';
|
||||||
import {
|
import {
|
||||||
constants,
|
constants,
|
||||||
expect,
|
expect,
|
||||||
@ -24,6 +25,8 @@ describe('DexSampler tests', () => {
|
|||||||
const MAKER_ASSET_DATA = assetDataUtils.encodeERC20AssetData(MAKER_TOKEN);
|
const MAKER_ASSET_DATA = assetDataUtils.encodeERC20AssetData(MAKER_TOKEN);
|
||||||
const TAKER_ASSET_DATA = assetDataUtils.encodeERC20AssetData(TAKER_TOKEN);
|
const TAKER_ASSET_DATA = assetDataUtils.encodeERC20AssetData(TAKER_TOKEN);
|
||||||
|
|
||||||
|
const wethAddress = getContractAddressesForChainOrThrow(CHAIN_ID).etherToken;
|
||||||
|
|
||||||
describe('getSampleAmounts()', () => {
|
describe('getSampleAmounts()', () => {
|
||||||
const FILL_AMOUNT = getRandomInteger(1, 1e18);
|
const FILL_AMOUNT = getRandomInteger(1, 1e18);
|
||||||
const NUM_SAMPLES = 16;
|
const NUM_SAMPLES = 16;
|
||||||
@ -160,6 +163,7 @@ describe('DexSampler tests', () => {
|
|||||||
expectedMakerToken,
|
expectedMakerToken,
|
||||||
expectedTakerToken,
|
expectedTakerToken,
|
||||||
[toBaseUnitAmount(1000)],
|
[toBaseUnitAmount(1000)],
|
||||||
|
wethAddress,
|
||||||
registry,
|
registry,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -193,6 +197,7 @@ describe('DexSampler tests', () => {
|
|||||||
expectedMakerToken,
|
expectedMakerToken,
|
||||||
expectedTakerToken,
|
expectedTakerToken,
|
||||||
[toBaseUnitAmount(1000)],
|
[toBaseUnitAmount(1000)],
|
||||||
|
wethAddress,
|
||||||
registry,
|
registry,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -255,6 +260,28 @@ describe('DexSampler tests', () => {
|
|||||||
expect(fillableAmounts).to.deep.eq(expectedMakerFillAmounts);
|
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: (path, fillAmounts) => {
|
||||||
|
expect(path).to.deep.eq([expectedMakerToken, expectedTakerToken]);
|
||||||
|
expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts);
|
||||||
|
return expectedMakerFillAmounts;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const dexOrderSampler = new DexOrderSampler(sampler);
|
||||||
|
const [fillableAmounts] = await dexOrderSampler.executeAsync(
|
||||||
|
DexOrderSampler.ops.getUniswapV2SellQuotes(
|
||||||
|
[expectedMakerToken, expectedTakerToken],
|
||||||
|
expectedTakerFillAmounts,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(fillableAmounts).to.deep.eq(expectedMakerFillAmounts);
|
||||||
|
});
|
||||||
|
|
||||||
it('getEth2DaiBuyQuotes()', async () => {
|
it('getEth2DaiBuyQuotes()', async () => {
|
||||||
const expectedTakerToken = randomAddress();
|
const expectedTakerToken = randomAddress();
|
||||||
const expectedMakerToken = randomAddress();
|
const expectedMakerToken = randomAddress();
|
||||||
@ -310,11 +337,17 @@ describe('DexSampler tests', () => {
|
|||||||
it('getSellQuotes()', async () => {
|
it('getSellQuotes()', async () => {
|
||||||
const expectedTakerToken = randomAddress();
|
const expectedTakerToken = randomAddress();
|
||||||
const expectedMakerToken = randomAddress();
|
const expectedMakerToken = randomAddress();
|
||||||
const sources = [ERC20BridgeSource.Kyber, ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.Uniswap];
|
const sources = [
|
||||||
|
ERC20BridgeSource.Kyber,
|
||||||
|
ERC20BridgeSource.Eth2Dai,
|
||||||
|
ERC20BridgeSource.Uniswap,
|
||||||
|
ERC20BridgeSource.UniswapV2,
|
||||||
|
];
|
||||||
const ratesBySource: RatesBySource = {
|
const ratesBySource: RatesBySource = {
|
||||||
[ERC20BridgeSource.Kyber]: getRandomFloat(0, 100),
|
[ERC20BridgeSource.Kyber]: getRandomFloat(0, 100),
|
||||||
[ERC20BridgeSource.Eth2Dai]: getRandomFloat(0, 100),
|
[ERC20BridgeSource.Eth2Dai]: getRandomFloat(0, 100),
|
||||||
[ERC20BridgeSource.Uniswap]: getRandomFloat(0, 100),
|
[ERC20BridgeSource.Uniswap]: getRandomFloat(0, 100),
|
||||||
|
[ERC20BridgeSource.UniswapV2]: getRandomFloat(0, 100),
|
||||||
};
|
};
|
||||||
const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 3);
|
const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 3);
|
||||||
const sampler = new MockSamplerContract({
|
const sampler = new MockSamplerContract({
|
||||||
@ -336,6 +369,11 @@ describe('DexSampler tests', () => {
|
|||||||
expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts);
|
expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts);
|
||||||
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.Eth2Dai]).integerValue());
|
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.Eth2Dai]).integerValue());
|
||||||
},
|
},
|
||||||
|
sampleSellsFromUniswapV2: (path, fillAmounts) => {
|
||||||
|
expect(path).to.deep.eq([expectedTakerToken, expectedMakerToken]);
|
||||||
|
expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts);
|
||||||
|
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.UniswapV2]).integerValue());
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const dexOrderSampler = new DexOrderSampler(sampler);
|
const dexOrderSampler = new DexOrderSampler(sampler);
|
||||||
const [quotes] = await dexOrderSampler.executeAsync(
|
const [quotes] = await dexOrderSampler.executeAsync(
|
||||||
@ -344,6 +382,43 @@ describe('DexSampler tests', () => {
|
|||||||
expectedMakerToken,
|
expectedMakerToken,
|
||||||
expectedTakerToken,
|
expectedTakerToken,
|
||||||
expectedTakerFillAmounts,
|
expectedTakerFillAmounts,
|
||||||
|
wethAddress,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(quotes).to.be.length(sources.length);
|
||||||
|
const expectedQuotes = sources.map(s =>
|
||||||
|
expectedTakerFillAmounts.map(a => ({
|
||||||
|
source: s,
|
||||||
|
input: a,
|
||||||
|
output: a.times(ratesBySource[s]).integerValue(),
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getSellQuotes() includes ETH for Uniswap_V2_ETH', async () => {
|
||||||
|
const expectedTakerToken = randomAddress();
|
||||||
|
const expectedMakerToken = randomAddress();
|
||||||
|
const sources = [ERC20BridgeSource.UniswapV2Eth];
|
||||||
|
const ratesBySource: RatesBySource = {
|
||||||
|
[ERC20BridgeSource.UniswapV2Eth]: getRandomFloat(0, 100),
|
||||||
|
};
|
||||||
|
const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 3);
|
||||||
|
const sampler = new MockSamplerContract({
|
||||||
|
sampleSellsFromUniswapV2: (path, fillAmounts) => {
|
||||||
|
expect(path).to.deep.eq([expectedTakerToken, wethAddress, expectedMakerToken]);
|
||||||
|
expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts);
|
||||||
|
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.UniswapV2Eth]).integerValue());
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const dexOrderSampler = new DexOrderSampler(sampler);
|
||||||
|
const [quotes] = await dexOrderSampler.executeAsync(
|
||||||
|
DexOrderSampler.ops.getSellQuotes(
|
||||||
|
sources,
|
||||||
|
expectedMakerToken,
|
||||||
|
expectedTakerToken,
|
||||||
|
expectedTakerFillAmounts,
|
||||||
|
wethAddress,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
expect(quotes).to.be.length(sources.length);
|
expect(quotes).to.be.length(sources.length);
|
||||||
@ -364,6 +439,7 @@ describe('DexSampler tests', () => {
|
|||||||
const ratesBySource: RatesBySource = {
|
const ratesBySource: RatesBySource = {
|
||||||
[ERC20BridgeSource.Eth2Dai]: getRandomFloat(0, 100),
|
[ERC20BridgeSource.Eth2Dai]: getRandomFloat(0, 100),
|
||||||
[ERC20BridgeSource.Uniswap]: getRandomFloat(0, 100),
|
[ERC20BridgeSource.Uniswap]: getRandomFloat(0, 100),
|
||||||
|
[ERC20BridgeSource.UniswapV2]: getRandomFloat(0, 100),
|
||||||
};
|
};
|
||||||
const expectedMakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 3);
|
const expectedMakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 3);
|
||||||
const sampler = new MockSamplerContract({
|
const sampler = new MockSamplerContract({
|
||||||
@ -379,6 +455,11 @@ describe('DexSampler tests', () => {
|
|||||||
expect(fillAmounts).to.deep.eq(expectedMakerFillAmounts);
|
expect(fillAmounts).to.deep.eq(expectedMakerFillAmounts);
|
||||||
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.Eth2Dai]).integerValue());
|
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.Eth2Dai]).integerValue());
|
||||||
},
|
},
|
||||||
|
sampleBuysFromUniswapV2: (path, fillAmounts) => {
|
||||||
|
expect(path).to.deep.eq([expectedTakerToken, expectedMakerToken]);
|
||||||
|
expect(fillAmounts).to.deep.eq(expectedMakerFillAmounts);
|
||||||
|
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.UniswapV2]).integerValue());
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const dexOrderSampler = new DexOrderSampler(sampler);
|
const dexOrderSampler = new DexOrderSampler(sampler);
|
||||||
const [quotes] = await dexOrderSampler.executeAsync(
|
const [quotes] = await dexOrderSampler.executeAsync(
|
||||||
@ -387,6 +468,56 @@ describe('DexSampler tests', () => {
|
|||||||
expectedMakerToken,
|
expectedMakerToken,
|
||||||
expectedTakerToken,
|
expectedTakerToken,
|
||||||
expectedMakerFillAmounts,
|
expectedMakerFillAmounts,
|
||||||
|
wethAddress,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(quotes).to.be.length(sources.length);
|
||||||
|
const expectedQuotes = sources.map(s =>
|
||||||
|
expectedMakerFillAmounts.map(a => ({
|
||||||
|
source: s,
|
||||||
|
input: a,
|
||||||
|
output: a.times(ratesBySource[s]).integerValue(),
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
expect(quotes).to.deep.eq(expectedQuotes);
|
||||||
|
});
|
||||||
|
it('getBuyQuotes() includes ETH for Uniswap_V2_ETH', async () => {
|
||||||
|
const expectedTakerToken = randomAddress();
|
||||||
|
const expectedMakerToken = randomAddress();
|
||||||
|
const sources = [ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.Uniswap, ERC20BridgeSource.UniswapV2Eth];
|
||||||
|
const ratesBySource: RatesBySource = {
|
||||||
|
[ERC20BridgeSource.Eth2Dai]: getRandomFloat(0, 100),
|
||||||
|
[ERC20BridgeSource.Uniswap]: getRandomFloat(0, 100),
|
||||||
|
[ERC20BridgeSource.UniswapV2Eth]: getRandomFloat(0, 100),
|
||||||
|
};
|
||||||
|
const expectedMakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 3);
|
||||||
|
const sampler = new MockSamplerContract({
|
||||||
|
sampleBuysFromUniswap: (takerToken, makerToken, fillAmounts) => {
|
||||||
|
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());
|
||||||
|
},
|
||||||
|
sampleBuysFromEth2Dai: (takerToken, makerToken, fillAmounts) => {
|
||||||
|
expect(takerToken).to.eq(expectedTakerToken);
|
||||||
|
expect(makerToken).to.eq(expectedMakerToken);
|
||||||
|
expect(fillAmounts).to.deep.eq(expectedMakerFillAmounts);
|
||||||
|
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.Eth2Dai]).integerValue());
|
||||||
|
},
|
||||||
|
sampleBuysFromUniswapV2: (path, fillAmounts) => {
|
||||||
|
expect(path).to.deep.eq([expectedTakerToken, wethAddress, expectedMakerToken]);
|
||||||
|
expect(fillAmounts).to.deep.eq(expectedMakerFillAmounts);
|
||||||
|
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.UniswapV2Eth]).integerValue());
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const dexOrderSampler = new DexOrderSampler(sampler);
|
||||||
|
const [quotes] = await dexOrderSampler.executeAsync(
|
||||||
|
DexOrderSampler.ops.getBuyQuotes(
|
||||||
|
sources,
|
||||||
|
expectedMakerToken,
|
||||||
|
expectedTakerToken,
|
||||||
|
expectedMakerFillAmounts,
|
||||||
|
wethAddress,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
expect(quotes).to.be.length(sources.length);
|
expect(quotes).to.be.length(sources.length);
|
||||||
|
@ -34,6 +34,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
const ETH2DAI_BRIDGE_ADDRESS = contractAddresses.eth2DaiBridge;
|
const ETH2DAI_BRIDGE_ADDRESS = contractAddresses.eth2DaiBridge;
|
||||||
const KYBER_BRIDGE_ADDRESS = contractAddresses.kyberBridge;
|
const KYBER_BRIDGE_ADDRESS = contractAddresses.kyberBridge;
|
||||||
const UNISWAP_BRIDGE_ADDRESS = contractAddresses.uniswapBridge;
|
const UNISWAP_BRIDGE_ADDRESS = contractAddresses.uniswapBridge;
|
||||||
|
const UNISWAP_V2_BRIDGE_ADDRESS = contractAddresses.uniswapV2Bridge;
|
||||||
const CURVE_BRIDGE_ADDRESS = contractAddresses.curveBridge;
|
const CURVE_BRIDGE_ADDRESS = contractAddresses.curveBridge;
|
||||||
|
|
||||||
const MAKER_TOKEN = randomAddress();
|
const MAKER_TOKEN = randomAddress();
|
||||||
@ -89,6 +90,8 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
return ERC20BridgeSource.Eth2Dai;
|
return ERC20BridgeSource.Eth2Dai;
|
||||||
case UNISWAP_BRIDGE_ADDRESS.toLowerCase():
|
case UNISWAP_BRIDGE_ADDRESS.toLowerCase():
|
||||||
return ERC20BridgeSource.Uniswap;
|
return ERC20BridgeSource.Uniswap;
|
||||||
|
case UNISWAP_V2_BRIDGE_ADDRESS.toLowerCase():
|
||||||
|
return ERC20BridgeSource.UniswapV2;
|
||||||
case CURVE_BRIDGE_ADDRESS.toLowerCase():
|
case CURVE_BRIDGE_ADDRESS.toLowerCase():
|
||||||
const curveSource = Object.keys(DEFAULT_CURVE_OPTS).filter(
|
const curveSource = Object.keys(DEFAULT_CURVE_OPTS).filter(
|
||||||
k => assetData.indexOf(DEFAULT_CURVE_OPTS[k].curveAddress.slice(2)) !== -1,
|
k => assetData.indexOf(DEFAULT_CURVE_OPTS[k].curveAddress.slice(2)) !== -1,
|
||||||
@ -151,11 +154,18 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
fillAmounts: BigNumber[],
|
fillAmounts: BigNumber[],
|
||||||
|
wethAddress: string,
|
||||||
liquidityProviderAddress?: string,
|
liquidityProviderAddress?: string,
|
||||||
) => DexSample[][];
|
) => DexSample[][];
|
||||||
|
|
||||||
function createGetMultipleSellQuotesOperationFromRates(rates: RatesBySource): GetMultipleQuotesOperation {
|
function createGetMultipleSellQuotesOperationFromRates(rates: RatesBySource): GetMultipleQuotesOperation {
|
||||||
return (sources: ERC20BridgeSource[], makerToken: string, takerToken: string, fillAmounts: BigNumber[]) => {
|
return (
|
||||||
|
sources: ERC20BridgeSource[],
|
||||||
|
makerToken: string,
|
||||||
|
takerToken: string,
|
||||||
|
fillAmounts: BigNumber[],
|
||||||
|
wethAddress: string,
|
||||||
|
) => {
|
||||||
return sources.map(s => createSamplesFromRates(s, fillAmounts, rates[s]));
|
return sources.map(s => createSamplesFromRates(s, fillAmounts, rates[s]));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -173,17 +183,31 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
fillAmounts: BigNumber[],
|
fillAmounts: BigNumber[],
|
||||||
|
wethAddress: string,
|
||||||
liquidityProviderAddress?: string,
|
liquidityProviderAddress?: string,
|
||||||
) => {
|
) => {
|
||||||
liquidityPoolParams.liquidityProviderAddress = liquidityProviderAddress;
|
liquidityPoolParams.liquidityProviderAddress = liquidityProviderAddress;
|
||||||
liquidityPoolParams.sources = sources;
|
liquidityPoolParams.sources = sources;
|
||||||
return tradeOperation(rates)(sources, makerToken, takerToken, fillAmounts, liquidityProviderAddress);
|
return tradeOperation(rates)(
|
||||||
|
sources,
|
||||||
|
makerToken,
|
||||||
|
takerToken,
|
||||||
|
fillAmounts,
|
||||||
|
wethAddress,
|
||||||
|
liquidityProviderAddress,
|
||||||
|
);
|
||||||
};
|
};
|
||||||
return [liquidityPoolParams, fn];
|
return [liquidityPoolParams, fn];
|
||||||
}
|
}
|
||||||
|
|
||||||
function createGetMultipleBuyQuotesOperationFromRates(rates: RatesBySource): GetMultipleQuotesOperation {
|
function createGetMultipleBuyQuotesOperationFromRates(rates: RatesBySource): GetMultipleQuotesOperation {
|
||||||
return (sources: ERC20BridgeSource[], makerToken: string, takerToken: string, fillAmounts: BigNumber[]) => {
|
return (
|
||||||
|
sources: ERC20BridgeSource[],
|
||||||
|
makerToken: string,
|
||||||
|
takerToken: string,
|
||||||
|
fillAmounts: BigNumber[],
|
||||||
|
wethAddress: string,
|
||||||
|
) => {
|
||||||
return sources.map(s => createSamplesFromRates(s, fillAmounts, rates[s].map(r => new BigNumber(1).div(r))));
|
return sources.map(s => createSamplesFromRates(s, fillAmounts, rates[s].map(r => new BigNumber(1).div(r))));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -193,6 +217,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
fillAmounts: BigNumber[],
|
fillAmounts: BigNumber[],
|
||||||
|
wethAddress: string,
|
||||||
liquidityProviderAddress?: string,
|
liquidityProviderAddress?: string,
|
||||||
) => BigNumber;
|
) => BigNumber;
|
||||||
|
|
||||||
@ -203,7 +228,13 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
) => string;
|
) => string;
|
||||||
|
|
||||||
function createGetMedianSellRate(rate: Numberish): GetMedianRateOperation {
|
function createGetMedianSellRate(rate: Numberish): GetMedianRateOperation {
|
||||||
return (sources: ERC20BridgeSource[], makerToken: string, takerToken: string, fillAmounts: BigNumber[]) => {
|
return (
|
||||||
|
sources: ERC20BridgeSource[],
|
||||||
|
makerToken: string,
|
||||||
|
takerToken: string,
|
||||||
|
fillAmounts: BigNumber[],
|
||||||
|
wethAddress: string,
|
||||||
|
) => {
|
||||||
return new BigNumber(rate);
|
return new BigNumber(rate);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -255,6 +286,8 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
[ERC20BridgeSource.Eth2Dai]: createDecreasingRates(NUM_SAMPLES),
|
[ERC20BridgeSource.Eth2Dai]: createDecreasingRates(NUM_SAMPLES),
|
||||||
[ERC20BridgeSource.Kyber]: createDecreasingRates(NUM_SAMPLES),
|
[ERC20BridgeSource.Kyber]: createDecreasingRates(NUM_SAMPLES),
|
||||||
[ERC20BridgeSource.Uniswap]: createDecreasingRates(NUM_SAMPLES),
|
[ERC20BridgeSource.Uniswap]: createDecreasingRates(NUM_SAMPLES),
|
||||||
|
[ERC20BridgeSource.UniswapV2]: createDecreasingRates(NUM_SAMPLES),
|
||||||
|
[ERC20BridgeSource.UniswapV2Eth]: createDecreasingRates(NUM_SAMPLES),
|
||||||
[ERC20BridgeSource.CurveUsdcDai]: _.times(NUM_SAMPLES, () => 0),
|
[ERC20BridgeSource.CurveUsdcDai]: _.times(NUM_SAMPLES, () => 0),
|
||||||
[ERC20BridgeSource.CurveUsdcDaiUsdt]: _.times(NUM_SAMPLES, () => 0),
|
[ERC20BridgeSource.CurveUsdcDaiUsdt]: _.times(NUM_SAMPLES, () => 0),
|
||||||
[ERC20BridgeSource.CurveUsdcDaiUsdtTusd]: _.times(NUM_SAMPLES, () => 0),
|
[ERC20BridgeSource.CurveUsdcDaiUsdtTusd]: _.times(NUM_SAMPLES, () => 0),
|
||||||
@ -310,7 +343,11 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
sampleDistributionBase: 1,
|
sampleDistributionBase: 1,
|
||||||
bridgeSlippage: 0,
|
bridgeSlippage: 0,
|
||||||
maxFallbackSlippage: 100,
|
maxFallbackSlippage: 100,
|
||||||
excludedSources: Object.keys(DEFAULT_CURVE_OPTS) as ERC20BridgeSource[],
|
excludedSources: [
|
||||||
|
ERC20BridgeSource.Uniswap,
|
||||||
|
ERC20BridgeSource.UniswapV2Eth,
|
||||||
|
...(Object.keys(DEFAULT_CURVE_OPTS) as ERC20BridgeSource[]),
|
||||||
|
],
|
||||||
allowFallback: false,
|
allowFallback: false,
|
||||||
shouldBatchBridgeOrders: false,
|
shouldBatchBridgeOrders: false,
|
||||||
};
|
};
|
||||||
@ -323,9 +360,9 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
const numSamples = _.random(1, NUM_SAMPLES);
|
const numSamples = _.random(1, NUM_SAMPLES);
|
||||||
let actualNumSamples = 0;
|
let actualNumSamples = 0;
|
||||||
replaceSamplerOps({
|
replaceSamplerOps({
|
||||||
getSellQuotes: (sources, makerToken, takerToken, amounts) => {
|
getSellQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => {
|
||||||
actualNumSamples = amounts.length;
|
actualNumSamples = amounts.length;
|
||||||
return DEFAULT_OPS.getSellQuotes(sources, makerToken, takerToken, amounts);
|
return DEFAULT_OPS.getSellQuotes(sources, makerToken, takerToken, amounts, wethAddress);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await marketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, {
|
await marketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, {
|
||||||
@ -338,9 +375,9 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
it('polls all DEXes if `excludedSources` is empty', async () => {
|
it('polls all DEXes if `excludedSources` is empty', async () => {
|
||||||
let sourcesPolled: ERC20BridgeSource[] = [];
|
let sourcesPolled: ERC20BridgeSource[] = [];
|
||||||
replaceSamplerOps({
|
replaceSamplerOps({
|
||||||
getSellQuotes: (sources, makerToken, takerToken, amounts) => {
|
getSellQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => {
|
||||||
sourcesPolled = sources.slice();
|
sourcesPolled = sources.slice();
|
||||||
return DEFAULT_OPS.getSellQuotes(sources, makerToken, takerToken, amounts);
|
return DEFAULT_OPS.getSellQuotes(sources, makerToken, takerToken, amounts, wethAddress);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await marketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, {
|
await marketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, {
|
||||||
@ -379,9 +416,9 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
const excludedSources = _.sampleSize(SELL_SOURCES, _.random(1, SELL_SOURCES.length));
|
const excludedSources = _.sampleSize(SELL_SOURCES, _.random(1, SELL_SOURCES.length));
|
||||||
let sourcesPolled: ERC20BridgeSource[] = [];
|
let sourcesPolled: ERC20BridgeSource[] = [];
|
||||||
replaceSamplerOps({
|
replaceSamplerOps({
|
||||||
getSellQuotes: (sources, makerToken, takerToken, amounts) => {
|
getSellQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => {
|
||||||
sourcesPolled = sources.slice();
|
sourcesPolled = sources.slice();
|
||||||
return DEFAULT_OPS.getSellQuotes(sources, makerToken, takerToken, amounts);
|
return DEFAULT_OPS.getSellQuotes(sources, makerToken, takerToken, amounts, wethAddress);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await marketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, {
|
await marketOperationUtils.getMarketSellOrdersAsync(ORDERS, FILL_AMOUNT, {
|
||||||
@ -445,7 +482,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
it('can mix convex sources', async () => {
|
it('can mix convex sources', async () => {
|
||||||
const rates: RatesBySource = {};
|
const rates: RatesBySource = {};
|
||||||
rates[ERC20BridgeSource.Native] = [0.4, 0.3, 0.2, 0.1];
|
rates[ERC20BridgeSource.Native] = [0.4, 0.3, 0.2, 0.1];
|
||||||
rates[ERC20BridgeSource.Uniswap] = [0.5, 0.05, 0.05, 0.05];
|
rates[ERC20BridgeSource.UniswapV2] = [0.5, 0.05, 0.05, 0.05];
|
||||||
rates[ERC20BridgeSource.Eth2Dai] = [0.6, 0.05, 0.05, 0.05];
|
rates[ERC20BridgeSource.Eth2Dai] = [0.6, 0.05, 0.05, 0.05];
|
||||||
rates[ERC20BridgeSource.Kyber] = [0, 0, 0, 0]; // unused
|
rates[ERC20BridgeSource.Kyber] = [0, 0, 0, 0]; // unused
|
||||||
replaceSamplerOps({
|
replaceSamplerOps({
|
||||||
@ -459,7 +496,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
const orderSources = improvedOrders.map(o => o.fills[0].source);
|
const orderSources = improvedOrders.map(o => o.fills[0].source);
|
||||||
const expectedSources = [
|
const expectedSources = [
|
||||||
ERC20BridgeSource.Eth2Dai,
|
ERC20BridgeSource.Eth2Dai,
|
||||||
ERC20BridgeSource.Uniswap,
|
ERC20BridgeSource.UniswapV2,
|
||||||
ERC20BridgeSource.Native,
|
ERC20BridgeSource.Native,
|
||||||
ERC20BridgeSource.Native,
|
ERC20BridgeSource.Native,
|
||||||
];
|
];
|
||||||
@ -474,7 +511,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
const nativeFeeRate = 0.06;
|
const nativeFeeRate = 0.06;
|
||||||
const rates: RatesBySource = {
|
const rates: RatesBySource = {
|
||||||
[ERC20BridgeSource.Native]: [1, 0.99, 0.98, 0.97], // Effectively [0.94, 0.93, 0.92, 0.91]
|
[ERC20BridgeSource.Native]: [1, 0.99, 0.98, 0.97], // Effectively [0.94, 0.93, 0.92, 0.91]
|
||||||
[ERC20BridgeSource.Uniswap]: [0.96, 0.1, 0.1, 0.1],
|
[ERC20BridgeSource.UniswapV2]: [0.96, 0.1, 0.1, 0.1],
|
||||||
[ERC20BridgeSource.Eth2Dai]: [0.95, 0.1, 0.1, 0.1],
|
[ERC20BridgeSource.Eth2Dai]: [0.95, 0.1, 0.1, 0.1],
|
||||||
[ERC20BridgeSource.Kyber]: [0.1, 0.1, 0.1, 0.1],
|
[ERC20BridgeSource.Kyber]: [0.1, 0.1, 0.1, 0.1],
|
||||||
};
|
};
|
||||||
@ -495,7 +532,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
const orderSources = improvedOrders.map(o => o.fills[0].source);
|
const orderSources = improvedOrders.map(o => o.fills[0].source);
|
||||||
const expectedSources = [
|
const expectedSources = [
|
||||||
ERC20BridgeSource.Native,
|
ERC20BridgeSource.Native,
|
||||||
ERC20BridgeSource.Uniswap,
|
ERC20BridgeSource.UniswapV2,
|
||||||
ERC20BridgeSource.Eth2Dai,
|
ERC20BridgeSource.Eth2Dai,
|
||||||
ERC20BridgeSource.Native,
|
ERC20BridgeSource.Native,
|
||||||
];
|
];
|
||||||
@ -511,7 +548,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
[ERC20BridgeSource.Kyber]: [0.1, 0.1, 0.1, 0.1],
|
[ERC20BridgeSource.Kyber]: [0.1, 0.1, 0.1, 0.1],
|
||||||
[ERC20BridgeSource.Eth2Dai]: [0.92, 0.1, 0.1, 0.1],
|
[ERC20BridgeSource.Eth2Dai]: [0.92, 0.1, 0.1, 0.1],
|
||||||
// Effectively [0.8, ~0.5, ~0, ~0]
|
// Effectively [0.8, ~0.5, ~0, ~0]
|
||||||
[ERC20BridgeSource.Uniswap]: [1, 0.7, 0.2, 0.2],
|
[ERC20BridgeSource.UniswapV2]: [1, 0.7, 0.2, 0.2],
|
||||||
};
|
};
|
||||||
const feeSchedule = {
|
const feeSchedule = {
|
||||||
[ERC20BridgeSource.Uniswap]: FILL_AMOUNT.div(4)
|
[ERC20BridgeSource.Uniswap]: FILL_AMOUNT.div(4)
|
||||||
@ -531,7 +568,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
const expectedSources = [
|
const expectedSources = [
|
||||||
ERC20BridgeSource.Native,
|
ERC20BridgeSource.Native,
|
||||||
ERC20BridgeSource.Eth2Dai,
|
ERC20BridgeSource.Eth2Dai,
|
||||||
ERC20BridgeSource.Uniswap,
|
ERC20BridgeSource.UniswapV2,
|
||||||
];
|
];
|
||||||
expect(orderSources.sort()).to.deep.eq(expectedSources.sort());
|
expect(orderSources.sort()).to.deep.eq(expectedSources.sort());
|
||||||
});
|
});
|
||||||
@ -540,7 +577,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
const rates: RatesBySource = {
|
const rates: RatesBySource = {
|
||||||
[ERC20BridgeSource.Kyber]: [0, 0, 0, 0], // Won't use
|
[ERC20BridgeSource.Kyber]: [0, 0, 0, 0], // Won't use
|
||||||
[ERC20BridgeSource.Eth2Dai]: [0.5, 0.85, 0.75, 0.75], // Concave
|
[ERC20BridgeSource.Eth2Dai]: [0.5, 0.85, 0.75, 0.75], // Concave
|
||||||
[ERC20BridgeSource.Uniswap]: [0.96, 0.2, 0.1, 0.1],
|
[ERC20BridgeSource.UniswapV2]: [0.96, 0.2, 0.1, 0.1],
|
||||||
[ERC20BridgeSource.Native]: [0.95, 0.2, 0.2, 0.1],
|
[ERC20BridgeSource.Native]: [0.95, 0.2, 0.2, 0.1],
|
||||||
};
|
};
|
||||||
replaceSamplerOps({
|
replaceSamplerOps({
|
||||||
@ -555,7 +592,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
const orderSources = improvedOrders.map(o => o.fills[0].source);
|
const orderSources = improvedOrders.map(o => o.fills[0].source);
|
||||||
const expectedSources = [
|
const expectedSources = [
|
||||||
ERC20BridgeSource.Eth2Dai,
|
ERC20BridgeSource.Eth2Dai,
|
||||||
ERC20BridgeSource.Uniswap,
|
ERC20BridgeSource.UniswapV2,
|
||||||
ERC20BridgeSource.Native,
|
ERC20BridgeSource.Native,
|
||||||
];
|
];
|
||||||
expect(orderSources.sort()).to.deep.eq(expectedSources.sort());
|
expect(orderSources.sort()).to.deep.eq(expectedSources.sort());
|
||||||
@ -564,7 +601,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
it('fallback orders use different sources', async () => {
|
it('fallback orders use different sources', async () => {
|
||||||
const rates: RatesBySource = {};
|
const rates: RatesBySource = {};
|
||||||
rates[ERC20BridgeSource.Native] = [0.9, 0.8, 0.5, 0.5];
|
rates[ERC20BridgeSource.Native] = [0.9, 0.8, 0.5, 0.5];
|
||||||
rates[ERC20BridgeSource.Uniswap] = [0.6, 0.05, 0.01, 0.01];
|
rates[ERC20BridgeSource.UniswapV2] = [0.6, 0.05, 0.01, 0.01];
|
||||||
rates[ERC20BridgeSource.Eth2Dai] = [0.4, 0.3, 0.01, 0.01];
|
rates[ERC20BridgeSource.Eth2Dai] = [0.4, 0.3, 0.01, 0.01];
|
||||||
rates[ERC20BridgeSource.Kyber] = [0.35, 0.2, 0.01, 0.01];
|
rates[ERC20BridgeSource.Kyber] = [0.35, 0.2, 0.01, 0.01];
|
||||||
replaceSamplerOps({
|
replaceSamplerOps({
|
||||||
@ -580,7 +617,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
ERC20BridgeSource.Native,
|
ERC20BridgeSource.Native,
|
||||||
ERC20BridgeSource.Native,
|
ERC20BridgeSource.Native,
|
||||||
ERC20BridgeSource.Native,
|
ERC20BridgeSource.Native,
|
||||||
ERC20BridgeSource.Uniswap,
|
ERC20BridgeSource.UniswapV2,
|
||||||
];
|
];
|
||||||
const secondSources = [ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.Kyber];
|
const secondSources = [ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.Kyber];
|
||||||
expect(orderSources.slice(0, firstSources.length).sort()).to.deep.eq(firstSources.sort());
|
expect(orderSources.slice(0, firstSources.length).sort()).to.deep.eq(firstSources.sort());
|
||||||
@ -590,7 +627,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
it('does not create a fallback if below maxFallbackSlippage', async () => {
|
it('does not create a fallback if below maxFallbackSlippage', async () => {
|
||||||
const rates: RatesBySource = {};
|
const rates: RatesBySource = {};
|
||||||
rates[ERC20BridgeSource.Native] = [1, 1, 0.01, 0.01];
|
rates[ERC20BridgeSource.Native] = [1, 1, 0.01, 0.01];
|
||||||
rates[ERC20BridgeSource.Uniswap] = [1, 1, 0.01, 0.01];
|
rates[ERC20BridgeSource.UniswapV2] = [1, 1, 0.01, 0.01];
|
||||||
rates[ERC20BridgeSource.Eth2Dai] = [0.49, 0.49, 0.49, 0.49];
|
rates[ERC20BridgeSource.Eth2Dai] = [0.49, 0.49, 0.49, 0.49];
|
||||||
rates[ERC20BridgeSource.Kyber] = [0.35, 0.2, 0.01, 0.01];
|
rates[ERC20BridgeSource.Kyber] = [0.35, 0.2, 0.01, 0.01];
|
||||||
replaceSamplerOps({
|
replaceSamplerOps({
|
||||||
@ -602,7 +639,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
{ ...DEFAULT_OPTS, numSamples: 4, allowFallback: true, maxFallbackSlippage: 0.25 },
|
{ ...DEFAULT_OPTS, numSamples: 4, allowFallback: true, maxFallbackSlippage: 0.25 },
|
||||||
);
|
);
|
||||||
const orderSources = improvedOrders.map(o => o.fills[0].source);
|
const orderSources = improvedOrders.map(o => o.fills[0].source);
|
||||||
const firstSources = [ERC20BridgeSource.Native, ERC20BridgeSource.Native, ERC20BridgeSource.Uniswap];
|
const firstSources = [ERC20BridgeSource.Native, ERC20BridgeSource.Native, ERC20BridgeSource.UniswapV2];
|
||||||
const secondSources: ERC20BridgeSource[] = [];
|
const secondSources: ERC20BridgeSource[] = [];
|
||||||
expect(orderSources.slice(0, firstSources.length).sort()).to.deep.eq(firstSources.sort());
|
expect(orderSources.slice(0, firstSources.length).sort()).to.deep.eq(firstSources.sort());
|
||||||
expect(orderSources.slice(firstSources.length).sort()).to.deep.eq(secondSources.sort());
|
expect(orderSources.slice(firstSources.length).sort()).to.deep.eq(secondSources.sort());
|
||||||
@ -666,7 +703,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
|
|
||||||
it('batches contiguous bridge sources', async () => {
|
it('batches contiguous bridge sources', async () => {
|
||||||
const rates: RatesBySource = {};
|
const rates: RatesBySource = {};
|
||||||
rates[ERC20BridgeSource.Uniswap] = [1, 0.01, 0.01, 0.01];
|
rates[ERC20BridgeSource.UniswapV2] = [1, 0.01, 0.01, 0.01];
|
||||||
rates[ERC20BridgeSource.Native] = [0.5, 0.01, 0.01, 0.01];
|
rates[ERC20BridgeSource.Native] = [0.5, 0.01, 0.01, 0.01];
|
||||||
rates[ERC20BridgeSource.Eth2Dai] = [0.49, 0.01, 0.01, 0.01];
|
rates[ERC20BridgeSource.Eth2Dai] = [0.49, 0.01, 0.01, 0.01];
|
||||||
rates[ERC20BridgeSource.CurveUsdcDai] = [0.48, 0.01, 0.01, 0.01];
|
rates[ERC20BridgeSource.CurveUsdcDai] = [0.48, 0.01, 0.01, 0.01];
|
||||||
@ -689,7 +726,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
expect(improvedOrders).to.be.length(3);
|
expect(improvedOrders).to.be.length(3);
|
||||||
const orderFillSources = improvedOrders.map(o => o.fills.map(f => f.source));
|
const orderFillSources = improvedOrders.map(o => o.fills.map(f => f.source));
|
||||||
expect(orderFillSources).to.deep.eq([
|
expect(orderFillSources).to.deep.eq([
|
||||||
[ERC20BridgeSource.Uniswap],
|
[ERC20BridgeSource.UniswapV2],
|
||||||
[ERC20BridgeSource.Native],
|
[ERC20BridgeSource.Native],
|
||||||
[ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.CurveUsdcDai],
|
[ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.CurveUsdcDai],
|
||||||
]);
|
]);
|
||||||
@ -707,7 +744,12 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
sampleDistributionBase: 1,
|
sampleDistributionBase: 1,
|
||||||
bridgeSlippage: 0,
|
bridgeSlippage: 0,
|
||||||
maxFallbackSlippage: 100,
|
maxFallbackSlippage: 100,
|
||||||
excludedSources: [...(Object.keys(DEFAULT_CURVE_OPTS) as ERC20BridgeSource[]), ERC20BridgeSource.Kyber],
|
excludedSources: [
|
||||||
|
...(Object.keys(DEFAULT_CURVE_OPTS) as ERC20BridgeSource[]),
|
||||||
|
ERC20BridgeSource.Kyber,
|
||||||
|
ERC20BridgeSource.Uniswap,
|
||||||
|
ERC20BridgeSource.UniswapV2Eth,
|
||||||
|
],
|
||||||
allowFallback: false,
|
allowFallback: false,
|
||||||
shouldBatchBridgeOrders: false,
|
shouldBatchBridgeOrders: false,
|
||||||
};
|
};
|
||||||
@ -720,9 +762,9 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
const numSamples = _.random(1, 16);
|
const numSamples = _.random(1, 16);
|
||||||
let actualNumSamples = 0;
|
let actualNumSamples = 0;
|
||||||
replaceSamplerOps({
|
replaceSamplerOps({
|
||||||
getBuyQuotes: (sources, makerToken, takerToken, amounts) => {
|
getBuyQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => {
|
||||||
actualNumSamples = amounts.length;
|
actualNumSamples = amounts.length;
|
||||||
return DEFAULT_OPS.getBuyQuotes(sources, makerToken, takerToken, amounts);
|
return DEFAULT_OPS.getBuyQuotes(sources, makerToken, takerToken, amounts, wethAddress);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await marketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, {
|
await marketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, {
|
||||||
@ -735,9 +777,9 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
it('polls all DEXes if `excludedSources` is empty', async () => {
|
it('polls all DEXes if `excludedSources` is empty', async () => {
|
||||||
let sourcesPolled: ERC20BridgeSource[] = [];
|
let sourcesPolled: ERC20BridgeSource[] = [];
|
||||||
replaceSamplerOps({
|
replaceSamplerOps({
|
||||||
getBuyQuotes: (sources, makerToken, takerToken, amounts) => {
|
getBuyQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => {
|
||||||
sourcesPolled = sources.slice();
|
sourcesPolled = sources.slice();
|
||||||
return DEFAULT_OPS.getBuyQuotes(sources, makerToken, takerToken, amounts);
|
return DEFAULT_OPS.getBuyQuotes(sources, makerToken, takerToken, amounts, wethAddress);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await marketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, {
|
await marketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, {
|
||||||
@ -776,9 +818,9 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
const excludedSources = _.sampleSize(SELL_SOURCES, _.random(1, SELL_SOURCES.length));
|
const excludedSources = _.sampleSize(SELL_SOURCES, _.random(1, SELL_SOURCES.length));
|
||||||
let sourcesPolled: ERC20BridgeSource[] = [];
|
let sourcesPolled: ERC20BridgeSource[] = [];
|
||||||
replaceSamplerOps({
|
replaceSamplerOps({
|
||||||
getBuyQuotes: (sources, makerToken, takerToken, amounts) => {
|
getBuyQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => {
|
||||||
sourcesPolled = sources.slice();
|
sourcesPolled = sources.slice();
|
||||||
return DEFAULT_OPS.getBuyQuotes(sources, makerToken, takerToken, amounts);
|
return DEFAULT_OPS.getBuyQuotes(sources, makerToken, takerToken, amounts, wethAddress);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
await marketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, {
|
await marketOperationUtils.getMarketBuyOrdersAsync(ORDERS, FILL_AMOUNT, {
|
||||||
@ -842,7 +884,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
it('can mix convex sources', async () => {
|
it('can mix convex sources', async () => {
|
||||||
const rates: RatesBySource = {};
|
const rates: RatesBySource = {};
|
||||||
rates[ERC20BridgeSource.Native] = [0.4, 0.3, 0.2, 0.1];
|
rates[ERC20BridgeSource.Native] = [0.4, 0.3, 0.2, 0.1];
|
||||||
rates[ERC20BridgeSource.Uniswap] = [0.5, 0.05, 0.05, 0.05];
|
rates[ERC20BridgeSource.UniswapV2] = [0.5, 0.05, 0.05, 0.05];
|
||||||
rates[ERC20BridgeSource.Eth2Dai] = [0.6, 0.05, 0.05, 0.05];
|
rates[ERC20BridgeSource.Eth2Dai] = [0.6, 0.05, 0.05, 0.05];
|
||||||
replaceSamplerOps({
|
replaceSamplerOps({
|
||||||
getBuyQuotes: createGetMultipleBuyQuotesOperationFromRates(rates),
|
getBuyQuotes: createGetMultipleBuyQuotesOperationFromRates(rates),
|
||||||
@ -855,7 +897,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
const orderSources = improvedOrders.map(o => o.fills[0].source);
|
const orderSources = improvedOrders.map(o => o.fills[0].source);
|
||||||
const expectedSources = [
|
const expectedSources = [
|
||||||
ERC20BridgeSource.Eth2Dai,
|
ERC20BridgeSource.Eth2Dai,
|
||||||
ERC20BridgeSource.Uniswap,
|
ERC20BridgeSource.UniswapV2,
|
||||||
ERC20BridgeSource.Native,
|
ERC20BridgeSource.Native,
|
||||||
ERC20BridgeSource.Native,
|
ERC20BridgeSource.Native,
|
||||||
];
|
];
|
||||||
@ -870,7 +912,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
const nativeFeeRate = 0.06;
|
const nativeFeeRate = 0.06;
|
||||||
const rates: RatesBySource = {
|
const rates: RatesBySource = {
|
||||||
[ERC20BridgeSource.Native]: [1, 0.99, 0.98, 0.97], // Effectively [0.94, ~0.93, ~0.92, ~0.91]
|
[ERC20BridgeSource.Native]: [1, 0.99, 0.98, 0.97], // Effectively [0.94, ~0.93, ~0.92, ~0.91]
|
||||||
[ERC20BridgeSource.Uniswap]: [0.96, 0.1, 0.1, 0.1],
|
[ERC20BridgeSource.UniswapV2]: [0.96, 0.1, 0.1, 0.1],
|
||||||
[ERC20BridgeSource.Eth2Dai]: [0.95, 0.1, 0.1, 0.1],
|
[ERC20BridgeSource.Eth2Dai]: [0.95, 0.1, 0.1, 0.1],
|
||||||
[ERC20BridgeSource.Kyber]: [0.1, 0.1, 0.1, 0.1],
|
[ERC20BridgeSource.Kyber]: [0.1, 0.1, 0.1, 0.1],
|
||||||
};
|
};
|
||||||
@ -890,7 +932,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
);
|
);
|
||||||
const orderSources = improvedOrders.map(o => o.fills[0].source);
|
const orderSources = improvedOrders.map(o => o.fills[0].source);
|
||||||
const expectedSources = [
|
const expectedSources = [
|
||||||
ERC20BridgeSource.Uniswap,
|
ERC20BridgeSource.UniswapV2,
|
||||||
ERC20BridgeSource.Eth2Dai,
|
ERC20BridgeSource.Eth2Dai,
|
||||||
ERC20BridgeSource.Native,
|
ERC20BridgeSource.Native,
|
||||||
ERC20BridgeSource.Native,
|
ERC20BridgeSource.Native,
|
||||||
@ -905,11 +947,11 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
const rates: RatesBySource = {
|
const rates: RatesBySource = {
|
||||||
[ERC20BridgeSource.Native]: [0.95, 0.1, 0.1, 0.1],
|
[ERC20BridgeSource.Native]: [0.95, 0.1, 0.1, 0.1],
|
||||||
// Effectively [0.8, ~0.5, ~0, ~0]
|
// Effectively [0.8, ~0.5, ~0, ~0]
|
||||||
[ERC20BridgeSource.Uniswap]: [1, 0.7, 0.2, 0.2],
|
[ERC20BridgeSource.UniswapV2]: [1, 0.7, 0.2, 0.2],
|
||||||
[ERC20BridgeSource.Eth2Dai]: [0.92, 0.1, 0.1, 0.1],
|
[ERC20BridgeSource.Eth2Dai]: [0.92, 0.1, 0.1, 0.1],
|
||||||
};
|
};
|
||||||
const feeSchedule = {
|
const feeSchedule = {
|
||||||
[ERC20BridgeSource.Uniswap]: FILL_AMOUNT.div(4)
|
[ERC20BridgeSource.UniswapV2]: FILL_AMOUNT.div(4)
|
||||||
.times(uniswapFeeRate)
|
.times(uniswapFeeRate)
|
||||||
.dividedToIntegerBy(ETH_TO_TAKER_RATE),
|
.dividedToIntegerBy(ETH_TO_TAKER_RATE),
|
||||||
};
|
};
|
||||||
@ -926,7 +968,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
const expectedSources = [
|
const expectedSources = [
|
||||||
ERC20BridgeSource.Native,
|
ERC20BridgeSource.Native,
|
||||||
ERC20BridgeSource.Eth2Dai,
|
ERC20BridgeSource.Eth2Dai,
|
||||||
ERC20BridgeSource.Uniswap,
|
ERC20BridgeSource.UniswapV2,
|
||||||
];
|
];
|
||||||
expect(orderSources.sort()).to.deep.eq(expectedSources.sort());
|
expect(orderSources.sort()).to.deep.eq(expectedSources.sort());
|
||||||
});
|
});
|
||||||
@ -934,7 +976,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
it('fallback orders use different sources', async () => {
|
it('fallback orders use different sources', async () => {
|
||||||
const rates: RatesBySource = {};
|
const rates: RatesBySource = {};
|
||||||
rates[ERC20BridgeSource.Native] = [0.9, 0.8, 0.5, 0.5];
|
rates[ERC20BridgeSource.Native] = [0.9, 0.8, 0.5, 0.5];
|
||||||
rates[ERC20BridgeSource.Uniswap] = [0.6, 0.05, 0.01, 0.01];
|
rates[ERC20BridgeSource.UniswapV2] = [0.6, 0.05, 0.01, 0.01];
|
||||||
rates[ERC20BridgeSource.Eth2Dai] = [0.4, 0.3, 0.01, 0.01];
|
rates[ERC20BridgeSource.Eth2Dai] = [0.4, 0.3, 0.01, 0.01];
|
||||||
replaceSamplerOps({
|
replaceSamplerOps({
|
||||||
getBuyQuotes: createGetMultipleBuyQuotesOperationFromRates(rates),
|
getBuyQuotes: createGetMultipleBuyQuotesOperationFromRates(rates),
|
||||||
@ -949,7 +991,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
ERC20BridgeSource.Native,
|
ERC20BridgeSource.Native,
|
||||||
ERC20BridgeSource.Native,
|
ERC20BridgeSource.Native,
|
||||||
ERC20BridgeSource.Native,
|
ERC20BridgeSource.Native,
|
||||||
ERC20BridgeSource.Uniswap,
|
ERC20BridgeSource.UniswapV2,
|
||||||
];
|
];
|
||||||
const secondSources = [ERC20BridgeSource.Eth2Dai];
|
const secondSources = [ERC20BridgeSource.Eth2Dai];
|
||||||
expect(orderSources.slice(0, firstSources.length).sort()).to.deep.eq(firstSources.sort());
|
expect(orderSources.slice(0, firstSources.length).sort()).to.deep.eq(firstSources.sort());
|
||||||
@ -959,7 +1001,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
it('does not create a fallback if below maxFallbackSlippage', async () => {
|
it('does not create a fallback if below maxFallbackSlippage', async () => {
|
||||||
const rates: RatesBySource = {};
|
const rates: RatesBySource = {};
|
||||||
rates[ERC20BridgeSource.Native] = [1, 1, 0.01, 0.01];
|
rates[ERC20BridgeSource.Native] = [1, 1, 0.01, 0.01];
|
||||||
rates[ERC20BridgeSource.Uniswap] = [1, 1, 0.01, 0.01];
|
rates[ERC20BridgeSource.UniswapV2] = [1, 1, 0.01, 0.01];
|
||||||
rates[ERC20BridgeSource.Eth2Dai] = [0.49, 0.49, 0.49, 0.49];
|
rates[ERC20BridgeSource.Eth2Dai] = [0.49, 0.49, 0.49, 0.49];
|
||||||
replaceSamplerOps({
|
replaceSamplerOps({
|
||||||
getBuyQuotes: createGetMultipleBuyQuotesOperationFromRates(rates),
|
getBuyQuotes: createGetMultipleBuyQuotesOperationFromRates(rates),
|
||||||
@ -970,7 +1012,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
{ ...DEFAULT_OPTS, numSamples: 4, allowFallback: true, maxFallbackSlippage: 0.25 },
|
{ ...DEFAULT_OPTS, numSamples: 4, allowFallback: true, maxFallbackSlippage: 0.25 },
|
||||||
);
|
);
|
||||||
const orderSources = improvedOrders.map(o => o.fills[0].source);
|
const orderSources = improvedOrders.map(o => o.fills[0].source);
|
||||||
const firstSources = [ERC20BridgeSource.Native, ERC20BridgeSource.Native, ERC20BridgeSource.Uniswap];
|
const firstSources = [ERC20BridgeSource.Native, ERC20BridgeSource.Native, ERC20BridgeSource.UniswapV2];
|
||||||
const secondSources: ERC20BridgeSource[] = [];
|
const secondSources: ERC20BridgeSource[] = [];
|
||||||
expect(orderSources.slice(0, firstSources.length).sort()).to.deep.eq(firstSources.sort());
|
expect(orderSources.slice(0, firstSources.length).sort()).to.deep.eq(firstSources.sort());
|
||||||
expect(orderSources.slice(firstSources.length).sort()).to.deep.eq(secondSources.sort());
|
expect(orderSources.slice(firstSources.length).sort()).to.deep.eq(secondSources.sort());
|
||||||
@ -980,7 +1022,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
const rates: RatesBySource = {};
|
const rates: RatesBySource = {};
|
||||||
rates[ERC20BridgeSource.Native] = [0.5, 0.01, 0.01, 0.01];
|
rates[ERC20BridgeSource.Native] = [0.5, 0.01, 0.01, 0.01];
|
||||||
rates[ERC20BridgeSource.Eth2Dai] = [0.49, 0.01, 0.01, 0.01];
|
rates[ERC20BridgeSource.Eth2Dai] = [0.49, 0.01, 0.01, 0.01];
|
||||||
rates[ERC20BridgeSource.Uniswap] = [0.48, 0.47, 0.01, 0.01];
|
rates[ERC20BridgeSource.UniswapV2] = [0.48, 0.47, 0.01, 0.01];
|
||||||
replaceSamplerOps({
|
replaceSamplerOps({
|
||||||
getBuyQuotes: createGetMultipleBuyQuotesOperationFromRates(rates),
|
getBuyQuotes: createGetMultipleBuyQuotesOperationFromRates(rates),
|
||||||
});
|
});
|
||||||
@ -997,7 +1039,7 @@ describe('MarketOperationUtils tests', () => {
|
|||||||
const orderFillSources = improvedOrders.map(o => o.fills.map(f => f.source));
|
const orderFillSources = improvedOrders.map(o => o.fills.map(f => f.source));
|
||||||
expect(orderFillSources).to.deep.eq([
|
expect(orderFillSources).to.deep.eq([
|
||||||
[ERC20BridgeSource.Native],
|
[ERC20BridgeSource.Native],
|
||||||
[ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.Uniswap],
|
[ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.UniswapV2],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -21,12 +21,14 @@ export type SampleBuysHandler = (
|
|||||||
makerToken: string,
|
makerToken: string,
|
||||||
makerTokenAmounts: BigNumber[],
|
makerTokenAmounts: BigNumber[],
|
||||||
) => SampleResults;
|
) => SampleResults;
|
||||||
|
export type SampleBuysMultihopHandler = (path: string[], takerTokenAmounts: BigNumber[]) => SampleResults;
|
||||||
export type SampleSellsLPHandler = (
|
export type SampleSellsLPHandler = (
|
||||||
registryAddress: string,
|
registryAddress: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
makerToken: string,
|
makerToken: string,
|
||||||
takerTokenAmounts: BigNumber[],
|
takerTokenAmounts: BigNumber[],
|
||||||
) => SampleResults;
|
) => SampleResults;
|
||||||
|
export type SampleSellsMultihopHandler = (path: string[], takerTokenAmounts: BigNumber[]) => SampleResults;
|
||||||
|
|
||||||
const DUMMY_PROVIDER = {
|
const DUMMY_PROVIDER = {
|
||||||
sendAsync: (...args: any[]): any => {
|
sendAsync: (...args: any[]): any => {
|
||||||
@ -41,8 +43,10 @@ interface Handlers {
|
|||||||
sampleSellsFromLiquidityProviderRegistry: SampleSellsLPHandler;
|
sampleSellsFromLiquidityProviderRegistry: SampleSellsLPHandler;
|
||||||
sampleSellsFromEth2Dai: SampleSellsHandler;
|
sampleSellsFromEth2Dai: SampleSellsHandler;
|
||||||
sampleSellsFromUniswap: SampleSellsHandler;
|
sampleSellsFromUniswap: SampleSellsHandler;
|
||||||
|
sampleSellsFromUniswapV2: SampleSellsMultihopHandler;
|
||||||
sampleBuysFromEth2Dai: SampleBuysHandler;
|
sampleBuysFromEth2Dai: SampleBuysHandler;
|
||||||
sampleBuysFromUniswap: SampleBuysHandler;
|
sampleBuysFromUniswap: SampleBuysHandler;
|
||||||
|
sampleBuysFromUniswapV2: SampleBuysMultihopHandler;
|
||||||
sampleBuysFromLiquidityProviderRegistry: SampleSellsLPHandler;
|
sampleBuysFromLiquidityProviderRegistry: SampleSellsLPHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,6 +131,18 @@ export class MockSamplerContract extends IERC20BridgeSamplerContract {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sampleSellsFromUniswapV2(
|
||||||
|
path: string[],
|
||||||
|
takerAssetAmounts: BigNumber[],
|
||||||
|
): ContractFunctionObj<GetOrderFillableAssetAmountResult> {
|
||||||
|
return this._wrapCall(
|
||||||
|
super.sampleSellsFromUniswapV2,
|
||||||
|
this._handlers.sampleSellsFromUniswapV2,
|
||||||
|
path,
|
||||||
|
takerAssetAmounts,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public sampleSellsFromLiquidityProviderRegistry(
|
public sampleSellsFromLiquidityProviderRegistry(
|
||||||
registryAddress: string,
|
registryAddress: string,
|
||||||
takerToken: string,
|
takerToken: string,
|
||||||
@ -171,6 +187,18 @@ export class MockSamplerContract extends IERC20BridgeSamplerContract {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sampleBuysFromUniswapV2(
|
||||||
|
path: string[],
|
||||||
|
makerAssetAmounts: BigNumber[],
|
||||||
|
): ContractFunctionObj<GetOrderFillableAssetAmountResult> {
|
||||||
|
return this._wrapCall(
|
||||||
|
super.sampleBuysFromUniswapV2,
|
||||||
|
this._handlers.sampleBuysFromUniswapV2,
|
||||||
|
path,
|
||||||
|
makerAssetAmounts,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private _callEncodedFunction(callData: string): string {
|
private _callEncodedFunction(callData: string): string {
|
||||||
// tslint:disable-next-line: custom-no-magic-numbers
|
// tslint:disable-next-line: custom-no-magic-numbers
|
||||||
const selector = hexUtils.slice(callData, 0, 4);
|
const selector = hexUtils.slice(callData, 0, 4);
|
||||||
|
@ -57,6 +57,14 @@
|
|||||||
{
|
{
|
||||||
"note": "Redeploy ERC20BridgeSampler on Mainnet using `Kyber.searchBestRate`",
|
"note": "Redeploy ERC20BridgeSampler on Mainnet using `Kyber.searchBestRate`",
|
||||||
"pr": 2575
|
"pr": 2575
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Redeploy ERC20BridgeSampler on Mainnet and Kovan using UniswapV2",
|
||||||
|
"pr": 2599
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Add UniswapV2Bridge address on Mainnet (new field)",
|
||||||
|
"pr": 2599
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -20,7 +20,8 @@
|
|||||||
"devUtils": "0x74134cf88b21383713e096a5ecf59e297dc7f547",
|
"devUtils": "0x74134cf88b21383713e096a5ecf59e297dc7f547",
|
||||||
"erc20BridgeProxy": "0x8ed95d1746bf1e4dab58d8ed4724f1ef95b20db0",
|
"erc20BridgeProxy": "0x8ed95d1746bf1e4dab58d8ed4724f1ef95b20db0",
|
||||||
"uniswapBridge": "0x36691c4f426eb8f42f150ebde43069a31cb080ad",
|
"uniswapBridge": "0x36691c4f426eb8f42f150ebde43069a31cb080ad",
|
||||||
"erc20BridgeSampler": "0xc0154b14cc60a6661171fdc817f759429a57e184",
|
"uniswapV2Bridge": "0xdcd6011f4c6b80e470d9487f5871a0cba7c93f48",
|
||||||
|
"erc20BridgeSampler": "0xdfec429f7d87bd9911211bbb3b8b83df0f37ebc7",
|
||||||
"kyberBridge": "0x1c29670f7a77f1052d30813a0a4f632c78a02610",
|
"kyberBridge": "0x1c29670f7a77f1052d30813a0a4f632c78a02610",
|
||||||
"eth2DaiBridge": "0x991c745401d5b5e469b8c3e2cb02c748f08754f1",
|
"eth2DaiBridge": "0x991c745401d5b5e469b8c3e2cb02c748f08754f1",
|
||||||
"chaiBridge": "0x77c31eba23043b9a72d13470f3a3a311344d7438",
|
"chaiBridge": "0x77c31eba23043b9a72d13470f3a3a311344d7438",
|
||||||
@ -53,6 +54,7 @@
|
|||||||
"stakingProxy": "0xfaabcee42ab6b9c649794ac6c133711071897ee9",
|
"stakingProxy": "0xfaabcee42ab6b9c649794ac6c133711071897ee9",
|
||||||
"erc20BridgeProxy": "0x599b340b5045436a99b1f0c718d30f5a0c8519dd",
|
"erc20BridgeProxy": "0x599b340b5045436a99b1f0c718d30f5a0c8519dd",
|
||||||
"uniswapBridge": "0x0000000000000000000000000000000000000000",
|
"uniswapBridge": "0x0000000000000000000000000000000000000000",
|
||||||
|
"uniswapV2Bridge": "0x0000000000000000000000000000000000000000",
|
||||||
"eth2DaiBridge": "0x0000000000000000000000000000000000000000",
|
"eth2DaiBridge": "0x0000000000000000000000000000000000000000",
|
||||||
"erc20BridgeSampler": "0x0000000000000000000000000000000000000000",
|
"erc20BridgeSampler": "0x0000000000000000000000000000000000000000",
|
||||||
"kyberBridge": "0x0000000000000000000000000000000000000000",
|
"kyberBridge": "0x0000000000000000000000000000000000000000",
|
||||||
@ -86,6 +88,7 @@
|
|||||||
"stakingProxy": "0xc6ad5277ea225ac05e271eb14a7ebb480cd9dd9f",
|
"stakingProxy": "0xc6ad5277ea225ac05e271eb14a7ebb480cd9dd9f",
|
||||||
"erc20BridgeProxy": "0x31b8653642110f17bdb1f719901d7e7d49b08141",
|
"erc20BridgeProxy": "0x31b8653642110f17bdb1f719901d7e7d49b08141",
|
||||||
"uniswapBridge": "0x0000000000000000000000000000000000000000",
|
"uniswapBridge": "0x0000000000000000000000000000000000000000",
|
||||||
|
"uniswapV2Bridge": "0x0000000000000000000000000000000000000000",
|
||||||
"eth2DaiBridge": "0x0000000000000000000000000000000000000000",
|
"eth2DaiBridge": "0x0000000000000000000000000000000000000000",
|
||||||
"erc20BridgeSampler": "0x0000000000000000000000000000000000000000",
|
"erc20BridgeSampler": "0x0000000000000000000000000000000000000000",
|
||||||
"kyberBridge": "0x0000000000000000000000000000000000000000",
|
"kyberBridge": "0x0000000000000000000000000000000000000000",
|
||||||
@ -119,6 +122,7 @@
|
|||||||
"stakingProxy": "0xbab9145f1d57cd4bb0c9aa2d1ece0a5b6e734d34",
|
"stakingProxy": "0xbab9145f1d57cd4bb0c9aa2d1ece0a5b6e734d34",
|
||||||
"erc20BridgeProxy": "0xfb2dd2a1366de37f7241c83d47da58fd503e2c64",
|
"erc20BridgeProxy": "0xfb2dd2a1366de37f7241c83d47da58fd503e2c64",
|
||||||
"uniswapBridge": "0x0e85f89f29998df65402391478e5924700c0079d",
|
"uniswapBridge": "0x0e85f89f29998df65402391478e5924700c0079d",
|
||||||
|
"uniswapV2Bridge": "0x0000000000000000000000000000000000000000",
|
||||||
"eth2DaiBridge": "0x2d47147429b474d2e4f83e658015858a1312ed5b",
|
"eth2DaiBridge": "0x2d47147429b474d2e4f83e658015858a1312ed5b",
|
||||||
"erc20BridgeSampler": "0x26215b52c57317b5ce7380d3e289b51c7d237084",
|
"erc20BridgeSampler": "0x26215b52c57317b5ce7380d3e289b51c7d237084",
|
||||||
"kyberBridge": "0xaecfa25920f892b6eb496e1f6e84037f59da7f44",
|
"kyberBridge": "0xaecfa25920f892b6eb496e1f6e84037f59da7f44",
|
||||||
@ -152,6 +156,7 @@
|
|||||||
"staking": "0x8a063452f7df2614db1bca3a85ef35da40cf0835",
|
"staking": "0x8a063452f7df2614db1bca3a85ef35da40cf0835",
|
||||||
"stakingProxy": "0x59adefa01843c627ba5d6aa350292b4b7ccae67a",
|
"stakingProxy": "0x59adefa01843c627ba5d6aa350292b4b7ccae67a",
|
||||||
"uniswapBridge": "0x0000000000000000000000000000000000000000",
|
"uniswapBridge": "0x0000000000000000000000000000000000000000",
|
||||||
|
"uniswapV2Bridge": "0x0000000000000000000000000000000000000000",
|
||||||
"eth2DaiBridge": "0x0000000000000000000000000000000000000000",
|
"eth2DaiBridge": "0x0000000000000000000000000000000000000000",
|
||||||
"erc20BridgeSampler": "0x2c530e4ecc573f11bd72cf5fdf580d134d25f15f",
|
"erc20BridgeSampler": "0x2c530e4ecc573f11bd72cf5fdf580d134d25f15f",
|
||||||
"kyberBridge": "0x0000000000000000000000000000000000000000",
|
"kyberBridge": "0x0000000000000000000000000000000000000000",
|
||||||
|
@ -22,6 +22,7 @@ export interface ContractAddresses {
|
|||||||
erc20BridgeProxy: string;
|
erc20BridgeProxy: string;
|
||||||
erc20BridgeSampler: string;
|
erc20BridgeSampler: string;
|
||||||
uniswapBridge: string;
|
uniswapBridge: string;
|
||||||
|
uniswapV2Bridge: string;
|
||||||
eth2DaiBridge: string;
|
eth2DaiBridge: string;
|
||||||
kyberBridge: string;
|
kyberBridge: string;
|
||||||
chaiBridge: string;
|
chaiBridge: string;
|
||||||
|
@ -9,6 +9,10 @@
|
|||||||
{
|
{
|
||||||
"note": "Add `ERC20BridgeSampler` deployment",
|
"note": "Add `ERC20BridgeSampler` deployment",
|
||||||
"pr": 2541
|
"pr": 2541
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"note": "Added `UniswapV2Bridge` address on Mainnet",
|
||||||
|
"pr": 2599
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -311,6 +311,7 @@ export async function runMigrationsAsync(
|
|||||||
staking: stakingLogic.address,
|
staking: stakingLogic.address,
|
||||||
stakingProxy: stakingProxy.address,
|
stakingProxy: stakingProxy.address,
|
||||||
uniswapBridge: constants.NULL_ADDRESS,
|
uniswapBridge: constants.NULL_ADDRESS,
|
||||||
|
uniswapV2Bridge: constants.NULL_ADDRESS,
|
||||||
eth2DaiBridge: constants.NULL_ADDRESS,
|
eth2DaiBridge: constants.NULL_ADDRESS,
|
||||||
kyberBridge: constants.NULL_ADDRESS,
|
kyberBridge: constants.NULL_ADDRESS,
|
||||||
erc20BridgeSampler: erc20BridgeSampler.address,
|
erc20BridgeSampler: erc20BridgeSampler.address,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user