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:
Xianny 2020-06-11 10:23:50 -07:00 committed by GitHub
parent b39189fde3
commit 0fbbabe208
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 384 additions and 63 deletions

View File

@ -649,7 +649,7 @@ contract ERC20BridgeSampler is
}
/// @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.
/// @return makerTokenAmounts Maker amounts bought at each taker token
/// amount.
@ -683,7 +683,7 @@ contract ERC20BridgeSampler is
}
/// @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.
/// @return takerTokenAmounts Taker amounts sold at each maker token
/// amount.

View File

@ -77,6 +77,10 @@
{
"note": "Increase timeout for tests",
"pr": 2587
},
{
"note": "Add support for Uniswap V2",
"pr": 2599
}
]
},

View File

@ -9,6 +9,8 @@ import { ERC20BridgeSource, FakeBuyOpts, GetMarketOrdersOpts } from './types';
*/
export const SELL_SOURCES = [
ERC20BridgeSource.Uniswap,
ERC20BridgeSource.UniswapV2,
ERC20BridgeSource.UniswapV2Eth,
ERC20BridgeSource.Eth2Dai,
ERC20BridgeSource.Kyber,
// All Curve Sources
@ -24,6 +26,8 @@ export const SELL_SOURCES = [
*/
export const BUY_SOURCES = [
ERC20BridgeSource.Uniswap,
ERC20BridgeSource.UniswapV2,
ERC20BridgeSource.UniswapV2Eth,
ERC20BridgeSource.Eth2Dai,
ERC20BridgeSource.Kyber,
// All Curve sources

View File

@ -93,6 +93,7 @@ export class MarketOperationUtils {
makerToken,
this._wethAddress,
ONE_ETHER,
this._wethAddress,
this._liquidityProviderRegistry,
),
// Get sell quotes for taker -> maker.
@ -103,6 +104,7 @@ export class MarketOperationUtils {
makerToken,
takerToken,
getSampleAmounts(takerAmount, _opts.numSamples, _opts.sampleDistributionBase),
this._wethAddress,
this._liquidityProviderRegistry,
),
);
@ -173,6 +175,7 @@ export class MarketOperationUtils {
takerToken,
this._wethAddress,
ONE_ETHER,
this._wethAddress,
this._liquidityProviderRegistry,
),
// Get buy quotes for taker -> maker.
@ -183,6 +186,7 @@ export class MarketOperationUtils {
makerToken,
takerToken,
getSampleAmounts(makerAmount, _opts.numSamples, _opts.sampleDistributionBase),
this._wethAddress,
this._liquidityProviderRegistry,
),
);
@ -248,6 +252,7 @@ export class MarketOperationUtils {
getNativeOrderTokens(orders[0])[1],
this._wethAddress,
ONE_ETHER,
this._wethAddress,
),
),
...batchNativeOrders.map((orders, i) =>
@ -256,6 +261,7 @@ export class MarketOperationUtils {
getNativeOrderTokens(orders[0])[0],
getNativeOrderTokens(orders[0])[1],
[makerAmounts[i]],
this._wethAddress,
),
),
];

View File

