Skip to content
This repository has been archived by the owner on Jul 9, 2021. It is now read-only.

asset-swapper: RFQ-T firm quotes #2541

Merged
merged 36 commits into from
Apr 15, 2020
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
3cdccb7
prep asset-swapper: rename variable
feuGeneA Mar 12, 2020
403fb38
asset-swapper: support firm RFQ-T quote requests
feuGeneA Mar 12, 2020
343caa1
migrations: Deploy ERC20BridgeSampler
feuGeneA Mar 26, 2020
0e1572c
migrations: add `yarn publish:private`
feuGeneA Apr 6, 2020
4b5a02c
asset-swapper, migrations: incl. prettier in lint
feuGeneA Mar 13, 2020
5602aac
mk SwapQuoterOpt rfqtTakerApiKeyWhitelist optional
feuGeneA Apr 9, 2020
1670b21
Use NULL_ADDRESS instead of literal
feuGeneA Apr 9, 2020
98fc780
Use map idiom instead of for loop
feuGeneA Apr 9, 2020
37390e0
Use Array.push instead of Array.concat
feuGeneA Apr 9, 2020
aadcf8f
Parallelize RFQ-T with orderbook query
feuGeneA Apr 9, 2020
63bfd23
Pass QuoteRequestor via SwapQuoteOpts not ctor arg
feuGeneA Apr 9, 2020
121d51b
Use try...catch instead of Promise.catch()
feuGeneA Apr 9, 2020
5f23833
rm unused SwapQuoteRequestOpts key enableRfqt
feuGeneA Apr 8, 2020
227676c
Remove unused intentOnFilling method parameter
feuGeneA Apr 9, 2020
93872ad
Push RFQ-T opts to own SwapQuoterOpts subnamespace
feuGeneA Apr 9, 2020
3c795d3
Demote instance member to just constructor a arg
feuGeneA Apr 9, 2020
fa617d2
Demote public member to private
feuGeneA Apr 9, 2020
70add44
Push RFQ-T opts to SwapQuoterReqOpts subnamespace
feuGeneA Apr 9, 2020
5f4778c
Don't throw when RFQ-T client isn't whitelisted
feuGeneA Apr 9, 2020
8cdc05f
Promote max maker response time to a global option
feuGeneA Apr 9, 2020
39c2a75
Promote a closure to a function
feuGeneA Apr 9, 2020
eb5ec58
Add `yarn prettier` script, & call it from `lint`
feuGeneA Apr 9, 2020
264407b
In Opts types, REQUIRE rfqt SUB-options
feuGeneA Apr 9, 2020
0cb5e45
Await Axios response so we don't circumvent catch
feuGeneA Apr 10, 2020
84adbcb
asset-swapper: Mockable axios for QuoteRequestor (#2549)
Apr 11, 2020
d55108a
Eliminate unnecessary `else`
feuGeneA Apr 11, 2020
ccc9e18
Type Axios response with undefined, not void
feuGeneA Apr 11, 2020
bb15f78
Validate maker endpoint responses with JSON Schema
feuGeneA Apr 11, 2020
27ca75d
Clarify parallelization of orderbook & RFQT
feuGeneA Apr 11, 2020
b854fcd
Remove an unnecessary type annotation
feuGeneA Apr 11, 2020
58d6256
Bug fix: RFQ-T orders werent going through sorting
feuGeneA Apr 11, 2020
47ef7ff
RFQ-T: validate assetData & add more tests (#2552)
Apr 15, 2020
aee758e
Fix bug: Stop ignoring default SwapQuoteRequestOps
feuGeneA Apr 14, 2020
3bdfcb8
Update {asset-s,migrat,contract-ad}* CHANGELOGs
feuGeneA Apr 15, 2020
513ddb4
Merge branch 'development' into rfq-t
feuGeneA Apr 15, 2020
1da8f68
migrations: Add independent `yarn prettier` script
feuGeneA Apr 15, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/asset-swapper/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"build": "yarn tsc -b",
"watch": "tsc -w -p tsconfig.json",
"build:ci": "yarn build",
"lint": "tslint --format stylish --project .",
"lint": "tslint --format stylish --project . && yarn prettier",
"prettier": "prettier --check 'src/**/*.{ts,tsx,json,md}' --config ../../.prettierrc",
"fix": "tslint --fix --format stylish --project .",
"test": "yarn run_mocha",
"rebuild_and_test": "run-s clean build test",
Expand Down Expand Up @@ -53,6 +54,7 @@
"@0x/orderbook": "^2.2.5",
"@0x/utils": "^5.4.1",
"@0x/web3-wrapper": "^7.0.7",
"axios": "^0.19.2",
feuGeneA marked this conversation as resolved.
Show resolved Hide resolved
"heartbeats": "^5.0.1",
"lodash": "^4.17.11"
},
Expand Down
10 changes: 10 additions & 0 deletions packages/asset-swapper/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
ForwarderExtensionContractOpts,
OrderPrunerOpts,
OrderPrunerPermittedFeeTypes,
RfqtFirmQuoteRequestOpts,
SwapQuoteExecutionOpts,
SwapQuoteGetOutputOpts,
SwapQuoteRequestOpts,
Expand Down Expand Up @@ -43,6 +44,10 @@ const DEFAULT_SWAP_QUOTER_OPTS: SwapQuoterOpts = {
},
...DEFAULT_ORDER_PRUNER_OPTS,
samplerGasLimit: 250e6,
rfqt: {
takerApiKeyWhitelist: [],
makerEndpoints: [],
},
};

