diff --git a/README.md b/README.md index 9986810a1..cfb7ab62e 100644 --- a/README.md +++ b/README.md @@ -59,19 +59,19 @@ To get a local development version of `0x-api` running: 2. Create an `.env` file and copy the content from the `.env_example` file. Defaults are defined in `config.ts`/`config.js`. The bash environment takes precedence over the `.env` file. If you run `source .env`, changes to the `.env` file will have no effect until you unset the colliding variables. -| Environment Variable | Default | Description | -| ----------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `CHAIN_ID` | Required. No default. | The chain id you'd like your API to run on (e.g: `1` -> mainnet, `42` -> Kovan, `3` -> Ropsten, `1337` -> Ganache). Defaults to `42` in the API, but required for `docker-compose up`. | -| `ETHEREUM_RPC_URL` | Required. No default. | The URL used to issue JSON RPC requests. Use `http://ganache:8545` to use the local ganache instance. | -| `MESH_WEBSOCKET_URI` | Required. Default for dev: `ws://localhost:60557` | The URL pointing to the 0x Mesh node. A default node is spun up in `docker-compose up` | -| `MESH_HTTP_URI` | Optional. Used when syncing the orderbook; defaults to websocket connection if not provided. | The URL pointing to the Mesh node's HTTP JSON-RPC endpoint. A default node is spun up in `docker-compose up` | -| `POSTGRES_URI` | Required. Default for dev: `postgresql://api:api@localhost/api` | A URI of a running postgres instance. By default, the API will create all necessary tables. A default instance is spun up in `docker-compose up` | -| `FEE_RECIPIENT_ADDRESS` | `0x0000000000000000000000000000000000000000` | The Ethereum address which should be specified as the fee recipient in orders your API accepts. | -| `MAKER_FEE_ASSET_DATA` | `0x` | The maker fee token asset data for created 0x orders. | -| `TAKER_FEE_ASSET_DATA` | `0x` | The taker fee token asset data for created 0x orders. | -| `MAKER_FEE_UNIT_AMOUNT` | `0` | The flat maker fee amount you'd like to receive for filled orders hosted by you. | -| `TAKER_FEE_UNIT_AMOUNT` | `0` | The flat taker fee amount you'd like to receive for filled orders hosted by you. | -| `WHITELIST_ALL_TOKENS` | `false` | A boolean determining whether all tokens should be allowed to be posted. | +| Environment Variable | Default | Description | +| ----------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `CHAIN_ID` | Required. No default. | The chain id you'd like your API to run on (e.g: `1` -> mainnet, `42` -> Kovan, `3` -> Ropsten, `1337` -> Ganache). Defaults to `42` in the API, but required for `docker-compose up`. | +| `ETHEREUM_RPC_URL` | Required. No default. | The URL used to issue JSON RPC requests. Use `http://ganache:8545` to use the local ganache instance. | +| `MESH_WEBSOCKET_URI` | Required. Default for dev: `ws://localhost:60557` | The URL pointing to the 0x Mesh node. A default node is spun up in `docker-compose up` | +| `MESH_HTTP_URI` | Optional. No default | The URL pointing to the Mesh node's HTTP JSON-RPC endpoint. Used for syncing the orderbook. If not provided, will fallback to websocket connection. A default Mesh node is spun up in `docker-compose up` | +| `POSTGRES_URI` | Required. Default for dev: `postgresql://api:api@localhost/api` | A URI of a running postgres instance. By default, the API will create all necessary tables. A default instance is spun up in `docker-compose up` | +| `FEE_RECIPIENT_ADDRESS` | `0x0000000000000000000000000000000000000000` | The Ethereum address which should be specified as the fee recipient in orders your API accepts. | +| `MAKER_FEE_ASSET_DATA` | `0x` | The maker fee token asset data for created 0x orders. | +| `TAKER_FEE_ASSET_DATA` | `0x` | The taker fee token asset data for created 0x orders. | +| `MAKER_FEE_UNIT_AMOUNT` | `0` | The flat maker fee amount you'd like to receive for filled orders hosted by you. | +| `TAKER_FEE_UNIT_AMOUNT` | `0` | The flat taker fee amount you'd like to receive for filled orders hosted by you. | +| `WHITELIST_ALL_TOKENS` | `false` | A boolean determining whether all tokens should be allowed to be posted. | 3. Install the dependencies: diff --git a/src/config.ts b/src/config.ts index 04953a7b7..caf9f00af 100644 --- a/src/config.ts +++ b/src/config.ts @@ -40,7 +40,9 @@ export const ETHEREUM_RPC_URL = assertEnvVarType('ETHEREUM_RPC_URL', process.env export const MESH_WEBSOCKET_URI = _.isEmpty(process.env.MESH_WEBSOCKET_URI) ? 'ws://localhost:60557' : assertEnvVarType('MESH_WEBSOCKET_URI', process.env.MESH_WEBSOCKET_URI, EnvVarType.Url); -export const MESH_HTTP_URI = process.env.MESH_HTTP_URI; +export const MESH_HTTP_URI = _.isEmpty(process.env.MESH_HTTP_URI) + ? undefined + : assertEnvVarType('assertEnvVarType', process.env.MESH_HTTP_URI, EnvVarType.Url); // The fee recipient for orders export const FEE_RECIPIENT_ADDRESS = _.isEmpty(process.env.FEE_RECIPIENT_ADDRESS) ? NULL_ADDRESS diff --git a/src/constants.ts b/src/constants.ts index 6e7c59e7c..6f43ad8e7 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -16,7 +16,7 @@ export const ONE_MINUTE_MS = ONE_SECOND_MS * 60; export const TEN_MINUTES_MS = ONE_MINUTE_MS * 10; // The number of orders to post to Mesh at one time -export const MESH_ORDERS_BATCH_SIZE = 300; +export const MESH_ORDERS_BATCH_SIZE = 200; // Swap Quoter export const QUOTE_ORDER_EXPIRATION_BUFFER_MS = ONE_SECOND_MS * 90; // Ignore orders that expire in 90 seconds diff --git a/src/services/order_watcher_service.ts b/src/services/order_watcher_service.ts index c5db6ef23..0fcce00d6 100644 --- a/src/services/order_watcher_service.ts +++ b/src/services/order_watcher_service.ts @@ -24,7 +24,7 @@ export class OrderWatcherService { // cannot validate the order we cannot keep the order around // Mesh websocket fails if there are too many orders, so we use HTTP instead // Validate the local state and notify the order watcher of any missed orders - const { accepted, rejected } = await this._meshClient.addOrdersViaHttpAsync(signedOrders); + const { accepted, rejected } = await this._meshClient.addOrdersAsync(signedOrders); logger.info('OrderWatcherService sync', { accepted: accepted.length, rejected: rejected.length, diff --git a/src/utils/mesh_client.ts b/src/utils/mesh_client.ts index 651d3aa1c..9329e3b1d 100644 --- a/src/utils/mesh_client.ts +++ b/src/utils/mesh_client.ts @@ -7,37 +7,38 @@ import { MESH_ORDERS_BATCH_SIZE } from '../constants'; import { utils } from './utils'; export class MeshClient extends WSClient { - public async addOrdersViaHttpAsync(orders: SignedOrder[], pinned: boolean = false): Promise { - if (_.isEmpty(this.httpURI)) { - return super.addOrdersAsync(orders, pinned); - } else { + public async addOrdersAsync(orders: SignedOrder[], pinned: boolean = false): Promise { + if (_.isEmpty(this.httpURI) || orders.length <= MESH_ORDERS_BATCH_SIZE) { + // send via websocket + // break into chunks because mesh websocket fails when the msg is too big const validationResults: ValidationResults = { accepted: [], rejected: [] }; const chunks = _.chunk(orders, MESH_ORDERS_BATCH_SIZE); chunks.forEach(async chunk => { - // format request payload - const data = { - jsonrpc: '2.0', - id: +new Date(), - method: 'mesh_addOrders', - params: [chunk, { pinned }], - }; - - // send the request - const response = await Axios({ - method: 'post', - url: this.httpURI, - data, - }); - - // validate the response - utils.isValidJsonRpcResponseOrThrow(response.data, data); - const results = response.data.results; - - // concatenate results + const results = await super.addOrdersAsync(chunk, pinned); validationResults.accepted = [...validationResults.accepted, ...results.accepted]; validationResults.rejected = [...validationResults.rejected, ...results.rejected]; }); return validationResults; + } else { + // send via http + // format JSON-RPC request payload + const data = { + jsonrpc: '2.0', + id: +new Date(), + method: 'mesh_addOrders', + params: [orders, { pinned }], + }; + + // send the request + const response = await Axios({ + method: 'post', + url: this.httpURI, + data, + }); + + // validate the response + utils.isValidJsonRpcResponseOrThrow(response.data, data); + return response.data.results; } }