@ -5,7 +5,7 @@ import { AbiEncoder, BigNumber } from '@0x/utils';
import { MarketOperation, SignedOrderWithFillableAmounts } from '../../types';
import { RfqtIndicativeQuoteResponse } from '../quote_requestor';
import { getCurveInfo, isCurveSource } from '../source_utils';
import { getCurveInfo } from '../source_utils';
import {
ERC20_PROXY_ID,
@ -181,6 +181,9 @@ function getBridgeAddressFromSource(source: ERC20BridgeSource, opts: CreateOrder
return opts.contractAddresses.kyberBridge;
case ERC20BridgeSource.Uniswap:
return opts.contractAddresses.uniswapBridge;
case ERC20BridgeSource.UniswapV2:
case ERC20BridgeSource.UniswapV2Eth:
return opts.contractAddresses.uniswapV2Bridge;
case ERC20BridgeSource.CurveUsdcDai:
case ERC20BridgeSource.CurveUsdcDaiUsdt:
case ERC20BridgeSource.CurveUsdcDaiUsdtTusd:
@ -203,19 +206,48 @@ function createBridgeOrder(fill: CollapsedFill, opts: CreateOrderFromPathOpts):
const bridgeAddress = getBridgeAddressFromSource(fill.source, opts);
let makerAssetData;
if (isCurveSource(fill.source)) {
const { curveAddress, fromTokenIdx, toTokenIdx, version } = getCurveInfo(fill.source, takerToken, makerToken);
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
makerToken,
bridgeAddress,
createCurveBridgeData(curveAddress, fromTokenIdx, toTokenIdx, version),
);
} else {
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
makerToken,
bridgeAddress,
createBridgeData(takerToken),
);
switch (fill.source) {
case ERC20BridgeSource.CurveUsdcDai:
case ERC20BridgeSource.CurveUsdcDaiUsdt:
case ERC20BridgeSource.CurveUsdcDaiUsdtTusd:
case ERC20BridgeSource.CurveUsdcDaiUsdtBusd:
case ERC20BridgeSource.CurveUsdcDaiUsdtSusd:
const { curveAddress, fromTokenIdx, toTokenIdx, version } = getCurveInfo(
fill.source,
takerToken,
makerToken,
);
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);
return {
@ -298,6 +330,11 @@ function createCurveBridgeData(
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] {
return [
// Maker asset amount.

View File

@ -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(
liquidityProviderRegistryAddress: string,
makerToken: string,
@ -231,6 +255,7 @@ export const samplerOperations = {
makerToken: string,
takerToken: string,
takerFillAmount: BigNumber,
wethAddress: string,
liquidityProviderRegistryAddress?: string | undefined,
): BatchedOperation<BigNumber> {
if (makerToken.toLowerCase() === takerToken.toLowerCase()) {
@ -241,6 +266,7 @@ export const samplerOperations = {
makerToken,
takerToken,
[takerFillAmount],
wethAddress,
liquidityProviderRegistryAddress,
);
return {
@ -297,6 +323,7 @@ export const samplerOperations = {
makerToken: string,
takerToken: string,
takerFillAmounts: BigNumber[],
wethAddress: string,
liquidityProviderRegistryAddress?: string | undefined,
): BatchedOperation<DexSample[][]> {
const subOps = sources
@ -306,6 +333,16 @@ export const samplerOperations = {
batchedOperation = samplerOperations.getEth2DaiSellQuotes(makerToken, takerToken, takerFillAmounts);
} else if (source === ERC20BridgeSource.Uniswap) {
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) {
batchedOperation = samplerOperations.getKyberSellQuotes(makerToken, takerToken, takerFillAmounts);
} else if (isCurveSource(source)) {
@ -366,6 +403,7 @@ export const samplerOperations = {
makerToken: string,
takerToken: string,
makerFillAmounts: BigNumber[],
wethAddress: string,
liquidityProviderRegistryAddress?: string | undefined,
fakeBuyOpts: FakeBuyOpts = DEFAULT_FAKE_BUY_OPTS,
): BatchedOperation<DexSample[][]> {
@ -376,6 +414,16 @@ export const samplerOperations = {
batchedOperation = samplerOperations.getEth2DaiBuyQuotes(makerToken, takerToken, makerFillAmounts);
} else if (source === ERC20BridgeSource.Uniswap) {
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) {
batchedOperation = samplerOperations.getKyberBuyQuotes(
makerToken,

View File

@ -28,6 +28,8 @@ export enum AggregationError {
export enum ERC20BridgeSource {
Native = 'Native',
Uniswap = 'Uniswap',
UniswapV2 = 'Uniswap_V2',
UniswapV2Eth = 'Uniswap_V2_ETH',
Eth2Dai = 'Eth2Dai',
Kyber = 'Kyber',
CurveUsdcDai = 'Curve_USDC_DAI',

View File

@ -1,3 +1,4 @@
import { getContractAddressesForChainOrThrow } from '@0x/contract-addresses';
import {
constants,
expect,
@ -24,6 +25,8 @@ describe('DexSampler tests', () => {
const MAKER_ASSET_DATA = assetDataUtils.encodeERC20AssetData(MAKER_TOKEN);
const TAKER_ASSET_DATA = assetDataUtils.encodeERC20AssetData(TAKER_TOKEN);
const wethAddress = getContractAddressesForChainOrThrow(CHAIN_ID).etherToken;
describe('getSampleAmounts()', () => {
const FILL_AMOUNT = getRandomInteger(1, 1e18);
const NUM_SAMPLES = 16;
@ -160,6 +163,7 @@ describe('DexSampler tests', () => {
expectedMakerToken,
expectedTakerToken,
[toBaseUnitAmount(1000)],
wethAddress,
registry,
),
);
@ -193,6 +197,7 @@ describe('DexSampler tests', () => {
expectedMakerToken,
expectedTakerToken,
[toBaseUnitAmount(1000)],
wethAddress,
registry,
),
);
@ -255,6 +260,28 @@ describe('DexSampler tests', () => {
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 () => {
const expectedTakerToken = randomAddress();
const expectedMakerToken = randomAddress();
@ -310,11 +337,17 @@ describe('DexSampler tests', () => {
it('getSellQuotes()', async () => {
const expectedTakerToken = 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 = {
[ERC20BridgeSource.Kyber]: getRandomFloat(0, 100),
[ERC20BridgeSource.Eth2Dai]: getRandomFloat(0, 100),
[ERC20BridgeSource.Uniswap]: getRandomFloat(0, 100),
[ERC20BridgeSource.UniswapV2]: getRandomFloat(0, 100),
};
const expectedTakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 3);
const sampler = new MockSamplerContract({
@ -336,6 +369,11 @@ describe('DexSampler tests', () => {
expect(fillAmounts).to.deep.eq(expectedTakerFillAmounts);
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 [quotes] = await dexOrderSampler.executeAsync(
@ -344,6 +382,43 @@ describe('DexSampler tests', () => {
expectedMakerToken,
expectedTakerToken,
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);
@ -364,6 +439,7 @@ describe('DexSampler tests', () => {
const ratesBySource: RatesBySource = {
[ERC20BridgeSource.Eth2Dai]: getRandomFloat(0, 100),
[ERC20BridgeSource.Uniswap]: getRandomFloat(0, 100),
[ERC20BridgeSource.UniswapV2]: getRandomFloat(0, 100),
};
const expectedMakerFillAmounts = getSampleAmounts(new BigNumber(100e18), 3);
const sampler = new MockSamplerContract({
@ -379,6 +455,11 @@ describe('DexSampler tests', () => {
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, expectedMakerToken]);
expect(fillAmounts).to.deep.eq(expectedMakerFillAmounts);
return fillAmounts.map(a => a.times(ratesBySource[ERC20BridgeSource.UniswapV2]).integerValue());
},
});
const dexOrderSampler = new DexOrderSampler(sampler);
const [quotes] = await dexOrderSampler.executeAsync(
@ -387,6 +468,56 @@ describe('DexSampler tests', () => {
expectedMakerToken,
expectedTakerToken,
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);

View File

@ -34,6 +34,7 @@ describe('MarketOperationUtils tests', () => {
const ETH2DAI_BRIDGE_ADDRESS = contractAddresses.eth2DaiBridge;
const KYBER_BRIDGE_ADDRESS = contractAddresses.kyberBridge;
const UNISWAP_BRIDGE_ADDRESS = contractAddresses.uniswapBridge;
const UNISWAP_V2_BRIDGE_ADDRESS = contractAddresses.uniswapV2Bridge;
const CURVE_BRIDGE_ADDRESS = contractAddresses.curveBridge;
const MAKER_TOKEN = randomAddress();
@ -89,6 +90,8 @@ describe('MarketOperationUtils tests', () => {
return ERC20BridgeSource.Eth2Dai;
case UNISWAP_BRIDGE_ADDRESS.toLowerCase():
return ERC20BridgeSource.Uniswap;
case UNISWAP_V2_BRIDGE_ADDRESS.toLowerCase():
return ERC20BridgeSource.UniswapV2;
case CURVE_BRIDGE_ADDRESS.toLowerCase():
const curveSource = Object.keys(DEFAULT_CURVE_OPTS).filter(
k => assetData.indexOf(DEFAULT_CURVE_OPTS[k].curveAddress.slice(2)) !== -1,
@ -151,11 +154,18 @@ describe('MarketOperationUtils tests', () => {
makerToken: string,
takerToken: string,
fillAmounts: BigNumber[],
wethAddress: string,
liquidityProviderAddress?: string,
) => DexSample[][];
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]));
};
}
@ -173,17 +183,31 @@ describe('MarketOperationUtils tests', () => {
makerToken: string,
takerToken: string,
fillAmounts: BigNumber[],
wethAddress: string,
liquidityProviderAddress?: string,
) => {
liquidityPoolParams.liquidityProviderAddress = liquidityProviderAddress;
liquidityPoolParams.sources = sources;
return tradeOperation(rates)(sources, makerToken, takerToken, fillAmounts, liquidityProviderAddress);
return tradeOperation(rates)(
sources,
makerToken,
takerToken,
fillAmounts,
wethAddress,
liquidityProviderAddress,
);
};
return [liquidityPoolParams, fn];
}
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))));
};
}
@ -193,6 +217,7 @@ describe('MarketOperationUtils tests', () => {
makerToken: string,
takerToken: string,
fillAmounts: BigNumber[],
wethAddress: string,
liquidityProviderAddress?: string,
) => BigNumber;
@ -203,7 +228,13 @@ describe('MarketOperationUtils tests', () => {
) => string;
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);
};
}
@ -255,6 +286,8 @@ describe('MarketOperationUtils tests', () => {
[ERC20BridgeSource.Eth2Dai]: createDecreasingRates(NUM_SAMPLES),
[ERC20BridgeSource.Kyber]: 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.CurveUsdcDaiUsdt]: _.times(NUM_SAMPLES, () => 0),
[ERC20BridgeSource.CurveUsdcDaiUsdtTusd]: _.times(NUM_SAMPLES, () => 0),
@ -310,7 +343,11 @@ describe('MarketOperationUtils tests', () => {
sampleDistributionBase: 1,
bridgeSlippage: 0,
maxFallbackSlippage: 100,
excludedSources: Object.keys(DEFAULT_CURVE_OPTS) as ERC20BridgeSource[],
excludedSources: [
ERC20BridgeSource.Uniswap,
ERC20BridgeSource.UniswapV2Eth,
...(Object.keys(DEFAULT_CURVE_OPTS) as ERC20BridgeSource[]),
],
allowFallback: false,
shouldBatchBridgeOrders: false,
};
@ -323,9 +360,9 @@ describe('MarketOperationUtils tests', () => {
const numSamples = _.random(1, NUM_SAMPLES);
let actualNumSamples = 0;
replaceSamplerOps({
getSellQuotes: (sources, makerToken, takerToken, amounts) => {
getSellQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => {
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, {
@ -338,9 +375,9 @@ describe('MarketOperationUtils tests', () => {
it('polls all DEXes if `excludedSources` is empty', async () => {
let sourcesPolled: ERC20BridgeSource[] = [];
replaceSamplerOps({
getSellQuotes: (sources, makerToken, takerToken, amounts) => {
getSellQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => {
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, {
@ -379,9 +416,9 @@ describe('MarketOperationUtils tests', () => {
const excludedSources = _.sampleSize(SELL_SOURCES, _.random(1, SELL_SOURCES.length));
let sourcesPolled: ERC20BridgeSource[] = [];
replaceSamplerOps({
getSellQuotes: (sources, makerToken, takerToken, amounts) => {
getSellQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => {
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, {
@ -445,7 +482,7 @@ describe('MarketOperationUtils tests', () => {
it('can mix convex sources', async () => {
const rates: RatesBySource = {};
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.Kyber] = [0, 0, 0, 0]; // unused
replaceSamplerOps({
@ -459,7 +496,7 @@ describe('MarketOperationUtils tests', () => {
const orderSources = improvedOrders.map(o => o.fills[0].source);
const expectedSources = [
ERC20BridgeSource.Eth2Dai,
ERC20BridgeSource.Uniswap,
ERC20BridgeSource.UniswapV2,
ERC20BridgeSource.Native,
ERC20BridgeSource.Native,
];
@ -474,7 +511,7 @@ describe('MarketOperationUtils tests', () => {
const nativeFeeRate = 0.06;
const rates: RatesBySource = {
[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.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 expectedSources = [
ERC20BridgeSource.Native,
ERC20BridgeSource.Uniswap,
ERC20BridgeSource.UniswapV2,
ERC20BridgeSource.Eth2Dai,
ERC20BridgeSource.Native,
];
@ -511,7 +548,7 @@ describe('MarketOperationUtils tests', () => {
[ERC20BridgeSource.Kyber]: [0.1, 0.1, 0.1, 0.1],
[ERC20BridgeSource.Eth2Dai]: [0.92, 0.1, 0.1, 0.1],
// 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 = {
[ERC20BridgeSource.Uniswap]: FILL_AMOUNT.div(4)
@ -531,7 +568,7 @@ describe('MarketOperationUtils tests', () => {
const expectedSources = [
ERC20BridgeSource.Native,
ERC20BridgeSource.Eth2Dai,
ERC20BridgeSource.Uniswap,
ERC20BridgeSource.UniswapV2,
];
expect(orderSources.sort()).to.deep.eq(expectedSources.sort());
});
@ -540,7 +577,7 @@ describe('MarketOperationUtils tests', () => {
const rates: RatesBySource = {
[ERC20BridgeSource.Kyber]: [0, 0, 0, 0], // Won't use
[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],
};
replaceSamplerOps({
@ -555,7 +592,7 @@ describe('MarketOperationUtils tests', () => {
const orderSources = improvedOrders.map(o => o.fills[0].source);
const expectedSources = [
ERC20BridgeSource.Eth2Dai,
ERC20BridgeSource.Uniswap,
ERC20BridgeSource.UniswapV2,
ERC20BridgeSource.Native,
];
expect(orderSources.sort()).to.deep.eq(expectedSources.sort());
@ -564,7 +601,7 @@ describe('MarketOperationUtils tests', () => {
it('fallback orders use different sources', async () => {
const rates: RatesBySource = {};
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.Kyber] = [0.35, 0.2, 0.01, 0.01];
replaceSamplerOps({
@ -580,7 +617,7 @@ describe('MarketOperationUtils tests', () => {
ERC20BridgeSource.Native,
ERC20BridgeSource.Native,
ERC20BridgeSource.Native,
ERC20BridgeSource.Uniswap,
ERC20BridgeSource.UniswapV2,
];
const secondSources = [ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.Kyber];
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 () => {
const rates: RatesBySource = {};
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.Kyber] = [0.35, 0.2, 0.01, 0.01];
replaceSamplerOps({
@ -602,7 +639,7 @@ describe('MarketOperationUtils tests', () => {
{ ...DEFAULT_OPTS, numSamples: 4, allowFallback: true, maxFallbackSlippage: 0.25 },
);
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[] = [];
expect(orderSources.slice(0, firstSources.length).sort()).to.deep.eq(firstSources.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 () => {
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.Eth2Dai] = [0.49, 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);
const orderFillSources = improvedOrders.map(o => o.fills.map(f => f.source));
expect(orderFillSources).to.deep.eq([
[ERC20BridgeSource.Uniswap],
[ERC20BridgeSource.UniswapV2],
[ERC20BridgeSource.Native],
[ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.CurveUsdcDai],
]);
@ -707,7 +744,12 @@ describe('MarketOperationUtils tests', () => {
sampleDistributionBase: 1,
bridgeSlippage: 0,
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,
shouldBatchBridgeOrders: false,
};
@ -720,9 +762,9 @@ describe('MarketOperationUtils tests', () => {
const numSamples = _.random(1, 16);
let actualNumSamples = 0;
replaceSamplerOps({
getBuyQuotes: (sources, makerToken, takerToken, amounts) => {
getBuyQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => {
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, {
@ -735,9 +777,9 @@ describe('MarketOperationUtils tests', () => {
it('polls all DEXes if `excludedSources` is empty', async () => {
let sourcesPolled: ERC20BridgeSource[] = [];
replaceSamplerOps({
getBuyQuotes: (sources, makerToken, takerToken, amounts) => {
getBuyQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => {
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, {
@ -776,9 +818,9 @@ describe('MarketOperationUtils tests', () => {
const excludedSources = _.sampleSize(SELL_SOURCES, _.random(1, SELL_SOURCES.length));
let sourcesPolled: ERC20BridgeSource[] = [];
replaceSamplerOps({
getBuyQuotes: (sources, makerToken, takerToken, amounts) => {
getBuyQuotes: (sources, makerToken, takerToken, amounts, wethAddress) => {
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, {
@ -842,7 +884,7 @@ describe('MarketOperationUtils tests', () => {
it('can mix convex sources', async () => {
const rates: RatesBySource = {};
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];
replaceSamplerOps({
getBuyQuotes: createGetMultipleBuyQuotesOperationFromRates(rates),
@ -855,7 +897,7 @@ describe('MarketOperationUtils tests', () => {
const orderSources = improvedOrders.map(o => o.fills[0].source);
const expectedSources = [
ERC20BridgeSource.Eth2Dai,
ERC20BridgeSource.Uniswap,
ERC20BridgeSource.UniswapV2,
ERC20BridgeSource.Native,
ERC20BridgeSource.Native,
];
@ -870,7 +912,7 @@ describe('MarketOperationUtils tests', () => {
const nativeFeeRate = 0.06;
const rates: RatesBySource = {
[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.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 expectedSources = [
ERC20BridgeSource.Uniswap,
ERC20BridgeSource.UniswapV2,
ERC20BridgeSource.Eth2Dai,
ERC20BridgeSource.Native,
ERC20BridgeSource.Native,
@ -905,11 +947,11 @@ describe('MarketOperationUtils tests', () => {
const rates: RatesBySource = {
[ERC20BridgeSource.Native]: [0.95, 0.1, 0.1, 0.1],
// 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],
};
const feeSchedule = {
[ERC20BridgeSource.Uniswap]: FILL_AMOUNT.div(4)
[ERC20BridgeSource.UniswapV2]: FILL_AMOUNT.div(4)
.times(uniswapFeeRate)
.dividedToIntegerBy(ETH_TO_TAKER_RATE),
};
@ -926,7 +968,7 @@ describe('MarketOperationUtils tests', () => {
const expectedSources = [
ERC20BridgeSource.Native,
ERC20BridgeSource.Eth2Dai,
ERC20BridgeSource.Uniswap,
ERC20BridgeSource.UniswapV2,
];
expect(orderSources.sort()).to.deep.eq(expectedSources.sort());
});
@ -934,7 +976,7 @@ describe('MarketOperationUtils tests', () => {
it('fallback orders use different sources', async () => {
const rates: RatesBySource = {};
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];
replaceSamplerOps({
getBuyQuotes: createGetMultipleBuyQuotesOperationFromRates(rates),
@ -949,7 +991,7 @@ describe('MarketOperationUtils tests', () => {
ERC20BridgeSource.Native,
ERC20BridgeSource.Native,
ERC20BridgeSource.Native,
ERC20BridgeSource.Uniswap,
ERC20BridgeSource.UniswapV2,
];
const secondSources = [ERC20BridgeSource.Eth2Dai];
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 () => {
const rates: RatesBySource = {};
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];
replaceSamplerOps({
getBuyQuotes: createGetMultipleBuyQuotesOperationFromRates(rates),
@ -970,7 +1012,7 @@ describe('MarketOperationUtils tests', () => {
{ ...DEFAULT_OPTS, numSamples: 4, allowFallback: true, maxFallbackSlippage: 0.25 },
);
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[] = [];
expect(orderSources.slice(0, firstSources.length).sort()).to.deep.eq(firstSources.sort());
expect(orderSources.slice(firstSources.length).sort()).to.deep.eq(secondSources.sort());
@ -980,7 +1022,7 @@ describe('MarketOperationUtils tests', () => {
const rates: RatesBySource = {};
rates[ERC20BridgeSource.Native] = [0.5, 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({
getBuyQuotes: createGetMultipleBuyQuotesOperationFromRates(rates),
});
@ -997,7 +1039,7 @@ describe('MarketOperationUtils tests', () => {
const orderFillSources = improvedOrders.map(o => o.fills.map(f => f.source));
expect(orderFillSources).to.deep.eq([
[ERC20BridgeSource.Native],
[ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.Uniswap],
[ERC20BridgeSource.Eth2Dai, ERC20BridgeSource.UniswapV2],
]);
});
});

View File

@ -21,12 +21,14 @@ export type SampleBuysHandler = (
makerToken: string,
makerTokenAmounts: BigNumber[],
) => SampleResults;
export type SampleBuysMultihopHandler = (path: string[], takerTokenAmounts: BigNumber[]) => SampleResults;
export type SampleSellsLPHandler = (
registryAddress: string,
takerToken: string,
makerToken: string,
takerTokenAmounts: BigNumber[],
) => SampleResults;
export type SampleSellsMultihopHandler = (path: string[], takerTokenAmounts: BigNumber[]) => SampleResults;
const DUMMY_PROVIDER = {
sendAsync: (...args: any[]): any => {
@ -41,8 +43,10 @@ interface Handlers {
sampleSellsFromLiquidityProviderRegistry: SampleSellsLPHandler;
sampleSellsFromEth2Dai: SampleSellsHandler;
sampleSellsFromUniswap: SampleSellsHandler;
sampleSellsFromUniswapV2: SampleSellsMultihopHandler;
sampleBuysFromEth2Dai: SampleBuysHandler;
sampleBuysFromUniswap: SampleBuysHandler;
sampleBuysFromUniswapV2: SampleBuysMultihopHandler;
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(
registryAddress: 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 {
// tslint:disable-next-line: custom-no-magic-numbers
const selector = hexUtils.slice(callData, 0, 4);

View File

@ -57,6 +57,14 @@
{
"note": "Redeploy ERC20BridgeSampler on Mainnet using `Kyber.searchBestRate`",
"pr": 2575
},
{
"note": "Redeploy ERC20BridgeSampler on Mainnet and Kovan using UniswapV2",
"pr": 2599
},
{
"note": "Add UniswapV2Bridge address on Mainnet (new field)",
"pr": 2599
}
]
},

View File

@ -20,7 +20,8 @@
"devUtils": "0x74134cf88b21383713e096a5ecf59e297dc7f547",
"erc20BridgeProxy": "0x8ed95d1746bf1e4dab58d8ed4724f1ef95b20db0",
"uniswapBridge": "0x36691c4f426eb8f42f150ebde43069a31cb080ad",
"erc20BridgeSampler": "0xc0154b14cc60a6661171fdc817f759429a57e184",
"uniswapV2Bridge": "0xdcd6011f4c6b80e470d9487f5871a0cba7c93f48",
"erc20BridgeSampler": "0xdfec429f7d87bd9911211bbb3b8b83df0f37ebc7",
"kyberBridge": "0x1c29670f7a77f1052d30813a0a4f632c78a02610",
"eth2DaiBridge": "0x991c745401d5b5e469b8c3e2cb02c748f08754f1",
"chaiBridge": "0x77c31eba23043b9a72d13470f3a3a311344d7438",
@ -53,6 +54,7 @@
"stakingProxy": "0xfaabcee42ab6b9c649794ac6c133711071897ee9",
"erc20BridgeProxy": "0x599b340b5045436a99b1f0c718d30f5a0c8519dd",
"uniswapBridge": "0x0000000000000000000000000000000000000000",
"uniswapV2Bridge": "0x0000000000000000000000000000000000000000",
"eth2DaiBridge": "0x0000000000000000000000000000000000000000",
"erc20BridgeSampler": "0x0000000000000000000000000000000000000000",
"kyberBridge": "0x0000000000000000000000000000000000000000",
@ -86,6 +88,7 @@
"stakingProxy": "0xc6ad5277ea225ac05e271eb14a7ebb480cd9dd9f",
"erc20BridgeProxy": "0x31b8653642110f17bdb1f719901d7e7d49b08141",
"uniswapBridge": "0x0000000000000000000000000000000000000000",
"uniswapV2Bridge": "0x0000000000000000000000000000000000000000",
"eth2DaiBridge": "0x0000000000000000000000000000000000000000",
"erc20BridgeSampler": "0x0000000000000000000000000000000000000000",
"kyberBridge": "0x0000000000000000000000000000000000000000",
@ -119,6 +122,7 @@
"stakingProxy": "0xbab9145f1d57cd4bb0c9aa2d1ece0a5b6e734d34",
"erc20BridgeProxy": "0xfb2dd2a1366de37f7241c83d47da58fd503e2c64",
"uniswapBridge": "0x0e85f89f29998df65402391478e5924700c0079d",
"uniswapV2Bridge": "0x0000000000000000000000000000000000000000",
"eth2DaiBridge": "0x2d47147429b474d2e4f83e658015858a1312ed5b",
"erc20BridgeSampler": "0x26215b52c57317b5ce7380d3e289b51c7d237084",
"kyberBridge": "0xaecfa25920f892b6eb496e1f6e84037f59da7f44",
@ -152,6 +156,7 @@
"staking": "0x8a063452f7df2614db1bca3a85ef35da40cf0835",
"stakingProxy": "0x59adefa01843c627ba5d6aa350292b4b7ccae67a",
"uniswapBridge": "0x0000000000000000000000000000000000000000",
"uniswapV2Bridge": "0x0000000000000000000000000000000000000000",
"eth2DaiBridge": "0x0000000000000000000000000000000000000000",
"erc20BridgeSampler": "0x2c530e4ecc573f11bd72cf5fdf580d134d25f15f",
"kyberBridge": "0x0000000000000000000000000000000000000000",

View File

@ -22,6 +22,7 @@ export interface ContractAddresses {
erc20BridgeProxy: string;
erc20BridgeSampler: string;
uniswapBridge: string;
uniswapV2Bridge: string;
eth2DaiBridge: string;
kyberBridge: string;
chaiBridge: string;

View File

@ -9,6 +9,10 @@
{
"note": "Add `ERC20BridgeSampler` deployment",
"pr": 2541
},
{
"note": "Added `UniswapV2Bridge` address on Mainnet",
"pr": 2599
}
]
},

View File

@ -311,6 +311,7 @@ export async function runMigrationsAsync(
staking: stakingLogic.address,
stakingProxy: stakingProxy.address,
uniswapBridge: constants.NULL_ADDRESS,
uniswapV2Bridge: constants.NULL_ADDRESS,
eth2DaiBridge: constants.NULL_ADDRESS,
kyberBridge: constants.NULL_ADDRESS,
erc20BridgeSampler: erc20BridgeSampler.address,