const DEFAULT_FORWARDER_EXTENSION_CONTRACT_OPTS: ForwarderExtensionContractOpts = {
Expand All @@ -61,6 +66,10 @@ const DEFAULT_SWAP_QUOTE_REQUEST_OPTS: SwapQuoteRequestOpts = {
...DEFAULT_GET_MARKET_ORDERS_OPTS,
};

const DEFAULT_RFQT_FIRM_QUOTE_REQUEST_OPTS: RfqtFirmQuoteRequestOpts = {
makerEndpointMaxResponseTimeMs: 1000,
};

export const constants = {
ETH_GAS_STATION_API_BASE_URL,
PROTOCOL_FEE_MULTIPLIER,
Expand All @@ -77,6 +86,7 @@ export const constants = {
DEFAULT_FORWARDER_SWAP_QUOTE_EXECUTE_OPTS,
DEFAULT_SWAP_QUOTE_REQUEST_OPTS,
DEFAULT_PER_PAGE,
DEFAULT_RFQT_FIRM_QUOTE_REQUEST_OPTS,
NULL_ERC20_ASSET_DATA,
PROTOCOL_FEE_UTILS_POLLING_INTERVAL_IN_MS,
MARKET_UTILS_AMOUNT_BUFFER_PERCENTAGE,
Expand Down
3 changes: 3 additions & 0 deletions packages/asset-swapper/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ export {
GetExtensionContractTypeOpts,
LiquidityForTakerMakerAssetDataPair,
MarketBuySwapQuote,
MarketOperation,
MarketSellSwapQuote,
RfqtFirmQuoteRequestOpts,
SwapQuote,
SwapQuoteConsumerBase,
SwapQuoteConsumerOpts,
Expand All @@ -64,3 +66,4 @@ export {
} from './utils/market_operation_utils/types';
export { affiliateFeeUtils } from './utils/affiliate_fee_utils';
export { ProtocolFeeUtils } from './utils/protocol_fee_utils';
export { QuoteRequestor } from './utils/quote_requestor';
41 changes: 35 additions & 6 deletions packages/asset-swapper/src/swap_quoter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { DexOrderSampler } from './utils/market_operation_utils/sampler';
import { orderPrunerUtils } from './utils/order_prune_utils';
import { OrderStateUtils } from './utils/order_state_utils';
import { ProtocolFeeUtils } from './utils/protocol_fee_utils';
import { QuoteRequestor } from './utils/quote_requestor';
import { sortingUtils } from './utils/sorting_utils';
import { SwapQuoteCalculator } from './utils/swap_quote_calculator';

Expand All @@ -42,6 +43,8 @@ export class SwapQuoter {
private readonly _devUtilsContract: DevUtilsContract;
private readonly _marketOperationUtils: MarketOperationUtils;
private readonly _orderStateUtils: OrderStateUtils;
private readonly _quoteRequestor: QuoteRequestor;
private readonly _rfqtTakerApiKeyWhitelist: string[];

/**
* Instantiates a new SwapQuoter instance given existing liquidity in the form of orders and feeOrders.
Expand Down Expand Up @@ -161,10 +164,13 @@ export class SwapQuoter {
this.orderbook = orderbook;
this.expiryBufferMs = expiryBufferMs;
this.permittedOrderFeeTypes = permittedOrderFeeTypes;
this._rfqtTakerApiKeyWhitelist = options.rfqt ? options.rfqt.takerApiKeyWhitelist || [] : [];
this._contractAddresses = options.contractAddresses || getContractAddressesForChainOrThrow(chainId);
this._devUtilsContract = new DevUtilsContract(this._contractAddresses.devUtils, provider);
this._protocolFeeUtils = new ProtocolFeeUtils(constants.PROTOCOL_FEE_UTILS_POLLING_INTERVAL_IN_MS);
this._orderStateUtils = new OrderStateUtils(this._devUtilsContract);
this._quoteRequestor =
options.quoteRequestor || new QuoteRequestor(options.rfqt ? options.rfqt.makerEndpoints || [] : []);
const sampler = new DexOrderSampler(
new IERC20BridgeSamplerContract(this._contractAddresses.erc20BridgeSampler, this.provider, {
gas: samplerGasLimit,
Expand Down Expand Up @@ -523,26 +529,49 @@ export class SwapQuoter {
gasPrice = await this._protocolFeeUtils.getGasPriceEstimationOrThrowAsync();
}
// get the relevant orders for the makerAsset
let prunedOrders = await this._getSignedOrdersAsync(makerAssetData, takerAssetData);
const orderPromises: Array<Promise<SignedOrder[]>> = [
this._getSignedOrdersAsync(makerAssetData, takerAssetData),
];
if (
options.rfqt &&
steveklebanoff marked this conversation as resolved.
Show resolved Hide resolved
options.rfqt.intentOnFilling &&
options.apiKey &&
this._rfqtTakerApiKeyWhitelist.includes(options.apiKey)
) {
if (!options.rfqt.takerAddress || options.rfqt.takerAddress === constants.NULL_ADDRESS) {
throw new Error('RFQ-T requests must specify a taker address');
}
orderPromises.push(
this._quoteRequestor.requestRfqtFirmQuotesAsync(
makerAssetData,
takerAssetData,
assetFillAmount,
marketOperation,
options.apiKey,
options.rfqt.takerAddress,
),
);
}
const orders: SignedOrder[] = ([] as SignedOrder[]).concat(...(await Promise.all(orderPromises)));
feuGeneA marked this conversation as resolved.
Show resolved Hide resolved
// if no native orders, pass in a dummy order for the sampler to have required metadata for sampling
if (prunedOrders.length === 0) {
prunedOrders = [
if (orders.length === 0) {
orders.push(
createDummyOrderForSampler(makerAssetData, takerAssetData, this._contractAddresses.uniswapBridge),
];
);
}

let swapQuote: SwapQuote;

if (marketOperation === MarketOperation.Buy) {
swapQuote = await this._swapQuoteCalculator.calculateMarketBuySwapQuoteAsync(
prunedOrders,
orders,
assetFillAmount,
gasPrice,
calculateSwapQuoteOpts,
);
} else {
swapQuote = await this._swapQuoteCalculator.calculateMarketSellSwapQuoteAsync(
prunedOrders,
orders,
assetFillAmount,
gasPrice,
calculateSwapQuoteOpts,
Expand Down
15 changes: 15 additions & 0 deletions packages/asset-swapper/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';

import { GetMarketOrdersOpts } from './utils/market_operation_utils/types';
import { QuoteRequestor } from './utils/quote_requestor';

/**
* expiryBufferMs: The number of seconds to add when calculating whether an order is expired or not. Defaults to 300s (5m).
Expand Down Expand Up @@ -192,6 +193,11 @@ export interface SwapQuoteOrdersBreakdown {
*/
export interface SwapQuoteRequestOpts extends CalculateSwapQuoteOpts {
gasPrice?: BigNumber;
apiKey?: string;
feuGeneA marked this conversation as resolved.
Show resolved Hide resolved
rfqt?: {
takerAddress: string;
intentOnFilling: boolean;
};
}

/**
Expand All @@ -213,6 +219,11 @@ export interface SwapQuoterOpts extends OrderPrunerOpts {
contractAddresses?: ContractAddresses;
samplerGasLimit?: number;
liquidityProviderRegistryAddress?: string;
rfqt?: {
takerApiKeyWhitelist: string[];
makerEndpoints: string[];
};
quoteRequestor?: QuoteRequestor;
}

/**
Expand Down Expand Up @@ -262,3 +273,7 @@ export enum OrderPrunerPermittedFeeTypes {
MakerDenominatedTakerFee = 'MAKER_DENOMINATED_TAKER_FEE',
TakerDenominatedTakerFee = 'TAKER_DENOMINATED_TAKER_FEE',
}

export interface RfqtFirmQuoteRequestOpts {
makerEndpointMaxResponseTimeMs?: number;
}
100 changes: 100 additions & 0 deletions packages/asset-swapper/src/utils/quote_requestor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { assetDataUtils, SignedOrder } from '@0x/order-utils';
import { ERC20AssetData } from '@0x/types';
import { BigNumber, logUtils } from '@0x/utils';
import Axios, { AxiosResponse } from 'axios';
import * as _ from 'lodash';

import { constants } from '../constants';
import { MarketOperation, RfqtFirmQuoteRequestOpts } from '../types';

/**
* Request quotes from RFQ-T providers
*/

function getTokenAddressOrThrow(assetData: string): string {
const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
if (decodedAssetData.hasOwnProperty('tokenAddress')) {
// type cast necessary here as decodeAssetDataOrThrow returns
// an AssetData object, which doesn't necessarily contain a
// token address. (it could possibly be a StaticCallAssetData,
// which lacks an address.) so we'll just assume it's a token
// here. should be safe, with the enclosing guard condition
// and subsequent error.
// tslint:disable-next-line:no-unnecessary-type-assertion
return (decodedAssetData as ERC20AssetData).tokenAddress;
} else {
throw new Error(`Decoded asset data (${JSON.stringify(decodedAssetData)}) does not contain a token address`);
}
}

export class QuoteRequestor {
private readonly _rfqtMakerEndpoints: string[];

constructor(rfqtMakerEndpoints: string[]) {
this._rfqtMakerEndpoints = rfqtMakerEndpoints;
}

public async requestRfqtFirmQuotesAsync(
makerAssetData: string,
takerAssetData: string,
assetFillAmount: BigNumber,
marketOperation: MarketOperation,
takerApiKey: string,
takerAddress: string,
options?: Partial<RfqtFirmQuoteRequestOpts>,
): Promise<SignedOrder[]> {
const { makerEndpointMaxResponseTimeMs } = _.merge({}, constants.DEFAULT_RFQT_FIRM_QUOTE_REQUEST_OPTS, options);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So you like lodash now, huh? 😆 If you're using it here, would prefer to use flatten as well 🤓

I'm ok leaving as it though ❤️


const buyToken = getTokenAddressOrThrow(makerAssetData);
const sellToken = getTokenAddressOrThrow(takerAssetData);

// create an array of promises for quote responses, using "undefined"
// as a placeholder for failed requests.

const responsesIfDefined: Array<void | AxiosResponse<SignedOrder>> = await Promise.all(
feuGeneA marked this conversation as resolved.
Show resolved Hide resolved
this._rfqtMakerEndpoints.map(async rfqtMakerEndpoint => {
try {
return Axios.get<SignedOrder>(`${rfqtMakerEndpoint}/quote`, {
feuGeneA marked this conversation as resolved.
Show resolved Hide resolved
headers: { '0x-api-key': takerApiKey },
params: {
sellToken,
buyToken,
buyAmount: marketOperation === MarketOperation.Buy ? assetFillAmount.toString() : undefined,
sellAmount:
marketOperation === MarketOperation.Sell ? assetFillAmount.toString() : undefined,
takerAddress,
},
timeout: makerEndpointMaxResponseTimeMs,
});
} catch (err) {
logUtils.warn(
`Failed to get RFQ-T quote from market maker endpoint ${rfqtMakerEndpoint} for API key ${takerApiKey} for taker address ${takerAddress}: ${JSON.stringify(
feuGeneA marked this conversation as resolved.
Show resolved Hide resolved
err,
)}`,
);
return undefined;
}
}),
);

const responses: Array<AxiosResponse<SignedOrder>> = responsesIfDefined.filter(
feuGeneA marked this conversation as resolved.
Show resolved Hide resolved
(respIfDefd): respIfDefd is AxiosResponse<SignedOrder> => respIfDefd !== undefined,
);

const ordersWithStringInts = responses.map(response => response.data); // not yet BigNumber
steveklebanoff marked this conversation as resolved.
Show resolved Hide resolved

const orders: SignedOrder[] = ordersWithStringInts.map(orderWithStringInts => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Find a helper function do this for us. @steveklebanoff ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a feeliing they exist in @0x/connect

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dekz Are you open to exporting typeConverters or orderParsingUtils from the @0x/orderbook package?

https://github.com/0xProject/0x-monorepo/blob/master/packages/connect/src/utils/type_converters.ts#L24

Or is there somewhere else where this is already defined & exported?

return {
...orderWithStringInts,
makerAssetAmount: new BigNumber(orderWithStringInts.makerAssetAmount),
takerAssetAmount: new BigNumber(orderWithStringInts.takerAssetAmount),
makerFee: new BigNumber(orderWithStringInts.makerFee),
takerFee: new BigNumber(orderWithStringInts.takerFee),
expirationTimeSeconds: new BigNumber(orderWithStringInts.expirationTimeSeconds),
salt: new BigNumber(orderWithStringInts.salt),
};
});

return orders;
}
}
2 changes: 1 addition & 1 deletion packages/contract-addresses/addresses.json
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@
"stakingProxy": "0x59adefa01843c627ba5d6aa350292b4b7ccae67a",
"uniswapBridge": "0x0000000000000000000000000000000000000000",
"eth2DaiBridge": "0x0000000000000000000000000000000000000000",
"erc20BridgeSampler": "0x0000000000000000000000000000000000000000",
"erc20BridgeSampler": "0x2c530e4ecc573f11bd72cf5fdf580d134d25f15f",
"kyberBridge": "0x0000000000000000000000000000000000000000",
"chaiBridge": "0x0000000000000000000000000000000000000000",
"dydxBridge": "0x0000000000000000000000000000000000000000",
Expand Down
10 changes: 8 additions & 2 deletions packages/migrations/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"build": "tsc -b",
"build:ci": "yarn build",
"clean": "shx rm -rf lib ${npm_package_config_snapshot_name} ${npm_package_config_snapshot_name}-*.zip",
"lint": "tslint --format stylish --project .",
"lint": "tslint --format stylish --project . && prettier --check 'src/**/*.{ts,tsx,json,md}' --config ../../.prettierrc",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like you agreed to keep prettier as a separate script in the asset-swapper package, can we do the same here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 1da8f68

"fix": "tslint --fix --format stylish --project .",
"test": "yarn run_mocha",
"test:circleci": "yarn test",
Expand All @@ -28,7 +28,8 @@
"build:snapshot:docker": "docker build --tag ${npm_package_config_docker_snapshot_name}:${npm_package_version} --tag ${npm_package_config_docker_snapshot_name}:latest .",
"publish:snapshot": "aws s3 cp ${npm_package_config_snapshot_name}-${npm_package_version}.zip ${npm_package_config_s3_snapshot_bucket} && aws s3 cp ${npm_package_config_s3_snapshot_bucket}/${npm_package_config_snapshot_name}-${npm_package_version}.zip ${npm_package_config_s3_snapshot_bucket}/${npm_package_config_snapshot_name}-latest.zip",
"publish:snapshot:docker": "docker push ${npm_package_config_docker_snapshot_name}:latest && docker push ${npm_package_config_docker_snapshot_name}:${npm_package_version}",
"test_contract_configs": "node ./lib/test_contract_configs.js"
"test_contract_configs": "node ./lib/test_contract_configs.js",
"publish:private": "yarn build && gitpkg publish"
},
"config": {
"s3_snapshot_bucket": "s3://ganache-snapshots.0x.org",
Expand All @@ -42,6 +43,9 @@
"0x-migrate": "bin/0x-migrate.js"
},
"license": "Apache-2.0",
"gitpkg": {
"registry": "git@github.com:0xProject/gitpkg-registry.git"
},
"devDependencies": {
"@0x/dev-utils": "^3.2.1",
"@0x/ts-doc-gen": "^0.0.22",
Expand All @@ -50,6 +54,7 @@
"@types/yargs": "^11.0.0",
"chai": "^4.0.1",
"dirty-chai": "^2.0.1",
"gitpkg": "https://github.com/0xProject/gitpkg.git",
"make-promises-safe": "^1.1.0",
"mocha": "^6.2.0",
"npm-run-all": "^4.1.2",
Expand All @@ -69,6 +74,7 @@
"@0x/contracts-dev-utils": "^1.3.3",
"@0x/contracts-erc1155": "^2.1.5",
"@0x/contracts-erc20": "^3.1.5",
"@0x/contracts-erc20-bridge-sampler": "^1.5.1",
"@0x/contracts-erc721": "^3.1.5",
"@0x/contracts-exchange": "^3.2.5",
"@0x/contracts-exchange-forwarder": "^4.2.5",
Expand Down
15 changes: 14 additions & 1 deletion packages/migrations/src/migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ import {
import { artifacts as devUtilsArtifacts, DevUtilsContract } from '@0x/contracts-dev-utils';
import { artifacts as erc1155Artifacts, ERC1155MintableContract } from '@0x/contracts-erc1155';
import { artifacts as erc20Artifacts, DummyERC20TokenContract, WETH9Contract } from '@0x/contracts-erc20';
import {
artifacts as erc20BridgeSamplerArtifacts,
ERC20BridgeSamplerContract,
} from '@0x/contracts-erc20-bridge-sampler';
import { artifacts as erc721Artifacts, DummyERC721TokenContract } from '@0x/contracts-erc721';
import { artifacts as exchangeArtifacts, ExchangeContract } from '@0x/contracts-exchange';
import { artifacts as forwarderArtifacts, ForwarderContract } from '@0x/contracts-exchange-forwarder';
Expand All @@ -42,6 +46,7 @@ const allArtifacts = {
...exchangeArtifacts,
...forwarderArtifacts,
...stakingArtifacts,
...erc20BridgeSamplerArtifacts,
};

/**
Expand Down Expand Up @@ -277,6 +282,14 @@ export async function runMigrationsAsync(
etherToken.address,
);

const erc20BridgeSampler = await ERC20BridgeSamplerContract.deployFrom0xArtifactAsync(
erc20BridgeSamplerArtifacts.ERC20BridgeSampler,
provider,
txDefaults,
allArtifacts,
devUtils.address,
);

const contractAddresses = {
erc20Proxy: erc20Proxy.address,
erc721Proxy: erc721Proxy.address,
Expand All @@ -300,7 +313,7 @@ export async function runMigrationsAsync(
uniswapBridge: constants.NULL_ADDRESS,
eth2DaiBridge: constants.NULL_ADDRESS,
kyberBridge: constants.NULL_ADDRESS,
erc20BridgeSampler: constants.NULL_ADDRESS,
erc20BridgeSampler: erc20BridgeSampler.address,
chaiBridge: constants.NULL_ADDRESS,
dydxBridge: constants.NULL_ADDRESS,
curveBridge: constants.NULL_ADDRESS,
Expand Down