aboutsummaryrefslogtreecommitdiffstats
path: root/packages/order-watcher
diff options
context:
space:
mode:
authorHsuan Lee <hsuan@cobinhood.com>2019-01-19 18:42:04 +0800
committerHsuan Lee <hsuan@cobinhood.com>2019-01-19 18:42:04 +0800
commit7ae38906926dc09bc10670c361af0d2bf0050426 (patch)
tree5fb10ae366b987db09e4ddb4bc3ba0f75404ad08 /packages/order-watcher
parentb5fd3c72a08aaa6957917d74c333387a16edf66b (diff)
downloaddexon-sol-tools-7ae38906926dc09bc10670c361af0d2bf0050426.tar
dexon-sol-tools-7ae38906926dc09bc10670c361af0d2bf0050426.tar.gz
dexon-sol-tools-7ae38906926dc09bc10670c361af0d2bf0050426.tar.bz2
dexon-sol-tools-7ae38906926dc09bc10670c361af0d2bf0050426.tar.lz
dexon-sol-tools-7ae38906926dc09bc10670c361af0d2bf0050426.tar.xz
dexon-sol-tools-7ae38906926dc09bc10670c361af0d2bf0050426.tar.zst
dexon-sol-tools-7ae38906926dc09bc10670c361af0d2bf0050426.zip
Update dependency packages
Diffstat (limited to 'packages/order-watcher')
-rw-r--r--packages/order-watcher/.npmignore9
-rw-r--r--packages/order-watcher/CHANGELOG.json385
-rw-r--r--packages/order-watcher/CHANGELOG.md162
-rw-r--r--packages/order-watcher/Dockerfile13
-rw-r--r--packages/order-watcher/README.md167
-rw-r--r--packages/order-watcher/coverage/.gitkeep0
-rw-r--r--packages/order-watcher/package.json89
-rw-r--r--packages/order-watcher/src/index.ts25
-rw-r--r--packages/order-watcher/src/order_watcher/collision_resistant_abi_decoder.ts54
-rw-r--r--packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts243
-rw-r--r--packages/order-watcher/src/order_watcher/event_watcher.ts158
-rw-r--r--packages/order-watcher/src/order_watcher/expiration_watcher.ts89
-rw-r--r--packages/order-watcher/src/order_watcher/order_watcher.ts490
-rw-r--r--packages/order-watcher/src/order_watcher/order_watcher_web_socket_server.ts200
-rw-r--r--packages/order-watcher/src/schemas/order_watcher_partial_config_schema.ts13
-rw-r--r--packages/order-watcher/src/server.ts44
-rw-r--r--packages/order-watcher/src/types.ts97
-rw-r--r--packages/order-watcher/src/utils/assert.ts23
-rw-r--r--packages/order-watcher/src/utils/utils.ts11
-rw-r--r--packages/order-watcher/test/expiration_watcher_test.ts199
-rw-r--r--packages/order-watcher/test/global_hooks.ts6
-rw-r--r--packages/order-watcher/test/order_watcher_test.ts887
-rw-r--r--packages/order-watcher/test/order_watcher_web_socket_server_test.ts312
-rw-r--r--packages/order-watcher/test/utils/chai_setup.ts13
-rw-r--r--packages/order-watcher/test/utils/constants.ts5
-rw-r--r--packages/order-watcher/test/utils/migrate.ts18
-rw-r--r--packages/order-watcher/test/utils/web3_wrapper.ts8
-rw-r--r--packages/order-watcher/tsconfig.json8
-rw-r--r--packages/order-watcher/tslint.json6
-rw-r--r--packages/order-watcher/typedoc-tsconfig.json7
30 files changed, 0 insertions, 3741 deletions
diff --git a/packages/order-watcher/.npmignore b/packages/order-watcher/.npmignore
deleted file mode 100644
index ac4ab11f2..000000000
--- a/packages/order-watcher/.npmignore
+++ /dev/null
@@ -1,9 +0,0 @@
-.*
-tsconfig.json
-webpack.config.js
-yarn-error.log
-test/
-/src/
-/_bundles/
-/generated_docs/
-/scripts/
diff --git a/packages/order-watcher/CHANGELOG.json b/packages/order-watcher/CHANGELOG.json
deleted file mode 100644
index 585bb48e6..000000000
--- a/packages/order-watcher/CHANGELOG.json
+++ /dev/null
@@ -1,385 +0,0 @@
-[
- {
- "version": "3.0.0",
- "changes": [
- {
- "note": "Upgrade the bignumber.js to v8.0.2",
- "pr": 1517
- }
- ]
- },
- {
- "timestamp": 1547747677,
- "version": "2.4.3",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ]
- },
- {
- "timestamp": 1547561734,
- "version": "2.4.2",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ]
- },
- {
- "timestamp": 1547225310,
- "version": "2.4.1",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ]
- },
- {
- "version": "2.4.0",
- "changes": [
- {
- "note": "Add support for `MultiAssetProxy`",
- "pr": 1363
- }
- ],
- "timestamp": 1547040760
- },
- {
- "version": "2.3.0",
- "changes": [
- {
- "note": "Added a WebSocket interface to OrderWatcher so that it can be used by a client written in any language",
- "pr": 1427
- }
- ]
- },
- {
- "version": "2.2.8",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ],
- "timestamp": 1544739608
- },
- {
- "version": "2.2.7",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ],
- "timestamp": 1544570656
- },
- {
- "timestamp": 1543401373,
- "version": "2.2.6",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ]
- },
- {
- "timestamp": 1542821676,
- "version": "2.2.5",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ]
- },
- {
- "version": "2.2.4",
- "changes": [
- {
- "note": "Fix the bug when order watcher was throwing an error on order removal when maker token was ZRX",
- "pr": 1259
- }
- ],
- "timestamp": 1542208198
- },
- {
- "version": "2.2.3",
- "changes": [
- {
- "note": "Start jsonRpcRequestId at 1, not 0 as 0 breaks the web3.js websocket RPC provider",
- "pr": 1227
- },
- {
- "note": "Fix the bug when order watcher was trying to convert undefined to an object in case of CancelUpTo event"
- }
- ],
- "timestamp": 1542134075
- },
- {
- "timestamp": 1542028948,
- "version": "2.2.2",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ]
- },
- {
- "version": "2.2.1",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ],
- "timestamp": 1541740904
- },
- {
- "version": "2.2.0",
- "changes": [
- {
- "note": "Added getStats function and returns a Stats object",
- "pr": 1118
- },
- {
- "note": "Updated to use new modularized artifacts and the latest version of @0xproject/contract-wrappers. Constructor has a new optional `contractAddresses` parameter.",
- "pr": 1105
- }
- ],
- "timestamp": 1539871071
- },
- {
- "version": "2.1.1",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ],
- "timestamp": 1538693146
- },
- {
- "version": "2.1.0",
- "changes": [
- {
- "note": "Export ExpirationWatcher",
- "pr": 1097
- }
- ],
- "timestamp": 1538157789
- },
- {
- "version": "2.0.0",
- "changes": [
- {
- "note": "Fixes dropped events issue by fetching logs by blockHash instead of blockNumber. Support for fetching by blockHash was added in Geth > v1.8.13 and Parity > v2.1.0. Infura works too.",
- "pr": 1080
- },
- {
- "note": "Fix misunderstanding about blockstream interface callbacks and pass the raw JSON RPC responses to it",
- "pr": 1080
- },
- {
- "note": "Add `transactionHash` to `OrderState` emitted by `OrderWatcher` subscriptions if the order's state change originated from a transaction.",
- "pr": 1087
- }
- ],
- "timestamp": 1537907159
- },
- {
- "version": "1.0.5",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ],
- "timestamp": 1537875740
- },
- {
- "version": "1.0.4",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ],
- "timestamp": 1537541580
- },
- {
- "version": "1.0.3",
- "changes": [
- {
- "note": "Drastically reduce the bundle size by removing unused parts of included contract artifacts."
- }
- ],
- "timestamp": 1537369748
- },
- {
- "version": "1.0.2",
- "changes": [
- {
- "note": "Add ZRX & WETH mainnet contract addresses into the included artifacts"
- }
- ],
- "timestamp": 1537265493
- },
- {
- "timestamp": 1536142250,
- "version": "1.0.1",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ]
- },
- {
- "version": "1.0.1-rc.5",
- "changes": [
- {
- "note": "Fix missing `BlockParamLiteral` type import issue"
- }
- ],
- "timestamp": 1535377027
- },
- {
- "version": "1.0.1-rc.4",
- "changes": [
- {
- "note": "Export types: `ExchangeContractErrs`, `OrderRelevantState`, `JSONRPCRequestPayload`, `JSONRPCErrorCallback` and `JSONRPCResponsePayload`",
- "pr": 924
- },
- {
- "note": "Remove exporting types: `BlockParamLiteral`, `BlockParam`, `Order`",
- "pr": 924
- }
- ],
- "timestamp": 1535133899
- },
- {
- "version": "1.0.1-rc.3",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ],
- "timestamp": 1534210131
- },
- {
- "version": "1.0.1-rc.2",
- "changes": [
- {
- "note": "Fixed bug caused by importing non-existent dep"
- }
- ],
- "timestamp": 1532619515
- },
- {
- "version": "1.0.1-rc.1",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ],
- "timestamp": 1532605697
- },
- {
- "timestamp": 1532357734,
- "version": "1.0.0",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ]
- },
- {
- "timestamp": 1532043000,
- "version": "1.0.0-rc.1",
- "changes": [
- {
- "note": "Add support for ERC721 event watching and Exchange V2 events",
- "pr": 887
- }
- ]
- },
- {
- "timestamp": 1531919263,
- "version": "0.0.8",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ]
- },
- {
- "version": "0.0.7",
- "changes": [
- {
- "note": "Switch out simple getLogs polling with ethereumjs-blockstream",
- "pr": 825
- },
- {
- "note": "Do not stop subscription if error is encountered",
- "pr": 825
- },
- {
- "note": "Fixed a bug that caused the incorrect block to be fetched via JSON-RPC within Blockstream",
- "pr": 875
- },
- {
- "note": "Remove stateLayer config from OrderWatcher. It now always operates on the latest block",
- "pr": 875
- }
- ],
- "timestamp": 1531149657
- },
- {
- "timestamp": 1529397769,
- "version": "0.0.6",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ]
- },
- {
- "timestamp": 1527617805,
- "version": "0.0.5",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ]
- },
- {
- "timestamp": 1527617227,
- "version": "0.0.4",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ]
- },
- {
- "timestamp": 1527616612,
- "version": "0.0.3",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ]
- },
- {
- "timestamp": 1527008794,
- "version": "0.0.2",
- "changes": [
- {
- "note": "Dependencies updated"
- }
- ]
- },
- {
- "timestamp": 1527008794,
- "version": "0.0.1",
- "changes": [
- {
- "note": "Moved OrderWatcher out of 0x.js package",
- "pr": 579
- }
- ]
- }
-]
diff --git a/packages/order-watcher/CHANGELOG.md b/packages/order-watcher/CHANGELOG.md
deleted file mode 100644
index df065866c..000000000
--- a/packages/order-watcher/CHANGELOG.md
+++ /dev/null
@@ -1,162 +0,0 @@
-<!--
-changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
-Edit the package's CHANGELOG.json file only.
--->
-
-CHANGELOG
-
-## v2.4.3 - _January 17, 2019_
-
- * Dependencies updated
-
-## v2.4.2 - _January 15, 2019_
-
- * Dependencies updated
-
-## v2.4.1 - _January 11, 2019_
-
- * Dependencies updated
-
-## v2.4.0 - _January 9, 2019_
-
- * Add support for `MultiAssetProxy` (#1363)
-
-## v2.3.0 - _Invalid date_
-
- * Added a WebSocket interface to OrderWatcher so that it can be used by a client written in any language (#1427)
-
-## v2.2.8 - _December 13, 2018_
-
- * Dependencies updated
-
-## v2.2.7 - _December 11, 2018_
-
- * Dependencies updated
-
-## v2.2.6 - _November 28, 2018_
-
- * Dependencies updated
-
-## v2.2.5 - _November 21, 2018_
-
- * Dependencies updated
-
-## v2.2.4 - _November 14, 2018_
-
- * Fix the bug when order watcher was throwing an error on order removal when maker token was ZRX (#1259)
-
-## v2.2.3 - _November 13, 2018_
-
- * Start jsonRpcRequestId at 1, not 0 as 0 breaks the web3.js websocket RPC provider (#1227)
- * Fix the bug when order watcher was trying to convert undefined to an object in case of CancelUpTo event
-
-## v2.2.2 - _November 12, 2018_
-
- * Dependencies updated
-
-## v2.2.1 - _November 9, 2018_
-
- * Dependencies updated
-
-## v2.2.0 - _October 18, 2018_
-
- * Added getStats function and returns a Stats object (#1118)
- * Updated to use new modularized artifacts and the latest version of @0xproject/contract-wrappers. Constructor has a new optional `contractAddresses` parameter. (#1105)
-
-## v2.1.1 - _October 4, 2018_
-
- * Dependencies updated
-
-## v2.1.0 - _September 28, 2018_
-
- * Export ExpirationWatcher (#1097)
-
-## v2.0.0 - _September 25, 2018_
-
- * Fixes dropped events issue by fetching logs by blockHash instead of blockNumber. Support for fetching by blockHash was added in Geth > v1.8.13 and Parity > v2.1.0. Infura works too. (#1080)
- * Fix misunderstanding about blockstream interface callbacks and pass the raw JSON RPC responses to it (#1080)
- * Add `transactionHash` to `OrderState` emitted by `OrderWatcher` subscriptions if the order's state change originated from a transaction. (#1087)
-
-## v1.0.5 - _September 25, 2018_
-
- * Dependencies updated
-
-## v1.0.4 - _September 21, 2018_
-
- * Dependencies updated
-
-## v1.0.3 - _September 19, 2018_
-
- * Drastically reduce the bundle size by removing unused parts of included contract artifacts.
-
-## v1.0.2 - _September 18, 2018_
-
- * Add ZRX & WETH mainnet contract addresses into the included artifacts
-
-## v1.0.1 - _September 5, 2018_
-
- * Dependencies updated
-
-## v1.0.1-rc.5 - _August 27, 2018_
-
- * Fix missing `BlockParamLiteral` type import issue
-
-## v1.0.1-rc.4 - _August 24, 2018_
-
- * Export types: `ExchangeContractErrs`, `OrderRelevantState`, `JSONRPCRequestPayload`, `JSONRPCErrorCallback` and `JSONRPCResponsePayload` (#924)
- * Remove exporting types: `BlockParamLiteral`, `BlockParam`, `Order` (#924)
-
-## v1.0.1-rc.3 - _August 14, 2018_
-
- * Dependencies updated
-
-## v1.0.1-rc.2 - _July 26, 2018_
-
- * Fixed bug caused by importing non-existent dep
-
-## v1.0.1-rc.1 - _July 26, 2018_
-
- * Dependencies updated
-
-## v1.0.0 - _July 23, 2018_
-
- * Dependencies updated
-
-## v1.0.0-rc.1 - _July 19, 2018_
-
- * Add support for ERC721 event watching and Exchange V2 events (#887)
-
-## v0.0.8 - _July 18, 2018_
-
- * Dependencies updated
-
-## v0.0.7 - _July 9, 2018_
-
- * Switch out simple getLogs polling with ethereumjs-blockstream (#825)
- * Do not stop subscription if error is encountered (#825)
- * Fixed a bug that caused the incorrect block to be fetched via JSON-RPC within Blockstream (#875)
- * Remove stateLayer config from OrderWatcher. It now always operates on the latest block (#875)
-
-## v0.0.6 - _June 19, 2018_
-
- * Dependencies updated
-
-## v0.0.5 - _May 29, 2018_
-
- * Dependencies updated
-
-## v0.0.4 - _May 29, 2018_
-
- * Dependencies updated
-
-## v0.0.3 - _May 29, 2018_
-
- * Dependencies updated
-
-## v0.0.2 - _May 22, 2018_
-
- * Dependencies updated
-
-## v0.0.1 - _May 22, 2018_
-
- * Moved OrderWatcher out of 0x.js package (#579)
diff --git a/packages/order-watcher/Dockerfile b/packages/order-watcher/Dockerfile
deleted file mode 100644
index 3ffa1b72f..000000000
--- a/packages/order-watcher/Dockerfile
+++ /dev/null
@@ -1,13 +0,0 @@
-FROM node
-
-WORKDIR /order-watcher
-
-COPY package.json .
-RUN npm i
-RUN npm install forever -g
-
-COPY . .
-
-EXPOSE 8080
-
-CMD ["forever", "./lib/src/server.js"]
diff --git a/packages/order-watcher/README.md b/packages/order-watcher/README.md
deleted file mode 100644
index a841775b6..000000000
--- a/packages/order-watcher/README.md
+++ /dev/null
@@ -1,167 +0,0 @@
-## OrderWatcher
-
-An order watcher daemon that watches for order validity.
-
-#### Read the wiki [article](https://0xproject.com/wiki#0x-OrderWatcher).
-
-OrderWatcher also comes with a WebSocket server to provide language-agnostic access
-to order watching functionality. We used the [WebSocket Client and Server Implementation for Node](https://www.npmjs.com/package/websocket). The server sends and receives messages that conform to the [JSON RPC specifications](https://www.jsonrpc.org/specification).
-
-## Installation
-
-**Install**
-
-```bash
-npm install @0x/order-watcher --save
-```
-
-**Import**
-
-```javascript
-import { OrderWatcher } from '@0x/order-watcher';
-```
-
-If your project is in [TypeScript](https://www.typescriptlang.org/), add the following to your `tsconfig.json`:
-
-```json
-"compilerOptions": {
- "typeRoots": ["node_modules/@0x/typescript-typings/types", "node_modules/@types"],
-}
-```
-
-## Using the WebSocket Server
-
-**Setup**
-
-**Environmental Variables**
-Several environmental variables can be set to configure the server:
-
-- `ORDER_WATCHER_HTTP_PORT` specifies the port that the http server will listen on
- and accept connections from. When this is not set, we default to 8080.
-
-**Requests**
-The server accepts three types of requests: `ADD_ORDER`, `REMOVE_ORDER` and `GET_STATS`. These mirror what the underlying OrderWatcher does. You can read more in the [wiki](https://0xproject.com/wiki#0x-OrderWatcher). Unlike the OrderWatcher, it does not expose any `subscribe` or `unsubscribe` functionality because the WebSocket server keeps a single subscription open for all clients.
-
-The first step for making a request is establishing a connection with the server. In Javascript:
-
-```
-var W3CWebSocket = require('websocket').w3cwebsocket;
-wsClient = new W3CWebSocket('ws://127.0.0.1:8080');
-```
-
-In Python, you could use the [websocket-client library](http://pypi.python.org/pypi/websocket-client/) and run:
-
-```
-from websocket import create_connection
-wsClient = create_connection("ws://127.0.0.1:8080")
-```
-
-With the connection established, you prepare the payload for your request. The payload is a json object with a format established by the [JSON RPC specification](https://www.jsonrpc.org/specification):
-
-- `id`: All requests require you to specify a numerical `id`. When the server responds to the request, the response will have the same `id` as the one supplied with your request.
-- `jsonrpc`: This is always the string `'2.0'`.
-- `method`: This specifies the OrderWatcher method you want to call. I.e., `'ADD_ORDER'`, `'REMOVE_ORDER'` or `'GET_STATS'`.
-- `params`: These contain the parameters needed by OrderWatcher to execute the method you called. For `ADD_ORDER`, provide `{ signedOrder: <your signedOrder> }`. For `REMOVE_ORDER`, provide `{ orderHash: <your orderHash> }`. For `GET_STATS`, no parameters are needed, so you may leave this empty.
-
-Next, convert the payload to a string and send it through the connection.
-In Javascript:
-
-```
-const addOrderPayload = {
- id: 1,
- jsonrpc: '2.0',
- method: 'ADD_ORDER',
- params: { signedOrder: <your signedOrder> },
-};
-wsClient.send(JSON.stringify(addOrderPayload));
-```
-
-In Python:
-
-```
-import json
-remove_order_payload = {
- 'id': 1,
- 'jsonrpc': '2.0',
- 'method': 'REMOVE_ORDER',
- 'params': {'orderHash': '0x6edc16bf37fde79f5012088c33784c730e2f103d9ab1caf73060c386ad107b7e'},
-}
-wsClient.send(json.dumps(remove_order_payload));
-```
-
-**Response**
-The server responds to all requests in a similar format. In the data field, you'll find another object containing the following fields:
-
-- `id`: The id corresponding to the request that the server is responding to. `UPDATE` responses are not based on any requests so the `id` field is omitted`.
-- `jsonrpc`: Always `'2.0'`.
-- `method`: The method the server is responding to. Eg. `ADD_ORDER`. When order states change the server may also initiate a response. In this case, method will be listed as `UPDATE`.
-- `result`: This field varies based on the method. `UPDATE` responses contain the new order state. `GET_STATS` responses contain the current order count. When there are errors, this field is omitted.
-- `error`: When there is an error executing a request, the [JSON RPC](https://www.jsonrpc.org/specification) error object is listed here. When the server responds successfully, this field is omitted.
-
-In Javascript, the responses can be parsed using the `onmessage` callback:
-
-```
-wsClient.onmessage = (msg) => {
- const responseData = JSON.parse(msg.data);
- const method = responseData.method
-};
-```
-
-In Python, `recv` is a lightweight way to receive a response:
-
-```
-result = wsClient.recv()
-method = result.method
-```
-
-## Contributing
-
-We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
-
-Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
-
-### Install dependencies
-
-If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
-
-```bash
-yarn config set workspaces-experimental true
-```
-
-Then install dependencies
-
-```bash
-yarn install
-```
-
-### Build
-
-To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
-
-```bash
-PKG=@0x/order-watcher yarn build
-```
-
-Or continuously rebuild on change:
-
-```bash
-PKG=@0x/order-watcher yarn watch
-```
-
-### Clean
-
-```bash
-yarn clean
-```
-
-### Lint
-
-```bash
-yarn lint
-```
-
-### Run Tests
-
-```bash
-yarn test
-```
diff --git a/packages/order-watcher/coverage/.gitkeep b/packages/order-watcher/coverage/.gitkeep
deleted file mode 100644
index e69de29bb..000000000
--- a/packages/order-watcher/coverage/.gitkeep
+++ /dev/null
diff --git a/packages/order-watcher/package.json b/packages/order-watcher/package.json
deleted file mode 100644
index 895c64813..000000000
--- a/packages/order-watcher/package.json
+++ /dev/null
@@ -1,89 +0,0 @@
-{
- "name": "@0x/order-watcher",
- "version": "2.4.3",
- "description": "An order watcher daemon that watches for order validity",
- "keywords": [
- "0x",
- "0xproject",
- "ethereum",
- "exchange",
- "orderbook"
- ],
- "main": "lib/src/index.js",
- "types": "lib/src/index.d.ts",
- "scripts": {
- "build": "yarn tsc -b",
- "build:ci": "yarn build",
- "lint": "tslint --format stylish --project .",
- "test:circleci": "run-s test:coverage",
- "test": "yarn run_mocha",
- "rebuild_and_test": "run-s build test",
- "test:coverage": "nyc npm run test --all && yarn coverage:report:lcov",
- "coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info",
- "clean": "shx rm -rf _bundles lib test_temp generated_docs",
- "run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js lib/test/global_hooks.js --timeout 10000 --bail --exit",
- "docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
- },
- "config": {
- "postpublish": {
- "dockerHubRepo": "order-watcher"
- }
- },
- "repository": {
- "type": "git",
- "url": "https://github.com/0xProject/0x-monorepo"
- },
- "license": "Apache-2.0",
- "engines": {
- "node": ">=6.0.0"
- },
- "devDependencies": {
- "@0x/dev-utils": "^1.0.24",
- "@0x/migrations": "^2.4.0",
- "@0x/subproviders": "^2.1.11",
- "@0x/tslint-config": "^2.0.2",
- "@types/bintrees": "^1.0.2",
- "@types/lodash": "4.14.104",
- "@types/mocha": "^2.2.42",
- "@types/node": "*",
- "@types/sinon": "^2.2.2",
- "chai": "^4.0.1",
- "chai-as-promised": "^7.1.0",
- "chai-bignumber": "^3.0.0",
- "dirty-chai": "^2.0.1",
- "make-promises-safe": "^1.1.0",
- "mocha": "^4.1.0",
- "npm-run-all": "^4.1.2",
- "nyc": "^11.0.1",
- "opn-cli": "^3.1.0",
- "shx": "^0.2.2",
- "sinon": "^4.0.0",
- "source-map-support": "^0.5.0",
- "tslint": "5.11.0",
- "typescript": "3.0.1"
- },
- "dependencies": {
- "@0x/abi-gen-wrappers": "^2.2.0",
- "@0x/assert": "^1.0.23",
- "@0x/base-contract": "^3.0.13",
- "@0x/contract-addresses": "^2.2.0",
- "@0x/contract-artifacts": "^1.3.0",
- "@0x/contract-wrappers": "^5.0.1",
- "@0x/fill-scenarios": "^1.1.2",
- "@0x/json-schemas": "^2.1.7",
- "@0x/order-utils": "^3.1.2",
- "@0x/types": "^1.5.2",
- "@0x/typescript-typings": "^3.0.8",
- "@0x/utils": "^3.0.1",
- "@0x/web3-wrapper": "^3.2.4",
- "bintrees": "^1.0.2",
- "ethereum-types": "^1.1.6",
- "ethereumjs-blockstream": "6.0.0",
- "ethers": "~4.0.4",
- "lodash": "^4.17.5",
- "websocket": "^1.0.25"
- },
- "publishConfig": {
- "access": "public"
- }
-}
diff --git a/packages/order-watcher/src/index.ts b/packages/order-watcher/src/index.ts
deleted file mode 100644
index 1f4e5eff1..000000000
--- a/packages/order-watcher/src/index.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-export { OrderWatcher } from './order_watcher/order_watcher';
-export { OrderWatcherWebSocketServer } from './order_watcher/order_watcher_web_socket_server';
-export { ExpirationWatcher } from './order_watcher/expiration_watcher';
-
-export {
- OrderStateValid,
- OrderStateInvalid,
- OrderState,
- ExchangeContractErrs,
- ObjectMap,
- OrderRelevantState,
- Stats,
-} from '@0x/types';
-
-export { OnOrderStateChangeCallback, OrderWatcherConfig } from './types';
-
-export { ContractAddresses } from '@0x/contract-addresses';
-export { SignedOrder } from '@0x/types';
-export {
- JSONRPCRequestPayload,
- JSONRPCErrorCallback,
- Provider,
- JSONRPCResponsePayload,
- JSONRPCResponseError,
-} from 'ethereum-types';
diff --git a/packages/order-watcher/src/order_watcher/collision_resistant_abi_decoder.ts b/packages/order-watcher/src/order_watcher/collision_resistant_abi_decoder.ts
deleted file mode 100644
index 2ea796947..000000000
--- a/packages/order-watcher/src/order_watcher/collision_resistant_abi_decoder.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import { AbiDecoder } from '@0x/utils';
-import { ContractAbi, DecodedLogArgs, LogEntry, LogWithDecodedArgs, RawLog } from 'ethereum-types';
-
-const TOKEN_TYPE_COLLISION = `Token can't be marked as ERC20 and ERC721 at the same time`;
-
-/**
- * ERC20 and ERC721 have some events with different args but colliding signature.
- * For exmaple:
- * Transfer(_from address, _to address, _value uint256)
- * Transfer(_from address, _to address, _tokenId uint256)
- * Both have the signature:
- * Transfer(address,address,uint256)
- *
- * In order to correctly decode those events we need to know the token type by address in advance.
- * You can pass it by calling `this.addERC20Token(address)` or `this.addERC721Token(address)`
- */
-export class CollisionResistanceAbiDecoder {
- private readonly _erc20AbiDecoder: AbiDecoder;
- private readonly _erc721AbiDecoder: AbiDecoder;
- private readonly _restAbiDecoder: AbiDecoder;
- private readonly _knownERC20Tokens = new Set();
- private readonly _knownERC721Tokens = new Set();
- constructor(erc20Abi: ContractAbi, erc721Abi: ContractAbi, abis: ContractAbi[]) {
- this._erc20AbiDecoder = new AbiDecoder([erc20Abi]);
- this._erc721AbiDecoder = new AbiDecoder([erc721Abi]);
- this._restAbiDecoder = new AbiDecoder(abis);
- }
- public tryToDecodeLogOrNoop<ArgsType extends DecodedLogArgs>(log: LogEntry): LogWithDecodedArgs<ArgsType> | RawLog {
- if (this._knownERC20Tokens.has(log.address)) {
- const maybeDecodedERC20Log = this._erc20AbiDecoder.tryToDecodeLogOrNoop(log);
- return maybeDecodedERC20Log;
- } else if (this._knownERC721Tokens.has(log.address)) {
- const maybeDecodedERC721Log = this._erc721AbiDecoder.tryToDecodeLogOrNoop(log);
- return maybeDecodedERC721Log;
- } else {
- const maybeDecodedLog = this._restAbiDecoder.tryToDecodeLogOrNoop(log);
- return maybeDecodedLog;
- }
- }
- // Hints the ABI decoder that a particular token address is ERC20 and events from it should be decoded as ERC20 events
- public addERC20Token(address: string): void {
- if (this._knownERC721Tokens.has(address)) {
- throw new Error(TOKEN_TYPE_COLLISION);
- }
- this._knownERC20Tokens.add(address);
- }
- // Hints the ABI decoder that a particular token address is ERC721 and events from it should be decoded as ERC721 events
- public addERC721Token(address: string): void {
- if (this._knownERC20Tokens.has(address)) {
- throw new Error(TOKEN_TYPE_COLLISION);
- }
- this._knownERC721Tokens.add(address);
- }
-}
diff --git a/packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts b/packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts
deleted file mode 100644
index d1085014c..000000000
--- a/packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts
+++ /dev/null
@@ -1,243 +0,0 @@
-import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
-import { AssetProxyId, SignedOrder } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as _ from 'lodash';
-
-export interface OrderHashesByMakerAddress {
- [makerAddress: string]: Set<string>;
-}
-
-export interface OrderHashesByERC20ByMakerAddress {
- [makerAddress: string]: {
- [erc20TokenAddress: string]: Set<string>;
- };
-}
-
-export interface OrderHashesByERC721AddressByTokenIdByMakerAddress {
- [makerAddress: string]: {
- [erc721TokenAddress: string]: {
- // Ideally erc721TokenId should be a BigNumber, but it's not a valid index type so we just convert it to a string before using it as an index
- [erc721TokenId: string]: Set<string>;
- };
- };
-}
-
-/**
- */
-export class DependentOrderHashesTracker {
- private readonly _zrxTokenAddress: string;
- // `_orderHashesByMakerAddress` is redundant and could be generated from
- // `_orderHashesByERC20ByMakerAddress` and `_orderHashesByERC721AddressByTokenIdByMakerAddress`
- // on the fly by merging all the entries together but it's more complex and computationally heavy.
- // We might change that in future if we're move memory-constrained.
- private readonly _orderHashesByMakerAddress: OrderHashesByMakerAddress = {};
- private readonly _orderHashesByERC20ByMakerAddress: OrderHashesByERC20ByMakerAddress = {};
- private readonly _orderHashesByERC721AddressByTokenIdByMakerAddress: OrderHashesByERC721AddressByTokenIdByMakerAddress = {};
- constructor(zrxTokenAddress: string) {
- this._zrxTokenAddress = zrxTokenAddress;
- }
- public getDependentOrderHashesByERC721ByMaker(makerAddress: string, tokenAddress: string): string[] {
- const orderHashSets = _.values(
- this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress][tokenAddress],
- );
- const orderHashList = _.reduce(
- orderHashSets,
- (accumulator, orderHashSet) => [...accumulator, ...orderHashSet],
- [] as string[],
- );
- const uniqueOrderHashList = _.uniq(orderHashList);
- return uniqueOrderHashList;
- }
- public getDependentOrderHashesByMaker(makerAddress: string): string[] {
- const dependentOrderHashes = Array.from(this._orderHashesByMakerAddress[makerAddress] || {});
- return dependentOrderHashes;
- }
- public getDependentOrderHashesByAssetDataByMaker(makerAddress: string, assetData: string): string[] {
- const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
- const dependentOrderHashes =
- decodedAssetData.assetProxyId === AssetProxyId.ERC20
- ? this._getDependentOrderHashesByERC20AssetData(makerAddress, assetData)
- : this._getDependentOrderHashesByERC721AssetData(makerAddress, assetData);
- return dependentOrderHashes;
- }
- public addToDependentOrderHashes(signedOrder: SignedOrder): void {
- this._addAssetDataToDependentOrderHashes(signedOrder, signedOrder.makerAssetData);
- this._addToERC20DependentOrderHashes(signedOrder, this._zrxTokenAddress);
- this._addToMakerDependentOrderHashes(signedOrder);
- }
- public removeFromDependentOrderHashes(signedOrder: SignedOrder): void {
- this._removeAssetDataFromDependentOrderHashes(signedOrder, signedOrder.makerAssetData);
- // If makerToken === ZRX then we already removed it and we don't need to remove it again.
- const decodedMakerAssetData = assetDataUtils.decodeAssetDataOrThrow(signedOrder.makerAssetData);
- if (
- assetDataUtils.isERC20AssetData(decodedMakerAssetData) &&
- decodedMakerAssetData.tokenAddress !== this._zrxTokenAddress
- ) {
- this._removeFromERC20DependentOrderhashes(signedOrder, this._zrxTokenAddress);
- }
- this._removeFromMakerDependentOrderhashes(signedOrder);
- }
- private _getDependentOrderHashesByERC20AssetData(makerAddress: string, erc20AssetData: string): string[] {
- const tokenAddress = assetDataUtils.decodeERC20AssetData(erc20AssetData).tokenAddress;
- let dependentOrderHashes: string[] = [];
- if (
- !_.isUndefined(this._orderHashesByERC20ByMakerAddress[makerAddress]) &&
- !_.isUndefined(this._orderHashesByERC20ByMakerAddress[makerAddress][tokenAddress])
- ) {
- dependentOrderHashes = Array.from(this._orderHashesByERC20ByMakerAddress[makerAddress][tokenAddress]);
- }
- return dependentOrderHashes;
- }
- private _getDependentOrderHashesByERC721AssetData(makerAddress: string, erc721AssetData: string): string[] {
- const tokenAddress = assetDataUtils.decodeERC721AssetData(erc721AssetData).tokenAddress;
- const tokenId = assetDataUtils.decodeERC721AssetData(erc721AssetData).tokenId;
- let dependentOrderHashes: string[] = [];
- if (
- !_.isUndefined(this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress]) &&
- !_.isUndefined(this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress][tokenAddress]) &&
- !_.isUndefined(
- this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress][tokenAddress][tokenId.toString()],
- )
- ) {
- dependentOrderHashes = Array.from(
- this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress][tokenAddress][tokenId.toString()],
- );
- }
- return dependentOrderHashes;
- }
- private _addToERC20DependentOrderHashes(signedOrder: SignedOrder, erc20TokenAddress: string): void {
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- if (_.isUndefined(this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress])) {
- this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress] = {};
- }
- if (_.isUndefined(this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress][erc20TokenAddress])) {
- this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress][erc20TokenAddress] = new Set();
- }
- this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress][erc20TokenAddress].add(orderHash);
- }
- private _addToERC721DependentOrderHashes(
- signedOrder: SignedOrder,
- erc721TokenAddress: string,
- tokenId: BigNumber,
- ): void {
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- if (_.isUndefined(this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress])) {
- this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress] = {};
- }
-
- if (
- _.isUndefined(
- this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress],
- )
- ) {
- this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress] = {};
- }
-
- if (
- _.isUndefined(
- this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress][
- tokenId.toString()
- ],
- )
- ) {
- this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress][
- tokenId.toString()
- ] = new Set();
- }
-
- this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress][
- tokenId.toString()
- ].add(orderHash);
- }
- private _addAssetDataToDependentOrderHashes(signedOrder: SignedOrder, assetData: string): void {
- const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
- if (assetDataUtils.isERC20AssetData(decodedAssetData)) {
- this._addToERC20DependentOrderHashes(signedOrder, decodedAssetData.tokenAddress);
- } else if (assetDataUtils.isERC721AssetData(decodedAssetData)) {
- this._addToERC721DependentOrderHashes(signedOrder, decodedAssetData.tokenAddress, decodedAssetData.tokenId);
- } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
- _.each(decodedAssetData.nestedAssetData, nestedAssetDataElement =>
- this._addAssetDataToDependentOrderHashes(signedOrder, nestedAssetDataElement),
- );
- }
- }
- private _addToMakerDependentOrderHashes(signedOrder: SignedOrder): void {
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- if (_.isUndefined(this._orderHashesByMakerAddress[signedOrder.makerAddress])) {
- this._orderHashesByMakerAddress[signedOrder.makerAddress] = new Set();
- }
- this._orderHashesByMakerAddress[signedOrder.makerAddress].add(orderHash);
- }
- private _removeFromERC20DependentOrderhashes(signedOrder: SignedOrder, erc20TokenAddress: string): void {
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress][erc20TokenAddress].delete(orderHash);
-
- if (_.isEmpty(this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress][erc20TokenAddress])) {
- delete this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress][erc20TokenAddress];
- }
-
- if (_.isEmpty(this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress])) {
- delete this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress];
- }
- }
- private _removeFromERC721DependentOrderhashes(
- signedOrder: SignedOrder,
- erc721TokenAddress: string,
- tokenId: BigNumber,
- ): void {
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress][
- tokenId.toString()
- ].delete(orderHash);
-
- if (
- _.isEmpty(
- this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress][
- tokenId.toString()
- ],
- )
- ) {
- delete this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][
- erc721TokenAddress
- ][tokenId.toString()];
- }
-
- if (
- _.isEmpty(
- this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress],
- )
- ) {
- delete this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][
- erc721TokenAddress
- ];
- }
-
- if (_.isEmpty(this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress])) {
- delete this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress];
- }
- }
- private _removeFromMakerDependentOrderhashes(signedOrder: SignedOrder): void {
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- this._orderHashesByMakerAddress[signedOrder.makerAddress].delete(orderHash);
-
- if (_.isEmpty(this._orderHashesByMakerAddress[signedOrder.makerAddress])) {
- delete this._orderHashesByMakerAddress[signedOrder.makerAddress];
- }
- }
- private _removeAssetDataFromDependentOrderHashes(signedOrder: SignedOrder, assetData: string): void {
- const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
- if (assetDataUtils.isERC20AssetData(decodedAssetData)) {
- this._removeFromERC20DependentOrderhashes(signedOrder, decodedAssetData.tokenAddress);
- } else if (assetDataUtils.isERC721AssetData(decodedAssetData)) {
- this._removeFromERC721DependentOrderhashes(
- signedOrder,
- decodedAssetData.tokenAddress,
- decodedAssetData.tokenId,
- );
- } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
- _.each(decodedAssetData.nestedAssetData, nestedAssetDataElement =>
- this._removeAssetDataFromDependentOrderHashes(signedOrder, nestedAssetDataElement),
- );
- }
- }
-}
diff --git a/packages/order-watcher/src/order_watcher/event_watcher.ts b/packages/order-watcher/src/order_watcher/event_watcher.ts
deleted file mode 100644
index 3149d858b..000000000
--- a/packages/order-watcher/src/order_watcher/event_watcher.ts
+++ /dev/null
@@ -1,158 +0,0 @@
-import { intervalUtils, logUtils } from '@0x/utils';
-import { marshaller, Web3Wrapper } from '@0x/web3-wrapper';
-import { BlockParamLiteral, FilterObject, LogEntry, Provider, RawLogEntry } from 'ethereum-types';
-import { Block, BlockAndLogStreamer, Log } from 'ethereumjs-blockstream';
-import * as _ from 'lodash';
-
-import { EventWatcherCallback, OrderWatcherError } from '../types';
-import { assert } from '../utils/assert';
-
-const DEFAULT_EVENT_POLLING_INTERVAL_MS = 200;
-
-enum LogEventState {
- Removed,
- Added,
-}
-
-/**
- * The EventWatcher watches for blockchain events at the specified block confirmation
- * depth.
- */
-export class EventWatcher {
- private readonly _web3Wrapper: Web3Wrapper;
- private readonly _isVerbose: boolean;
- private _blockAndLogStreamerIfExists: BlockAndLogStreamer<Block, Log> | undefined;
- private _blockAndLogStreamIntervalIfExists?: NodeJS.Timer;
- private _onLogAddedSubscriptionToken: string | undefined;
- private _onLogRemovedSubscriptionToken: string | undefined;
- private readonly _pollingIntervalMs: number;
- constructor(
- provider: Provider,
- pollingIntervalIfExistsMs: undefined | number,
- stateLayer: BlockParamLiteral,
- isVerbose: boolean,
- ) {
- this._isVerbose = isVerbose;
- this._web3Wrapper = new Web3Wrapper(provider);
- this._pollingIntervalMs = _.isUndefined(pollingIntervalIfExistsMs)
- ? DEFAULT_EVENT_POLLING_INTERVAL_MS
- : pollingIntervalIfExistsMs;
- this._blockAndLogStreamerIfExists = undefined;
- this._blockAndLogStreamIntervalIfExists = undefined;
- this._onLogAddedSubscriptionToken = undefined;
- this._onLogRemovedSubscriptionToken = undefined;
- }
- public subscribe(callback: EventWatcherCallback): void {
- assert.isFunction('callback', callback);
- if (!_.isUndefined(this._blockAndLogStreamIntervalIfExists)) {
- throw new Error(OrderWatcherError.SubscriptionAlreadyPresent);
- }
- this._startBlockAndLogStream(callback);
- }
- public unsubscribe(): void {
- if (_.isUndefined(this._blockAndLogStreamIntervalIfExists)) {
- throw new Error(OrderWatcherError.SubscriptionNotFound);
- }
- this._stopBlockAndLogStream();
- }
- private _startBlockAndLogStream(callback: EventWatcherCallback): void {
- if (!_.isUndefined(this._blockAndLogStreamerIfExists)) {
- throw new Error(OrderWatcherError.SubscriptionAlreadyPresent);
- }
- this._blockAndLogStreamerIfExists = new BlockAndLogStreamer(
- this._blockstreamGetBlockOrNullAsync.bind(this),
- this._blockstreamGetLogsAsync.bind(this),
- this._onBlockAndLogStreamerError.bind(this),
- );
- const catchAllLogFilter = {};
- this._blockAndLogStreamerIfExists.addLogFilter(catchAllLogFilter);
- this._blockAndLogStreamIntervalIfExists = intervalUtils.setAsyncExcludingInterval(
- this._reconcileBlockAsync.bind(this),
- this._pollingIntervalMs,
- this._onBlockAndLogStreamerError.bind(this),
- );
- let isRemoved = false;
- this._onLogAddedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogAdded(
- this._onLogStateChangedAsync.bind(this, callback, isRemoved),
- );
- isRemoved = true;
- this._onLogRemovedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogRemoved(
- this._onLogStateChangedAsync.bind(this, callback, isRemoved),
- );
- }
- // This method only exists in order to comply with the expected interface of Blockstream's constructor
- private async _blockstreamGetBlockOrNullAsync(hash: string): Promise<Block | null> {
- const shouldIncludeTransactionData = false;
- const blockOrNull = await this._web3Wrapper.sendRawPayloadAsync<Block | null>({
- method: 'eth_getBlockByHash',
- params: [hash, shouldIncludeTransactionData],
- });
- return blockOrNull;
- }
- // This method only exists in order to comply with the expected interface of Blockstream's constructor
- private async _blockstreamGetLatestBlockOrNullAsync(): Promise<Block | null> {
- const shouldIncludeTransactionData = false;
- const blockOrNull = await this._web3Wrapper.sendRawPayloadAsync<Block | null>({
- method: 'eth_getBlockByNumber',
- params: [BlockParamLiteral.Latest, shouldIncludeTransactionData],
- });
- return blockOrNull;
- }
- // This method only exists in order to comply with the expected interface of Blockstream's constructor
- private async _blockstreamGetLogsAsync(filterOptions: FilterObject): Promise<RawLogEntry[]> {
- const logs = await this._web3Wrapper.sendRawPayloadAsync<RawLogEntry[]>({
- method: 'eth_getLogs',
- params: [filterOptions],
- });
- return logs as RawLogEntry[];
- }
- private _stopBlockAndLogStream(): void {
- if (_.isUndefined(this._blockAndLogStreamerIfExists)) {
- throw new Error(OrderWatcherError.SubscriptionNotFound);
- }
- this._blockAndLogStreamerIfExists.unsubscribeFromOnLogAdded(this._onLogAddedSubscriptionToken as string);
- this._blockAndLogStreamerIfExists.unsubscribeFromOnLogRemoved(this._onLogRemovedSubscriptionToken as string);
- intervalUtils.clearAsyncExcludingInterval(this._blockAndLogStreamIntervalIfExists as NodeJS.Timer);
- delete this._blockAndLogStreamerIfExists;
- delete this._blockAndLogStreamIntervalIfExists;
- }
- private async _onLogStateChangedAsync(
- callback: EventWatcherCallback,
- isRemoved: boolean,
- rawLog: RawLogEntry,
- ): Promise<void> {
- const log: LogEntry = marshaller.unmarshalLog(rawLog);
- await this._emitDifferencesAsync(log, isRemoved ? LogEventState.Removed : LogEventState.Added, callback);
- }
- private async _reconcileBlockAsync(): Promise<void> {
- const latestBlockOrNull = await this._blockstreamGetLatestBlockOrNullAsync();
- if (_.isNull(latestBlockOrNull)) {
- return; // noop
- }
- // We need to coerce to Block type cause Web3.Block includes types for mempool blocks
- if (!_.isUndefined(this._blockAndLogStreamerIfExists)) {
- // If we clear the interval while fetching the block - this._blockAndLogStreamer will be undefined
- await this._blockAndLogStreamerIfExists.reconcileNewBlock(latestBlockOrNull);
- }
- }
- private async _emitDifferencesAsync(
- log: LogEntry,
- logEventState: LogEventState,
- callback: EventWatcherCallback,
- ): Promise<void> {
- const logEvent = {
- removed: logEventState === LogEventState.Removed,
- ...log,
- };
- if (!_.isUndefined(this._blockAndLogStreamIntervalIfExists)) {
- callback(null, logEvent);
- }
- }
- private _onBlockAndLogStreamerError(err: Error): void {
- // Since Blockstream errors are all recoverable, we simply log them if the verbose
- // config is passed in.
- if (this._isVerbose) {
- logUtils.warn(err);
- }
- }
-}
diff --git a/packages/order-watcher/src/order_watcher/expiration_watcher.ts b/packages/order-watcher/src/order_watcher/expiration_watcher.ts
deleted file mode 100644
index 82590efde..000000000
--- a/packages/order-watcher/src/order_watcher/expiration_watcher.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-import { BigNumber, intervalUtils } from '@0x/utils';
-import { RBTree } from 'bintrees';
-import * as _ from 'lodash';
-
-import { OrderWatcherError } from '../types';
-import { utils } from '../utils/utils';
-
-const DEFAULT_EXPIRATION_MARGIN_MS = 0;
-const DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS = 50;
-
-/**
- * This class includes the functionality to detect expired orders.
- * It stores them in a min heap by expiration time and checks for expired ones every `orderExpirationCheckingIntervalMs`
- */
-export class ExpirationWatcher {
- private readonly _orderHashByExpirationRBTree: RBTree<string>;
- private readonly _expiration: { [orderHash: string]: BigNumber } = {};
- private readonly _orderExpirationCheckingIntervalMs: number;
- private readonly _expirationMarginMs: number;
- private _orderExpirationCheckingIntervalIdIfExists?: NodeJS.Timer;
- constructor(expirationMarginIfExistsMs?: number, orderExpirationCheckingIntervalIfExistsMs?: number) {
- this._orderExpirationCheckingIntervalMs =
- orderExpirationCheckingIntervalIfExistsMs || DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS;
- this._expirationMarginMs = expirationMarginIfExistsMs || DEFAULT_EXPIRATION_MARGIN_MS;
- this._orderExpirationCheckingIntervalMs =
- expirationMarginIfExistsMs || DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS;
- const comparator = (lhsOrderHash: string, rhsOrderHash: string) => {
- const lhsExpiration = this._expiration[lhsOrderHash].toNumber();
- const rhsExpiration = this._expiration[rhsOrderHash].toNumber();
- if (lhsExpiration !== rhsExpiration) {
- return lhsExpiration - rhsExpiration;
- } else {
- // HACK: If two orders have identical expirations, the order in which they are emitted by the
- // ExpirationWatcher does not matter, so we emit them in alphabetical order by orderHash.
- return lhsOrderHash.localeCompare(rhsOrderHash);
- }
- };
- this._orderHashByExpirationRBTree = new RBTree(comparator);
- }
- public subscribe(callback: (orderHash: string) => void): void {
- if (!_.isUndefined(this._orderExpirationCheckingIntervalIdIfExists)) {
- throw new Error(OrderWatcherError.SubscriptionAlreadyPresent);
- }
- this._orderExpirationCheckingIntervalIdIfExists = intervalUtils.setInterval(
- this._pruneExpiredOrders.bind(this, callback),
- this._orderExpirationCheckingIntervalMs,
- _.noop.bind(_), // _pruneExpiredOrders never throws
- );
- }
- public unsubscribe(): void {
- if (_.isUndefined(this._orderExpirationCheckingIntervalIdIfExists)) {
- throw new Error(OrderWatcherError.SubscriptionNotFound);
- }
- intervalUtils.clearInterval(this._orderExpirationCheckingIntervalIdIfExists);
- delete this._orderExpirationCheckingIntervalIdIfExists;
- }
- public addOrder(orderHash: string, expirationUnixTimestampMs: BigNumber): void {
- this._expiration[orderHash] = expirationUnixTimestampMs;
- this._orderHashByExpirationRBTree.insert(orderHash);
- }
- public removeOrder(orderHash: string): void {
- if (_.isUndefined(this._expiration[orderHash])) {
- return; // noop since order already removed
- }
- this._orderHashByExpirationRBTree.remove(orderHash);
- delete this._expiration[orderHash];
- }
- private _pruneExpiredOrders(callback: (orderHash: string) => void): void {
- const currentUnixTimestampMs = utils.getCurrentUnixTimestampMs();
- while (true) {
- const hasNoTrackedOrders = this._orderHashByExpirationRBTree.size === 0;
- if (hasNoTrackedOrders) {
- break;
- }
- const nextOrderHashToExpire = this._orderHashByExpirationRBTree.min();
- const hasNoExpiredOrders = this._expiration[nextOrderHashToExpire].isGreaterThan(
- currentUnixTimestampMs.plus(this._expirationMarginMs),
- );
- const isSubscriptionActive = _.isUndefined(this._orderExpirationCheckingIntervalIdIfExists);
- if (hasNoExpiredOrders || isSubscriptionActive) {
- break;
- }
- const orderHash = this._orderHashByExpirationRBTree.min();
- this._orderHashByExpirationRBTree.remove(orderHash);
- delete this._expiration[orderHash];
- callback(orderHash);
- }
- }
-}
diff --git a/packages/order-watcher/src/order_watcher/order_watcher.ts b/packages/order-watcher/src/order_watcher/order_watcher.ts
deleted file mode 100644
index a06fd0cfe..000000000
--- a/packages/order-watcher/src/order_watcher/order_watcher.ts
+++ /dev/null
@@ -1,490 +0,0 @@
-// tslint:disable:no-unnecessary-type-assertion
-import { ContractAddresses } from '@0x/contract-addresses';
-import * as artifacts from '@0x/contract-artifacts';
-import {
- AssetBalanceAndProxyAllowanceFetcher,
- ContractWrappers,
- ERC20TokenApprovalEventArgs,
- ERC20TokenEventArgs,
- ERC20TokenEvents,
- ERC20TokenTransferEventArgs,
- ERC721TokenApprovalEventArgs,
- ERC721TokenApprovalForAllEventArgs,
- ERC721TokenEventArgs,
- ERC721TokenEvents,
- ERC721TokenTransferEventArgs,
- ExchangeCancelEventArgs,
- ExchangeCancelUpToEventArgs,
- ExchangeEventArgs,
- ExchangeEvents,
- ExchangeFillEventArgs,
- OrderFilledCancelledFetcher,
- WETH9DepositEventArgs,
- WETH9EventArgs,
- WETH9Events,
- WETH9WithdrawalEventArgs,
-} from '@0x/contract-wrappers';
-import { schemas } from '@0x/json-schemas';
-import {
- assetDataUtils,
- BalanceAndProxyAllowanceLazyStore,
- OrderFilledCancelledLazyStore,
- orderHashUtils,
- OrderStateUtils,
-} from '@0x/order-utils';
-import { AssetProxyId, ExchangeContractErrs, OrderState, SignedOrder, Stats } from '@0x/types';
-import { errorUtils, intervalUtils } from '@0x/utils';
-import { BlockParamLiteral, LogEntryEvent, LogWithDecodedArgs, Provider } from 'ethereum-types';
-import * as _ from 'lodash';
-
-import { orderWatcherPartialConfigSchema } from '../schemas/order_watcher_partial_config_schema';
-import { OnOrderStateChangeCallback, OrderWatcherConfig, OrderWatcherError } from '../types';
-import { assert } from '../utils/assert';
-
-import { CollisionResistanceAbiDecoder } from './collision_resistant_abi_decoder';
-import { DependentOrderHashesTracker } from './dependent_order_hashes_tracker';
-import { EventWatcher } from './event_watcher';
-import { ExpirationWatcher } from './expiration_watcher';
-
-const MILLISECONDS_IN_A_SECOND = 1000;
-
-type ContractEventArgs = WETH9EventArgs | ExchangeEventArgs | ERC20TokenEventArgs | ERC721TokenEventArgs;
-
-interface OrderByOrderHash {
- [orderHash: string]: SignedOrder;
-}
-
-interface OrderStateByOrderHash {
- [orderHash: string]: OrderState;
-}
-
-const DEFAULT_ORDER_WATCHER_CONFIG: OrderWatcherConfig = {
- orderExpirationCheckingIntervalMs: 50,
- eventPollingIntervalMs: 200,
- expirationMarginMs: 0,
- // tslint:disable-next-line:custom-no-magic-numbers
- cleanupJobIntervalMs: 1000 * 60 * 60, // 1h
- isVerbose: true,
-};
-const STATE_LAYER = BlockParamLiteral.Latest;
-
-/**
- * This class includes all the functionality related to watching a set of orders
- * for potential changes in order validity/fillability. The orderWatcher notifies
- * the subscriber of these changes so that a final decision can be made on whether
- * the order should be deemed invalid.
- */
-export class OrderWatcher {
- private readonly _dependentOrderHashesTracker: DependentOrderHashesTracker;
- private readonly _orderStateByOrderHashCache: OrderStateByOrderHash = {};
- private readonly _orderByOrderHash: OrderByOrderHash = {};
- private readonly _eventWatcher: EventWatcher;
- private readonly _provider: Provider;
- private readonly _collisionResistantAbiDecoder: CollisionResistanceAbiDecoder;
- private readonly _expirationWatcher: ExpirationWatcher;
- private readonly _orderStateUtils: OrderStateUtils;
- private readonly _orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore;
- private readonly _balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore;
- private readonly _cleanupJobInterval: number;
- private _cleanupJobIntervalIdIfExists?: NodeJS.Timer;
- private _callbackIfExists?: OnOrderStateChangeCallback;
- /**
- * Instantiate a new OrderWatcher
- * @param provider Web3 provider to use for JSON RPC calls
- * @param networkId NetworkId to watch orders on
- * @param contractAddresses Optional contract addresses. Defaults to known
- * addresses based on networkId.
- * @param partialConfig Optional configurations
- */
- constructor(
- provider: Provider,
- networkId: number,
- contractAddresses?: ContractAddresses,
- partialConfig: Partial<OrderWatcherConfig> = DEFAULT_ORDER_WATCHER_CONFIG,
- ) {
- assert.isWeb3Provider('provider', provider);
- assert.isNumber('networkId', networkId);
- assert.doesConformToSchema('partialConfig', partialConfig, orderWatcherPartialConfigSchema);
- const config = {
- ...DEFAULT_ORDER_WATCHER_CONFIG,
- ...partialConfig,
- };
-
- this._provider = provider;
- this._collisionResistantAbiDecoder = new CollisionResistanceAbiDecoder(
- artifacts.ERC20Token.compilerOutput.abi,
- artifacts.ERC721Token.compilerOutput.abi,
- [artifacts.WETH9.compilerOutput.abi, artifacts.Exchange.compilerOutput.abi],
- );
- const contractWrappers = new ContractWrappers(provider, {
- networkId,
- // Note(albrow): We let the contract-wrappers package handle
- // default values for contractAddresses.
- contractAddresses,
- });
- this._eventWatcher = new EventWatcher(provider, config.eventPollingIntervalMs, STATE_LAYER, config.isVerbose);
- const balanceAndProxyAllowanceFetcher = new AssetBalanceAndProxyAllowanceFetcher(
- contractWrappers.erc20Token,
- contractWrappers.erc721Token,
- STATE_LAYER,
- );
- this._balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore(
- balanceAndProxyAllowanceFetcher,
- );
- const orderFilledCancelledFetcher = new OrderFilledCancelledFetcher(contractWrappers.exchange, STATE_LAYER);
- this._orderFilledCancelledLazyStore = new OrderFilledCancelledLazyStore(orderFilledCancelledFetcher);
- this._orderStateUtils = new OrderStateUtils(balanceAndProxyAllowanceFetcher, orderFilledCancelledFetcher);
- const expirationMarginIfExistsMs = _.isUndefined(config) ? undefined : config.expirationMarginMs;
- this._expirationWatcher = new ExpirationWatcher(
- expirationMarginIfExistsMs,
- config.orderExpirationCheckingIntervalMs,
- );
- this._cleanupJobInterval = config.cleanupJobIntervalMs;
- const zrxTokenAddress = assetDataUtils.decodeERC20AssetData(orderFilledCancelledFetcher.getZRXAssetData())
- .tokenAddress;
- this._dependentOrderHashesTracker = new DependentOrderHashesTracker(zrxTokenAddress);
- }
- /**
- * Add an order to the orderWatcher. Before the order is added, it's
- * signature is verified.
- * @param signedOrder The order you wish to start watching.
- */
- public async addOrderAsync(signedOrder: SignedOrder): Promise<void> {
- assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema);
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- await assert.isValidSignatureAsync(this._provider, orderHash, signedOrder.signature, signedOrder.makerAddress);
-
- const expirationUnixTimestampMs = signedOrder.expirationTimeSeconds.times(MILLISECONDS_IN_A_SECOND);
- this._expirationWatcher.addOrder(orderHash, expirationUnixTimestampMs);
-
- this._orderByOrderHash[orderHash] = signedOrder;
- this._dependentOrderHashesTracker.addToDependentOrderHashes(signedOrder);
-
- const orderAssetDatas = [signedOrder.makerAssetData, signedOrder.takerAssetData];
- _.each(orderAssetDatas, assetData => this._addAssetDataToAbiDecoder(assetData));
- }
- /**
- * Removes an order from the orderWatcher
- * @param orderHash The orderHash of the order you wish to stop watching.
- */
- public removeOrder(orderHash: string): void {
- assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema);
- const signedOrder = this._orderByOrderHash[orderHash];
- if (_.isUndefined(signedOrder)) {
- return; // noop
- }
- this._dependentOrderHashesTracker.removeFromDependentOrderHashes(signedOrder);
- delete this._orderByOrderHash[orderHash];
- this._expirationWatcher.removeOrder(orderHash);
- delete this._orderStateByOrderHashCache[orderHash];
- }
- /**
- * Starts an orderWatcher subscription. The callback will be called every time a watched order's
- * backing blockchain state has changed. This is a call-to-action for the caller to re-validate the order.
- * @param callback Receives the orderHash of the order that should be re-validated, together
- * with all the order-relevant blockchain state needed to re-validate the order.
- */
- public subscribe(callback: OnOrderStateChangeCallback): void {
- assert.isFunction('callback', callback);
- if (!_.isUndefined(this._callbackIfExists)) {
- throw new Error(OrderWatcherError.SubscriptionAlreadyPresent);
- }
- this._callbackIfExists = callback;
- this._eventWatcher.subscribe(this._onEventWatcherCallbackAsync.bind(this));
- this._expirationWatcher.subscribe(this._onOrderExpired.bind(this));
- this._cleanupJobIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval(
- this._cleanupAsync.bind(this),
- this._cleanupJobInterval,
- (err: Error) => {
- this.unsubscribe();
- callback(err);
- },
- );
- }
- /**
- * Ends an orderWatcher subscription.
- */
- public unsubscribe(): void {
- if (_.isUndefined(this._callbackIfExists) || _.isUndefined(this._cleanupJobIntervalIdIfExists)) {
- throw new Error(OrderWatcherError.SubscriptionNotFound);
- }
- this._balanceAndProxyAllowanceLazyStore.deleteAll();
- this._orderFilledCancelledLazyStore.deleteAll();
- delete this._callbackIfExists;
- this._eventWatcher.unsubscribe();
- this._expirationWatcher.unsubscribe();
- intervalUtils.clearAsyncExcludingInterval(this._cleanupJobIntervalIdIfExists);
- }
- /**
- * Gets statistics of the OrderWatcher Instance.
- */
- public getStats(): Stats {
- return {
- orderCount: _.size(this._orderByOrderHash),
- };
- }
- private async _cleanupAsync(): Promise<void> {
- for (const orderHash of _.keys(this._orderByOrderHash)) {
- this._cleanupOrderRelatedState(orderHash);
- await this._emitRevalidateOrdersAsync([orderHash]);
- }
- }
- private _addAssetDataToAbiDecoder(assetData: string): void {
- const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData);
- if (assetDataUtils.isERC20AssetData(decodedAssetData)) {
- this._collisionResistantAbiDecoder.addERC20Token(decodedAssetData.tokenAddress);
- } else if (assetDataUtils.isERC721AssetData(decodedAssetData)) {
- this._collisionResistantAbiDecoder.addERC721Token(decodedAssetData.tokenAddress);
- } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) {
- _.each(decodedAssetData.nestedAssetData, nestedAssetDataElement =>
- this._addAssetDataToAbiDecoder(nestedAssetDataElement),
- );
- }
- }
- private _deleteLazyStoreBalance(assetData: string, userAddress: string): void {
- const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
- switch (assetProxyId) {
- case AssetProxyId.ERC20:
- case AssetProxyId.ERC721:
- this._balanceAndProxyAllowanceLazyStore.deleteBalance(assetData, userAddress);
- break;
- case AssetProxyId.MultiAsset:
- const decodedAssetData = assetDataUtils.decodeMultiAssetData(assetData);
- _.each(decodedAssetData.nestedAssetData, nestedAssetDataElement =>
- this._deleteLazyStoreBalance(nestedAssetDataElement, userAddress),
- );
- break;
- default:
- break;
- }
- }
- private _deleteLazyStoreProxyAllowance(assetData: string, userAddress: string): void {
- const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData);
- switch (assetProxyId) {
- case AssetProxyId.ERC20:
- case AssetProxyId.ERC721:
- this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(assetData, userAddress);
- break;
- case AssetProxyId.MultiAsset:
- const decodedAssetData = assetDataUtils.decodeMultiAssetData(assetData);
- _.each(decodedAssetData.nestedAssetData, nestedAssetDataElement =>
- this._deleteLazyStoreProxyAllowance(nestedAssetDataElement, userAddress),
- );
- break;
- default:
- break;
- }
- }
- private _cleanupOrderRelatedState(orderHash: string): void {
- const signedOrder = this._orderByOrderHash[orderHash];
-
- this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(orderHash);
- this._orderFilledCancelledLazyStore.deleteIsCancelled(orderHash);
-
- this._deleteLazyStoreBalance(signedOrder.makerAssetData, signedOrder.makerAddress);
- this._deleteLazyStoreProxyAllowance(signedOrder.makerAssetData, signedOrder.makerAddress);
- this._deleteLazyStoreBalance(signedOrder.takerAssetData, signedOrder.takerAddress);
- this._deleteLazyStoreProxyAllowance(signedOrder.takerAssetData, signedOrder.takerAddress);
-
- const zrxAssetData = this._orderFilledCancelledLazyStore.getZRXAssetData();
- if (!signedOrder.makerFee.isZero()) {
- this._deleteLazyStoreBalance(zrxAssetData, signedOrder.makerAddress);
- this._deleteLazyStoreProxyAllowance(zrxAssetData, signedOrder.makerAddress);
- }
- if (!signedOrder.takerFee.isZero()) {
- this._deleteLazyStoreBalance(zrxAssetData, signedOrder.takerAddress);
- this._deleteLazyStoreProxyAllowance(zrxAssetData, signedOrder.takerAddress);
- }
- }
- private _onOrderExpired(orderHash: string): void {
- const orderState: OrderState = {
- isValid: false,
- orderHash,
- error: ExchangeContractErrs.OrderFillExpired,
- };
- if (!_.isUndefined(this._orderByOrderHash[orderHash])) {
- this.removeOrder(orderHash);
- if (!_.isUndefined(this._callbackIfExists)) {
- this._callbackIfExists(null, orderState);
- }
- }
- }
- private async _onEventWatcherCallbackAsync(err: Error | null, logIfExists?: LogEntryEvent): Promise<void> {
- if (!_.isNull(err)) {
- if (!_.isUndefined(this._callbackIfExists)) {
- this._callbackIfExists(err);
- }
- return;
- }
- const maybeDecodedLog = this._collisionResistantAbiDecoder.tryToDecodeLogOrNoop<ContractEventArgs>(
- // At this moment we are sure that no error occured and log is defined.
- logIfExists as LogEntryEvent,
- );
- const isLogDecoded = !_.isUndefined(((maybeDecodedLog as any) as LogWithDecodedArgs<ContractEventArgs>).event);
- if (!isLogDecoded) {
- return; // noop
- }
- const decodedLog = (maybeDecodedLog as any) as LogWithDecodedArgs<ContractEventArgs>;
- const transactionHash = decodedLog.transactionHash;
- switch (decodedLog.event) {
- case ERC20TokenEvents.Approval:
- case ERC721TokenEvents.Approval: {
- // ERC20 and ERC721 Transfer events have the same name so we need to distinguish them by args
- if (!_.isUndefined(decodedLog.args._value)) {
- // ERC20
- // Invalidate cache
- const args = decodedLog.args as ERC20TokenApprovalEventArgs;
- const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address);
- this._deleteLazyStoreProxyAllowance(tokenAssetData, args._owner);
- // Revalidate orders
- const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
- args._owner,
- tokenAssetData,
- );
- await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
- break;
- } else {
- // ERC721
- // Invalidate cache
- const args = decodedLog.args as ERC721TokenApprovalEventArgs;
- const tokenAssetData = assetDataUtils.encodeERC721AssetData(decodedLog.address, args._tokenId);
- this._deleteLazyStoreProxyAllowance(tokenAssetData, args._owner);
- // Revalidate orders
- const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
- args._owner,
- tokenAssetData,
- );
- await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
- break;
- }
- }
- case ERC20TokenEvents.Transfer:
- case ERC721TokenEvents.Transfer: {
- // ERC20 and ERC721 Transfer events have the same name so we need to distinguish them by args
- if (!_.isUndefined(decodedLog.args._value)) {
- // ERC20
- // Invalidate cache
- const args = decodedLog.args as ERC20TokenTransferEventArgs;
- const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address);
- this._deleteLazyStoreBalance(tokenAssetData, args._from);
- this._deleteLazyStoreBalance(tokenAssetData, args._to);
- // Revalidate orders
- const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
- args._from,
- tokenAssetData,
- );
- await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
- break;
- } else {
- // ERC721
- // Invalidate cache
- const args = decodedLog.args as ERC721TokenTransferEventArgs;
- const tokenAssetData = assetDataUtils.encodeERC721AssetData(decodedLog.address, args._tokenId);
- this._deleteLazyStoreBalance(tokenAssetData, args._from);
- this._deleteLazyStoreBalance(tokenAssetData, args._to);
- // Revalidate orders
- const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
- args._from,
- tokenAssetData,
- );
- await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
- break;
- }
- }
- case ERC721TokenEvents.ApprovalForAll: {
- // Invalidate cache
- const args = decodedLog.args as ERC721TokenApprovalForAllEventArgs;
- const tokenAddress = decodedLog.address;
- this._balanceAndProxyAllowanceLazyStore.deleteAllERC721ProxyAllowance(tokenAddress, args._owner);
- // Revalidate orders
- const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByERC721ByMaker(
- args._owner,
- tokenAddress,
- );
- await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
- break;
- }
- case WETH9Events.Deposit: {
- // Invalidate cache
- const args = decodedLog.args as WETH9DepositEventArgs;
- const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address);
- this._deleteLazyStoreBalance(tokenAssetData, args._owner);
- // Revalidate orders
- const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
- args._owner,
- tokenAssetData,
- );
- await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
- break;
- }
- case WETH9Events.Withdrawal: {
- // Invalidate cache
- const args = decodedLog.args as WETH9WithdrawalEventArgs;
- const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address);
- this._deleteLazyStoreBalance(tokenAssetData, args._owner);
- // Revalidate orders
- const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker(
- args._owner,
- tokenAssetData,
- );
- await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
- break;
- }
- case ExchangeEvents.Fill: {
- // Invalidate cache
- const args = decodedLog.args as ExchangeFillEventArgs;
- this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(args.orderHash);
- // Revalidate orders
- const orderHash = args.orderHash;
- const isOrderWatched = !_.isUndefined(this._orderByOrderHash[orderHash]);
- if (isOrderWatched) {
- await this._emitRevalidateOrdersAsync([orderHash], transactionHash);
- }
- break;
- }
- case ExchangeEvents.Cancel: {
- // Invalidate cache
- const args = decodedLog.args as ExchangeCancelEventArgs;
- this._orderFilledCancelledLazyStore.deleteIsCancelled(args.orderHash);
- // Revalidate orders
- const orderHash = args.orderHash;
- const isOrderWatched = !_.isUndefined(this._orderByOrderHash[orderHash]);
- if (isOrderWatched) {
- await this._emitRevalidateOrdersAsync([orderHash], transactionHash);
- }
- break;
- }
- case ExchangeEvents.CancelUpTo: {
- // TODO(logvinov): Do it smarter and actually look at the salt and order epoch
- // Invalidate cache
- const args = decodedLog.args as ExchangeCancelUpToEventArgs;
- this._orderFilledCancelledLazyStore.deleteAllIsCancelled();
- // Revalidate orders
- const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByMaker(args.makerAddress);
- await this._emitRevalidateOrdersAsync(orderHashes, transactionHash);
- break;
- }
-
- default:
- throw errorUtils.spawnSwitchErr('decodedLog.event', decodedLog.event);
- }
- }
- private async _emitRevalidateOrdersAsync(orderHashes: string[], transactionHash?: string): Promise<void> {
- for (const orderHash of orderHashes) {
- const signedOrder = this._orderByOrderHash[orderHash];
- // Most of these calls will never reach the network because the data is fetched from stores
- // and only updated when cache is invalidated
- const orderState = await this._orderStateUtils.getOpenOrderStateAsync(signedOrder, transactionHash);
- if (_.isUndefined(this._callbackIfExists)) {
- break; // Unsubscribe was called
- }
- if (_.isEqual(orderState, this._orderStateByOrderHashCache[orderHash])) {
- // Actual order state didn't change
- continue;
- } else {
- this._orderStateByOrderHashCache[orderHash] = orderState;
- }
- this._callbackIfExists(null, orderState);
- }
- }
-}
diff --git a/packages/order-watcher/src/order_watcher/order_watcher_web_socket_server.ts b/packages/order-watcher/src/order_watcher/order_watcher_web_socket_server.ts
deleted file mode 100644
index b75b07603..000000000
--- a/packages/order-watcher/src/order_watcher/order_watcher_web_socket_server.ts
+++ /dev/null
@@ -1,200 +0,0 @@
-import { ContractAddresses } from '@0x/contract-addresses';
-import { schemas } from '@0x/json-schemas';
-import { OrderStateInvalid, OrderStateValid, SignedOrder } from '@0x/types';
-import { BigNumber, logUtils } from '@0x/utils';
-import { Provider } from 'ethereum-types';
-import * as http from 'http';
-import * as WebSocket from 'websocket';
-
-import { GetStatsResult, OrderWatcherConfig, OrderWatcherMethod, WebSocketRequest, WebSocketResponse } from '../types';
-import { assert } from '../utils/assert';
-
-import { OrderWatcher } from './order_watcher';
-
-const DEFAULT_HTTP_PORT = 8080;
-const JSON_RPC_VERSION = '2.0';
-
-// Wraps the OrderWatcher functionality in a WebSocket server. Motivations:
-// 1) Users can watch orders via non-typescript programs.
-// 2) Better encapsulation so that users can work
-export class OrderWatcherWebSocketServer {
- private readonly _orderWatcher: OrderWatcher;
- private readonly _httpServer: http.Server;
- private readonly _connectionStore: Set<WebSocket.connection>;
- private readonly _wsServer: WebSocket.server;
- private readonly _isVerbose: boolean;
- /**
- * Recover types lost when the payload is stringified.
- */
- private static _parseSignedOrder(rawRequest: any): SignedOrder {
- const bigNumberFields = [
- 'salt',
- 'makerFee',
- 'takerFee',
- 'makerAssetAmount',
- 'takerAssetAmount',
- 'expirationTimeSeconds',
- ];
- for (const field of bigNumberFields) {
- rawRequest[field] = new BigNumber(rawRequest[field]);
- }
- return rawRequest;
- }
-
- /**
- * Instantiate a new WebSocket server which provides OrderWatcher functionality
- * @param provider Web3 provider to use for JSON RPC calls.
- * @param networkId NetworkId to watch orders on.
- * @param contractAddresses Optional contract addresses. Defaults to known
- * addresses based on networkId.
- * @param orderWatcherConfig OrderWatcher configurations. isVerbose sets the verbosity for the WebSocket server aswell.
- * @param isVerbose Whether to enable verbose logging. Defaults to true.
- */
- constructor(
- provider: Provider,
- networkId: number,
- contractAddresses?: ContractAddresses,
- orderWatcherConfig?: Partial<OrderWatcherConfig>,
- ) {
- this._isVerbose =
- orderWatcherConfig !== undefined && orderWatcherConfig.isVerbose !== undefined
- ? orderWatcherConfig.isVerbose
- : true;
- this._orderWatcher = new OrderWatcher(provider, networkId, contractAddresses, orderWatcherConfig);
- this._connectionStore = new Set();
- this._httpServer = http.createServer();
- this._wsServer = new WebSocket.server({
- httpServer: this._httpServer,
- // Avoid setting autoAcceptConnections to true as it defeats all
- // standard cross-origin protection facilities built into the protocol
- // and the browser.
- // Source: https://www.npmjs.com/package/websocket#server-example
- // Also ensures that a request event is emitted by
- // the server whenever a new WebSocket request is made.
- autoAcceptConnections: false,
- });
-
- this._wsServer.on('request', async (request: any) => {
- // Designed for usage pattern where client and server are run on the same
- // machine by the same user. As such, no security checks are in place.
- const connection: WebSocket.connection = request.accept(null, request.origin);
- this._log(`${new Date()} [Server] Accepted connection from origin ${request.origin}.`);
- connection.on('message', this._onMessageCallbackAsync.bind(this, connection));
- connection.on('close', this._onCloseCallback.bind(this, connection));
- this._connectionStore.add(connection);
- });
- }
-
- /**
- * Activates the WebSocket server by subscribing to the OrderWatcher and
- * starting the WebSocket's HTTP server
- */
- public start(): void {
- // Have the WebSocket server subscribe to the OrderWatcher to receive updates.
- // These updates are then broadcast to clients in the _connectionStore.
- this._orderWatcher.subscribe(this._broadcastCallback.bind(this));
-
- const port = process.env.ORDER_WATCHER_HTTP_PORT || DEFAULT_HTTP_PORT;
- this._httpServer.listen(port, () => {
- this._log(`${new Date()} [Server] Listening on port ${port}`);
- });
- }
-
- /**
- * Deactivates the WebSocket server by stopping the HTTP server from accepting
- * new connections and unsubscribing from the OrderWatcher
- */
- public stop(): void {
- this._httpServer.close();
- this._orderWatcher.unsubscribe();
- }
-
- private _log(...args: any[]): void {
- if (this._isVerbose) {
- logUtils.log(...args);
- }
- }
-
- private async _onMessageCallbackAsync(connection: WebSocket.connection, message: any): Promise<void> {
- let response: WebSocketResponse;
- let id: number | null = null;
- try {
- assert.doesConformToSchema('message', message, schemas.orderWatcherWebSocketUtf8MessageSchema);
- const request: WebSocketRequest = JSON.parse(message.utf8Data);
- id = request.id;
- assert.doesConformToSchema('request', request, schemas.orderWatcherWebSocketRequestSchema);
- assert.isString(request.jsonrpc, JSON_RPC_VERSION);
- response = {
- id,
- jsonrpc: JSON_RPC_VERSION,
- method: request.method,
- result: await this._routeRequestAsync(request),
- };
- } catch (err) {
- response = {
- id,
- jsonrpc: JSON_RPC_VERSION,
- method: null,
- error: err.toString(),
- };
- }
- this._log(`${new Date()} [Server] OrderWatcher output: ${JSON.stringify(response)}`);
- connection.sendUTF(JSON.stringify(response));
- }
-
- private _onCloseCallback(connection: WebSocket.connection): void {
- this._connectionStore.delete(connection);
- this._log(`${new Date()} [Server] Client ${connection.remoteAddress} disconnected.`);
- }
-
- private async _routeRequestAsync(request: WebSocketRequest): Promise<GetStatsResult | undefined> {
- this._log(`${new Date()} [Server] Request received: ${request.method}`);
- switch (request.method) {
- case OrderWatcherMethod.AddOrder: {
- const signedOrder: SignedOrder = OrderWatcherWebSocketServer._parseSignedOrder(
- request.params.signedOrder,
- );
- await this._orderWatcher.addOrderAsync(signedOrder);
- break;
- }
- case OrderWatcherMethod.RemoveOrder: {
- this._orderWatcher.removeOrder(request.params.orderHash || 'undefined');
- break;
- }
- case OrderWatcherMethod.GetStats: {
- return this._orderWatcher.getStats();
- }
- default:
- // Should never reach here. Should be caught by JSON schema check.
- throw new Error(`Unexpected default case hit for request.method`);
- }
- return undefined;
- }
-
- /**
- * Broadcasts OrderState changes to ALL connected clients. At the moment,
- * we do not support clients subscribing to only a subset of orders. As such,
- * Client B will be notified of changes to an order that Client A added.
- */
- private _broadcastCallback(err: Error | null, orderState?: OrderStateValid | OrderStateInvalid | undefined): void {
- const method = OrderWatcherMethod.Update;
- const response =
- err === null
- ? {
- jsonrpc: JSON_RPC_VERSION,
- method,
- result: orderState,
- }
- : {
- jsonrpc: JSON_RPC_VERSION,
- method,
- error: {
- code: -32000,
- message: err.message,
- },
- };
- this._connectionStore.forEach((connection: WebSocket.connection) => {
- connection.sendUTF(JSON.stringify(response));
- });
- }
-}
diff --git a/packages/order-watcher/src/schemas/order_watcher_partial_config_schema.ts b/packages/order-watcher/src/schemas/order_watcher_partial_config_schema.ts
deleted file mode 100644
index 8bfced063..000000000
--- a/packages/order-watcher/src/schemas/order_watcher_partial_config_schema.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-export const orderWatcherPartialConfigSchema = {
- id: '/OrderWatcherPartialConfigSchema',
- properties: {
- stateLayer: { $ref: '/blockParamSchema' },
- orderExpirationCheckingIntervalMs: { type: 'number' },
- eventPollingIntervalMs: { type: 'number' },
- expirationMarginMs: { type: 'number' },
- cleanupJobIntervalMs: { type: 'number' },
- isVerbose: { type: 'boolean' },
- },
- type: 'object',
- required: [],
-};
diff --git a/packages/order-watcher/src/server.ts b/packages/order-watcher/src/server.ts
deleted file mode 100644
index 1d31e87ab..000000000
--- a/packages/order-watcher/src/server.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import { getContractAddressesForNetworkOrThrow } from '@0x/contract-addresses';
-import { RPCSubprovider, Web3ProviderEngine } from '@0x/subproviders';
-import * as _ from 'lodash';
-
-import { OrderWatcherWebSocketServer } from './order_watcher/order_watcher_web_socket_server';
-
-const GANACHE_NETWORK_ID = 50;
-const DEFAULT_RPC_URL = 'http://localhost:8545';
-
-const provider = new Web3ProviderEngine();
-const jsonRpcUrl = process.env.JSON_RPC_URL || DEFAULT_RPC_URL;
-const rpcSubprovider = new RPCSubprovider(jsonRpcUrl);
-provider.addProvider(rpcSubprovider);
-provider.start();
-
-const networkId = process.env.NETWORK_ID !== undefined ? _.parseInt(process.env.NETWORK_ID) : GANACHE_NETWORK_ID;
-
-const contractAddressesString = process.env.contractAddresses;
-const contractAddressesIfExists =
- contractAddressesString === undefined
- ? getContractAddressesForNetworkOrThrow(networkId)
- : JSON.parse(contractAddressesString);
-
-const orderWatcherConfig: any = {
- isVerbose: process.env.IS_VERBOSE === 'true',
-};
-const orderExpirationCheckingIntervalMs = process.env.ORDER_EXPIRATION_CHECKING_INTERVAL_MS;
-if (orderExpirationCheckingIntervalMs !== undefined) {
- orderWatcherConfig.orderExpirationCheckingIntervalMs = _.parseInt(orderExpirationCheckingIntervalMs);
-}
-const eventPollingIntervalMs = process.env.EVENT_POLLING_INTERVAL_MS;
-if (eventPollingIntervalMs !== undefined) {
- orderWatcherConfig.eventPollingIntervalMs = _.parseInt(eventPollingIntervalMs);
-}
-const expirationMarginMs = process.env.EXPIRATION_MARGIN_MS;
-if (expirationMarginMs !== undefined) {
- orderWatcherConfig.expirationMarginMs = _.parseInt(expirationMarginMs);
-}
-const cleanupJobIntervalMs = process.env.CLEANUP_JOB_INTERVAL_MS;
-if (cleanupJobIntervalMs !== undefined) {
- orderWatcherConfig.cleanupJobIntervalMs = _.parseInt(cleanupJobIntervalMs);
-}
-const wsServer = new OrderWatcherWebSocketServer(provider, networkId, contractAddressesIfExists, orderWatcherConfig);
-wsServer.start();
diff --git a/packages/order-watcher/src/types.ts b/packages/order-watcher/src/types.ts
deleted file mode 100644
index 2b529a939..000000000
--- a/packages/order-watcher/src/types.ts
+++ /dev/null
@@ -1,97 +0,0 @@
-import { OrderState, SignedOrder } from '@0x/types';
-import { LogEntryEvent } from 'ethereum-types';
-
-export enum OrderWatcherError {
- SubscriptionAlreadyPresent = 'SUBSCRIPTION_ALREADY_PRESENT',
- SubscriptionNotFound = 'SUBSCRIPTION_NOT_FOUND',
-}
-
-export type EventWatcherCallback = (err: null | Error, log?: LogEntryEvent) => void;
-
-/**
- * orderExpirationCheckingIntervalMs: How often to check for expired orders. Default=50.
- * eventPollingIntervalMs: How often to poll the Ethereum node for new events. Default=200.
- * expirationMarginMs: Amount of time before order expiry that you'd like to be notified
- * of an orders expiration. Default=0.
- * cleanupJobIntervalMs: How often to run a cleanup job which revalidates all the orders. Default=1hr.
- * isVerbose: Weather the order watcher should be verbose. Default=true.
- */
-export interface OrderWatcherConfig {
- orderExpirationCheckingIntervalMs: number;
- eventPollingIntervalMs: number;
- expirationMarginMs: number;
- cleanupJobIntervalMs: number;
- isVerbose: boolean;
-}
-
-export type OnOrderStateChangeCallback = (err: Error | null, orderState?: OrderState) => void;
-
-export enum InternalOrderWatcherError {
- NoAbiDecoder = 'NO_ABI_DECODER',
- ZrxNotInTokenRegistry = 'ZRX_NOT_IN_TOKEN_REGISTRY',
- WethNotInTokenRegistry = 'WETH_NOT_IN_TOKEN_REGISTRY',
-}
-
-export enum OrderWatcherMethod {
- // Methods initiated by the user.
- GetStats = 'GET_STATS',
- AddOrder = 'ADD_ORDER',
- RemoveOrder = 'REMOVE_ORDER',
- // These are spontaneous; they are primarily orderstate changes.
- Update = 'UPDATE',
- // `subscribe` and `unsubscribe` are methods of OrderWatcher, but we don't
- // need to expose them to the WebSocket server user because the user implicitly
- // subscribes and unsubscribes by connecting and disconnecting from the server.
-}
-
-// Users have to create a json object of this format and attach it to
-// the data field of their WebSocket message to interact with the server.
-export type WebSocketRequest = AddOrderRequest | RemoveOrderRequest | GetStatsRequest;
-
-export interface AddOrderRequest {
- id: number;
- jsonrpc: string;
- method: OrderWatcherMethod.AddOrder;
- params: { signedOrder: SignedOrder };
-}
-
-export interface RemoveOrderRequest {
- id: number;
- jsonrpc: string;
- method: OrderWatcherMethod.RemoveOrder;
- params: { orderHash: string };
-}
-
-export interface GetStatsRequest {
- id: number;
- jsonrpc: string;
- method: OrderWatcherMethod.GetStats;
-}
-
-// Users should expect a json object of this format in the data field
-// of the WebSocket messages that the server sends out.
-export type WebSocketResponse = SuccessfulWebSocketResponse | ErrorWebSocketResponse;
-
-export interface SuccessfulWebSocketResponse {
- id: number;
- jsonrpc: string;
- method: OrderWatcherMethod;
- result: OrderState | GetStatsResult | undefined; // result is undefined for ADD_ORDER and REMOVE_ORDER
-}
-
-export interface ErrorWebSocketResponse {
- id: number | null;
- jsonrpc: string;
- method: null;
- error: JSONRPCError;
-}
-
-export interface JSONRPCError {
- code: number;
- message: string;
- data?: string | object;
-}
-
-export interface GetStatsResult {
- orderCount: number;
-}
diff --git a/packages/order-watcher/src/utils/assert.ts b/packages/order-watcher/src/utils/assert.ts
deleted file mode 100644
index ccfc7325c..000000000
--- a/packages/order-watcher/src/utils/assert.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { assert as sharedAssert } from '@0x/assert';
-// HACK: We need those two unused imports because they're actually used by sharedAssert which gets injected here
-// tslint:disable:no-unused-variable
-import { Schema } from '@0x/json-schemas';
-import { ECSignature } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-// tslint:enable:no-unused-variable
-import { Provider } from 'ethereum-types';
-
-import { signatureUtils } from '@0x/order-utils';
-
-export const assert = {
- ...sharedAssert,
- async isValidSignatureAsync(
- provider: Provider,
- orderHash: string,
- signature: string,
- signerAddress: string,
- ): Promise<void> {
- const isValid = await signatureUtils.isValidSignatureAsync(provider, orderHash, signature, signerAddress);
- assert.assert(isValid, `Expected order with hash '${orderHash}' to have a valid signature`);
- },
-};
diff --git a/packages/order-watcher/src/utils/utils.ts b/packages/order-watcher/src/utils/utils.ts
deleted file mode 100644
index 9c3849ff1..000000000
--- a/packages/order-watcher/src/utils/utils.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { BigNumber } from '@0x/utils';
-
-export const utils = {
- getCurrentUnixTimestampSec(): BigNumber {
- const milisecondsInASecond = 1000;
- return new BigNumber(Date.now() / milisecondsInASecond).integerValue();
- },
- getCurrentUnixTimestampMs(): BigNumber {
- return new BigNumber(Date.now());
- },
-};
diff --git a/packages/order-watcher/test/expiration_watcher_test.ts b/packages/order-watcher/test/expiration_watcher_test.ts
deleted file mode 100644
index fb5ea2a27..000000000
--- a/packages/order-watcher/test/expiration_watcher_test.ts
+++ /dev/null
@@ -1,199 +0,0 @@
-import { tokenUtils } from '@0x/contract-wrappers/lib/test/utils/token_utils';
-import { BlockchainLifecycle, callbackErrorReporter } from '@0x/dev-utils';
-import { FillScenarios } from '@0x/fill-scenarios';
-import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
-import { DoneCallback } from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-import 'mocha';
-import * as Sinon from 'sinon';
-
-import { ExpirationWatcher } from '../src/order_watcher/expiration_watcher';
-import { utils } from '../src/utils/utils';
-
-import { chaiSetup } from './utils/chai_setup';
-import { migrateOnceAsync } from './utils/migrate';
-import { provider, web3Wrapper } from './utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-const MILISECONDS_IN_SECOND = 1000;
-
-describe('ExpirationWatcher', () => {
- let userAddresses: string[];
- let fillScenarios: FillScenarios;
- let makerAssetData: string;
- let takerAssetData: string;
- let coinbase: string;
- let makerAddress: string;
- let takerAddress: string;
- let feeRecipient: string;
- const fillableAmount = new BigNumber(5);
- let currentUnixTimestampSec: BigNumber;
- let timer: Sinon.SinonFakeTimers;
- let expirationWatcher: ExpirationWatcher;
- before(async () => {
- const contractAddresses = await migrateOnceAsync();
- await blockchainLifecycle.startAsync();
- userAddresses = await web3Wrapper.getAvailableAddressesAsync();
- fillScenarios = new FillScenarios(
- provider,
- userAddresses,
- contractAddresses.zrxToken,
- contractAddresses.exchange,
- contractAddresses.erc20Proxy,
- contractAddresses.erc721Proxy,
- );
- [coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses;
- const [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses();
- [makerAssetData, takerAssetData] = [
- assetDataUtils.encodeERC20AssetData(makerTokenAddress),
- assetDataUtils.encodeERC20AssetData(takerTokenAddress),
- ];
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- const sinonTimerConfig = { shouldAdvanceTime: true } as any;
- // This constructor has incorrect types
- timer = Sinon.useFakeTimers(sinonTimerConfig);
- currentUnixTimestampSec = utils.getCurrentUnixTimestampSec();
- expirationWatcher = new ExpirationWatcher();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- timer.restore();
- expirationWatcher.unsubscribe();
- });
- it('correctly emits events when order expires', (done: DoneCallback) => {
- (async () => {
- const orderLifetimeSec = 60;
- const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec);
- const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- expirationUnixTimestampSec,
- );
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- expirationWatcher.addOrder(orderHash, signedOrder.expirationTimeSeconds.times(MILISECONDS_IN_SECOND));
- const callbackAsync = callbackErrorReporter.reportNoErrorCallbackErrors(done)((hash: string) => {
- expect(hash).to.be.equal(orderHash);
- expect(utils.getCurrentUnixTimestampSec()).to.be.bignumber.gte(expirationUnixTimestampSec);
- });
- expirationWatcher.subscribe(callbackAsync);
- timer.tick(orderLifetimeSec * MILISECONDS_IN_SECOND);
- })().catch(done);
- });
- it("doesn't emit events before order expires", (done: DoneCallback) => {
- (async () => {
- const orderLifetimeSec = 60;
- const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec);
- const signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- expirationUnixTimestampSec,
- );
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- expirationWatcher.addOrder(orderHash, signedOrder.expirationTimeSeconds.times(MILISECONDS_IN_SECOND));
- const callbackAsync = callbackErrorReporter.reportNoErrorCallbackErrors(done)(async (_hash: string) => {
- done(new Error('Emitted expiration went before the order actually expired'));
- });
- expirationWatcher.subscribe(callbackAsync);
- const notEnoughTime = orderLifetimeSec - 1;
- timer.tick(notEnoughTime * MILISECONDS_IN_SECOND);
- done();
- })().catch(done);
- });
- it('emits events in correct order', (done: DoneCallback) => {
- (async () => {
- const order1Lifetime = 60;
- const order2Lifetime = 120;
- const order1ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order1Lifetime);
- const order2ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order2Lifetime);
- const signedOrder1 = await fillScenarios.createFillableSignedOrderAsync(
- makerAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- order1ExpirationUnixTimestampSec,
- );
- const signedOrder2 = await fillScenarios.createFillableSignedOrderAsync(
- makerAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- order2ExpirationUnixTimestampSec,
- );
- const orderHash1 = orderHashUtils.getOrderHashHex(signedOrder1);
- const orderHash2 = orderHashUtils.getOrderHashHex(signedOrder2);
- expirationWatcher.addOrder(orderHash2, signedOrder2.expirationTimeSeconds.times(MILISECONDS_IN_SECOND));
- expirationWatcher.addOrder(orderHash1, signedOrder1.expirationTimeSeconds.times(MILISECONDS_IN_SECOND));
- const expirationOrder = [orderHash1, orderHash2];
- const expectToBeCalledOnce = false;
- const callbackAsync = callbackErrorReporter.reportNoErrorCallbackErrors(done, expectToBeCalledOnce)(
- (hash: string) => {
- const orderHash = expirationOrder.shift();
- expect(hash).to.be.equal(orderHash);
- if (_.isEmpty(expirationOrder)) {
- done();
- }
- },
- );
- expirationWatcher.subscribe(callbackAsync);
- timer.tick(order2Lifetime * MILISECONDS_IN_SECOND);
- })().catch(done);
- });
- it('emits events in correct order when expirations are equal', (done: DoneCallback) => {
- (async () => {
- const order1Lifetime = 60;
- const order2Lifetime = 60;
- const order1ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order1Lifetime);
- const order2ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order2Lifetime);
- const signedOrder1 = await fillScenarios.createFillableSignedOrderAsync(
- makerAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- order1ExpirationUnixTimestampSec,
- );
- const signedOrder2 = await fillScenarios.createFillableSignedOrderAsync(
- makerAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- order2ExpirationUnixTimestampSec,
- );
- const orderHash1 = orderHashUtils.getOrderHashHex(signedOrder1);
- const orderHash2 = orderHashUtils.getOrderHashHex(signedOrder2);
- expirationWatcher.addOrder(orderHash1, signedOrder1.expirationTimeSeconds.times(MILISECONDS_IN_SECOND));
- expirationWatcher.addOrder(orderHash2, signedOrder2.expirationTimeSeconds.times(MILISECONDS_IN_SECOND));
- const expirationOrder = orderHash1 < orderHash2 ? [orderHash1, orderHash2] : [orderHash2, orderHash1];
- const expectToBeCalledOnce = false;
- const callbackAsync = callbackErrorReporter.reportNoErrorCallbackErrors(done, expectToBeCalledOnce)(
- (hash: string) => {
- const orderHash = expirationOrder.shift();
- expect(hash).to.be.equal(orderHash);
- if (_.isEmpty(expirationOrder)) {
- done();
- }
- },
- );
- expirationWatcher.subscribe(callbackAsync);
- timer.tick(order2Lifetime * MILISECONDS_IN_SECOND);
- })().catch(done);
- });
-});
diff --git a/packages/order-watcher/test/global_hooks.ts b/packages/order-watcher/test/global_hooks.ts
deleted file mode 100644
index 26c37158f..000000000
--- a/packages/order-watcher/test/global_hooks.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-before('set up mocha', async function(): Promise<void> {
- // HACK: Since the migrations take longer then our global mocha timeout limit
- // we manually increase it for this before hook.
- const mochaTestTimeoutMs = 25000;
- this.timeout(mochaTestTimeoutMs); // tslint:disable-line:no-invalid-this
-});
diff --git a/packages/order-watcher/test/order_watcher_test.ts b/packages/order-watcher/test/order_watcher_test.ts
deleted file mode 100644
index 28b564b32..000000000
--- a/packages/order-watcher/test/order_watcher_test.ts
+++ /dev/null
@@ -1,887 +0,0 @@
-// tslint:disable:no-unnecessary-type-assertion
-import { ContractWrappers } from '@0x/contract-wrappers';
-import { tokenUtils } from '@0x/contract-wrappers/lib/test/utils/token_utils';
-import { BlockchainLifecycle, callbackErrorReporter } from '@0x/dev-utils';
-import { FillScenarios } from '@0x/fill-scenarios';
-import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
-import {
- DoneCallback,
- ExchangeContractErrs,
- OrderState,
- OrderStateInvalid,
- OrderStateValid,
- SignedOrder,
-} from '@0x/types';
-import { BigNumber } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as chai from 'chai';
-import * as _ from 'lodash';
-import 'mocha';
-
-import {
- DependentOrderHashesTracker,
- OrderHashesByERC20ByMakerAddress,
-} from '../src/order_watcher/dependent_order_hashes_tracker';
-import { OrderWatcher } from '../src/order_watcher/order_watcher';
-import { OrderWatcherError } from '../src/types';
-
-import { chaiSetup } from './utils/chai_setup';
-import { constants } from './utils/constants';
-import { migrateOnceAsync } from './utils/migrate';
-import { provider, web3Wrapper } from './utils/web3_wrapper';
-
-const TIMEOUT_MS = 150;
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-describe('OrderWatcher', () => {
- let contractWrappers: ContractWrappers;
- let fillScenarios: FillScenarios;
- let userAddresses: string[];
- let zrxTokenAddress: string;
- let makerAssetData: string;
- let takerAssetData: string;
- let makerTokenAddress: string;
- let takerTokenAddress: string;
- let makerAddress: string;
- let takerAddress: string;
- let coinbase: string;
- let feeRecipient: string;
- let signedOrder: SignedOrder;
- let orderWatcher: OrderWatcher;
- const decimals = constants.ZRX_DECIMALS;
- const fillableAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(5), decimals);
- before(async () => {
- const contractAddresses = await migrateOnceAsync();
- await blockchainLifecycle.startAsync();
- const networkId = constants.TESTRPC_NETWORK_ID;
- const config = {
- networkId,
- contractAddresses,
- };
- contractWrappers = new ContractWrappers(provider, config);
- userAddresses = await web3Wrapper.getAvailableAddressesAsync();
- zrxTokenAddress = contractAddresses.zrxToken;
- fillScenarios = new FillScenarios(
- provider,
- userAddresses,
- zrxTokenAddress,
- contractAddresses.exchange,
- contractAddresses.erc20Proxy,
- contractAddresses.erc721Proxy,
- );
- [coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses;
- [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses();
- [makerAssetData, takerAssetData] = [
- assetDataUtils.encodeERC20AssetData(makerTokenAddress),
- assetDataUtils.encodeERC20AssetData(takerTokenAddress),
- ];
- const orderWatcherConfig = {};
- orderWatcher = new OrderWatcher(provider, networkId, contractAddresses, orderWatcherConfig);
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- beforeEach(async () => {
- await blockchainLifecycle.startAsync();
- });
- afterEach(async () => {
- await blockchainLifecycle.revertAsync();
- });
- describe('#removeOrder', async () => {
- it('should successfully remove existing order', async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- await orderWatcher.addOrderAsync(signedOrder);
- expect((orderWatcher as any)._orderByOrderHash).to.include({
- [orderHash]: signedOrder,
- });
- const dependentOrderHashesTracker = (orderWatcher as any)
- ._dependentOrderHashesTracker as DependentOrderHashesTracker;
- let orderHashesByERC20ByMakerAddress: OrderHashesByERC20ByMakerAddress = (dependentOrderHashesTracker as any)
- ._orderHashesByERC20ByMakerAddress;
- expect(orderHashesByERC20ByMakerAddress[signedOrder.makerAddress][makerTokenAddress]).to.have.keys(
- orderHash,
- );
- orderWatcher.removeOrder(orderHash);
- expect((orderWatcher as any)._orderByOrderHash).to.not.include({
- [orderHash]: signedOrder,
- });
- orderHashesByERC20ByMakerAddress = (dependentOrderHashesTracker as any)._orderHashesByERC20ByMakerAddress;
- expect(orderHashesByERC20ByMakerAddress[signedOrder.makerAddress]).to.be.undefined();
- });
- it('should no-op when removing a non-existing order', async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- const nonExistentOrderHash = `0x${orderHash
- .substr(2)
- .split('')
- .reverse()
- .join('')}`;
- orderWatcher.removeOrder(nonExistentOrderHash);
- });
- });
- describe('#subscribe', async () => {
- afterEach(async () => {
- orderWatcher.unsubscribe();
- });
- it('should fail when trying to subscribe twice', async () => {
- orderWatcher.subscribe(_.noop.bind(_));
- expect(() => orderWatcher.subscribe(_.noop.bind(_))).to.throw(OrderWatcherError.SubscriptionAlreadyPresent);
- });
- });
- describe('#getStats', async () => {
- it('orderCount should increment and decrement with order additions and removals', async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- expect(orderWatcher.getStats().orderCount).to.be.eq(0);
- await orderWatcher.addOrderAsync(signedOrder);
- expect(orderWatcher.getStats().orderCount).to.be.eq(1);
- orderWatcher.removeOrder(orderHash);
- expect(orderWatcher.getStats().orderCount).to.be.eq(0);
- });
- });
- describe('tests with cleanup', async () => {
- afterEach(async () => {
- orderWatcher.unsubscribe();
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- orderWatcher.removeOrder(orderHash);
- });
- it('should emit orderStateInvalid when makerAddress allowance set to 0 for watched order', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- await orderWatcher.addOrderAsync(signedOrder);
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.false();
- const invalidOrderState = orderState as OrderStateInvalid;
- expect(invalidOrderState.orderHash).to.be.equal(orderHash);
- expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance);
- });
- orderWatcher.subscribe(callback);
- await contractWrappers.erc20Token.setProxyAllowanceAsync(
- makerTokenAddress,
- makerAddress,
- new BigNumber(0),
- );
- })().catch(done);
- });
- it('should not emit an orderState event when irrelevant Transfer event received', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- await orderWatcher.addOrderAsync(signedOrder);
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((_orderState: OrderState) => {
- throw new Error('OrderState callback fired for irrelevant order');
- });
- orderWatcher.subscribe(callback);
- const notTheMaker = userAddresses[0];
- const anyRecipient = takerAddress;
- const transferAmount = new BigNumber(2);
- await contractWrappers.erc20Token.transferAsync(
- makerTokenAddress,
- notTheMaker,
- anyRecipient,
- transferAmount,
- );
- setTimeout(() => {
- done();
- }, TIMEOUT_MS);
- })().catch(done);
- });
- it('should emit orderStateInvalid when makerAddress moves balance backing watched order', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- await orderWatcher.addOrderAsync(signedOrder);
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.false();
- const invalidOrderState = orderState as OrderStateInvalid;
- expect(invalidOrderState.orderHash).to.be.equal(orderHash);
- expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerBalance);
- });
- orderWatcher.subscribe(callback);
- const anyRecipient = takerAddress;
- const makerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, makerAddress);
- await contractWrappers.erc20Token.transferAsync(
- makerTokenAddress,
- makerAddress,
- anyRecipient,
- makerBalance,
- );
- })().catch(done);
- });
- it('should emit orderStateInvalid when watched order fully filled', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- await orderWatcher.addOrderAsync(signedOrder);
-
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.false();
- const invalidOrderState = orderState as OrderStateInvalid;
- expect(invalidOrderState.orderHash).to.be.equal(orderHash);
- expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderRemainingFillAmountZero);
- });
- orderWatcher.subscribe(callback);
-
- await contractWrappers.exchange.fillOrderAsync(signedOrder, fillableAmount, takerAddress);
- })().catch(done);
- });
- it('should include transactionHash in emitted orderStateInvalid when watched order fully filled', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- await orderWatcher.addOrderAsync(signedOrder);
-
- let transactionHash: string;
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.false();
- const invalidOrderState = orderState as OrderStateInvalid;
- expect(invalidOrderState.transactionHash).to.be.equal(transactionHash);
- });
- orderWatcher.subscribe(callback);
-
- transactionHash = await contractWrappers.exchange.fillOrderAsync(
- signedOrder,
- fillableAmount,
- takerAddress,
- );
- })().catch(done);
- });
- it('should emit orderStateValid when watched order partially filled', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
-
- const makerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, makerAddress);
- const fillAmountInBaseUnits = new BigNumber(2);
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- await orderWatcher.addOrderAsync(signedOrder);
-
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.true();
- const validOrderState = orderState as OrderStateValid;
- expect(validOrderState.orderHash).to.be.equal(orderHash);
- const orderRelevantState = validOrderState.orderRelevantState;
- const remainingMakerBalance = makerBalance.minus(fillAmountInBaseUnits);
- const remainingFillable = fillableAmount.minus(fillAmountInBaseUnits);
- expect(orderRelevantState.remainingFillableMakerAssetAmount).to.be.bignumber.equal(
- remainingFillable,
- );
- expect(orderRelevantState.remainingFillableTakerAssetAmount).to.be.bignumber.equal(
- remainingFillable,
- );
- expect(orderRelevantState.makerBalance).to.be.bignumber.equal(remainingMakerBalance);
- });
- orderWatcher.subscribe(callback);
- await contractWrappers.exchange.fillOrderAsync(signedOrder, fillAmountInBaseUnits, takerAddress);
- })().catch(done);
- });
- it('should trigger the callback when orders backing ZRX allowance changes', (done: DoneCallback) => {
- (async () => {
- const makerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(2), decimals);
- const takerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(0), decimals);
- signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- makerAssetData,
- takerAssetData,
- makerFee,
- takerFee,
- makerAddress,
- takerAddress,
- fillableAmount,
- takerAddress,
- );
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)();
- await orderWatcher.addOrderAsync(signedOrder);
- orderWatcher.subscribe(callback);
- await contractWrappers.erc20Token.setProxyAllowanceAsync(
- zrxTokenAddress,
- makerAddress,
- new BigNumber(0),
- );
- })().catch(done);
- });
- describe('remainingFillable(M|T)akerTokenAmount', () => {
- it('should calculate correct remaining fillable', (done: DoneCallback) => {
- (async () => {
- const takerFillableAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(10), decimals);
- const makerFillableAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(20), decimals);
- signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
- makerAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- makerFillableAmount,
- takerFillableAmount,
- );
- const fillAmountInBaseUnits = Web3Wrapper.toBaseUnitAmount(new BigNumber(2), decimals);
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- await orderWatcher.addOrderAsync(signedOrder);
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.true();
- const validOrderState = orderState as OrderStateValid;
- expect(validOrderState.orderHash).to.be.equal(orderHash);
- const orderRelevantState = validOrderState.orderRelevantState;
- expect(orderRelevantState.remainingFillableMakerAssetAmount).to.be.bignumber.equal(
- Web3Wrapper.toBaseUnitAmount(new BigNumber(16), decimals),
- );
- expect(orderRelevantState.remainingFillableTakerAssetAmount).to.be.bignumber.equal(
- Web3Wrapper.toBaseUnitAmount(new BigNumber(8), decimals),
- );
- });
- orderWatcher.subscribe(callback);
- await contractWrappers.exchange.fillOrderAsync(signedOrder, fillAmountInBaseUnits, takerAddress);
- })().catch(done);
- });
- it('should equal approved amount when approved amount is lowest', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
-
- const changedMakerApprovalAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(3), decimals);
- await orderWatcher.addOrderAsync(signedOrder);
-
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
- const validOrderState = orderState as OrderStateValid;
- const orderRelevantState = validOrderState.orderRelevantState;
- expect(orderRelevantState.remainingFillableMakerAssetAmount).to.be.bignumber.equal(
- changedMakerApprovalAmount,
- );
- expect(orderRelevantState.remainingFillableTakerAssetAmount).to.be.bignumber.equal(
- changedMakerApprovalAmount,
- );
- });
- orderWatcher.subscribe(callback);
- await contractWrappers.erc20Token.setProxyAllowanceAsync(
- makerTokenAddress,
- makerAddress,
- changedMakerApprovalAmount,
- );
- })().catch(done);
- });
- it('should equal balance amount when balance amount is lowest', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
-
- const makerBalance = await contractWrappers.erc20Token.getBalanceAsync(
- makerTokenAddress,
- makerAddress,
- );
-
- const remainingAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), decimals);
- const transferAmount = makerBalance.minus(remainingAmount);
- await orderWatcher.addOrderAsync(signedOrder);
-
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.true();
- const validOrderState = orderState as OrderStateValid;
- const orderRelevantState = validOrderState.orderRelevantState;
- expect(orderRelevantState.remainingFillableMakerAssetAmount).to.be.bignumber.equal(
- remainingAmount,
- );
- expect(orderRelevantState.remainingFillableTakerAssetAmount).to.be.bignumber.equal(
- remainingAmount,
- );
- });
- orderWatcher.subscribe(callback);
- await contractWrappers.erc20Token.transferAsync(
- makerTokenAddress,
- makerAddress,
- constants.NULL_ADDRESS,
- transferAmount,
- );
- })().catch(done);
- });
- it('should equal ratio amount when fee balance is lowered', (done: DoneCallback) => {
- (async () => {
- const takerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(0), decimals);
- const makerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(5), decimals);
- signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- makerAssetData,
- takerAssetData,
- makerFee,
- takerFee,
- makerAddress,
- takerAddress,
- fillableAmount,
- feeRecipient,
- );
-
- const remainingFeeAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(3), decimals);
-
- const remainingTokenAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(4), decimals);
- const transferTokenAmount = makerFee.minus(remainingTokenAmount);
- await orderWatcher.addOrderAsync(signedOrder);
-
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
- const validOrderState = orderState as OrderStateValid;
- const orderRelevantState = validOrderState.orderRelevantState;
- expect(orderRelevantState.remainingFillableMakerAssetAmount).to.be.bignumber.equal(
- remainingFeeAmount,
- );
- });
- orderWatcher.subscribe(callback);
- await contractWrappers.erc20Token.setProxyAllowanceAsync(
- zrxTokenAddress,
- makerAddress,
- remainingFeeAmount,
- );
- await contractWrappers.erc20Token.transferAsync(
- makerTokenAddress,
- makerAddress,
- constants.NULL_ADDRESS,
- transferTokenAmount,
- );
- })().catch(done);
- });
- it('should calculate full amount when all available and non-divisible', (done: DoneCallback) => {
- (async () => {
- const takerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(0), decimals);
- const makerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(2), decimals);
- signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- makerAssetData,
- takerAssetData,
- makerFee,
- takerFee,
- makerAddress,
- takerAddress,
- fillableAmount,
- feeRecipient,
- );
-
- await orderWatcher.addOrderAsync(signedOrder);
-
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
- const validOrderState = orderState as OrderStateValid;
- const orderRelevantState = validOrderState.orderRelevantState;
- expect(orderRelevantState.remainingFillableMakerAssetAmount).to.be.bignumber.equal(
- fillableAmount,
- );
- });
- orderWatcher.subscribe(callback);
- await contractWrappers.erc20Token.setProxyAllowanceAsync(
- makerTokenAddress,
- makerAddress,
- Web3Wrapper.toBaseUnitAmount(new BigNumber(100), decimals),
- );
- })().catch(done);
- });
- });
- it('should emit orderStateInvalid when watched order cancelled', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- await orderWatcher.addOrderAsync(signedOrder);
-
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.false();
- const invalidOrderState = orderState as OrderStateInvalid;
- expect(invalidOrderState.orderHash).to.be.equal(orderHash);
- expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderCancelled);
- });
- orderWatcher.subscribe(callback);
- await contractWrappers.exchange.cancelOrderAsync(signedOrder);
- })().catch(done);
- });
- it('should emit orderStateInvalid when within rounding error range after a partial fill', (done: DoneCallback) => {
- (async () => {
- const fillAmountInBaseUnits = new BigNumber(2);
- const makerAssetAmount = new BigNumber(1001);
- const takerAssetAmount = new BigNumber(3);
- signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync(
- makerAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- makerAssetAmount,
- takerAssetAmount,
- );
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- await orderWatcher.addOrderAsync(signedOrder);
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.false();
- const invalidOrderState = orderState as OrderStateInvalid;
- expect(invalidOrderState.orderHash).to.be.equal(orderHash);
- expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderFillRoundingError);
- });
- orderWatcher.subscribe(callback);
- await contractWrappers.exchange.fillOrderAsync(signedOrder, fillAmountInBaseUnits, takerAddress);
- })().catch(done);
- });
- describe('erc721', () => {
- let makerErc721AssetData: string;
- let makerErc721TokenAddress: string;
- const tokenId = new BigNumber(42);
- [makerErc721TokenAddress] = tokenUtils.getDummyERC721TokenAddresses();
- makerErc721AssetData = assetDataUtils.encodeERC721AssetData(makerErc721TokenAddress, tokenId);
- const fillableErc721Amount = new BigNumber(1);
- it('should emit orderStateInvalid when maker allowance set to 0 for watched order', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerErc721AssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableErc721Amount,
- );
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- await orderWatcher.addOrderAsync(signedOrder);
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.false();
- const invalidOrderState = orderState as OrderStateInvalid;
- expect(invalidOrderState.orderHash).to.be.equal(orderHash);
- expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance);
- });
- orderWatcher.subscribe(callback);
- await contractWrappers.erc721Token.setApprovalAsync(
- makerErc721TokenAddress,
- constants.NULL_ADDRESS,
- tokenId,
- );
- })().catch(done);
- });
- it('should emit orderStateInvalid when maker allowance for all set to 0 for watched order', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerErc721AssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableErc721Amount,
- );
- await contractWrappers.erc721Token.setApprovalAsync(
- makerErc721TokenAddress,
- constants.NULL_ADDRESS,
- tokenId,
- );
- let isApproved = true;
- await contractWrappers.erc721Token.setProxyApprovalForAllAsync(
- makerErc721TokenAddress,
- makerAddress,
- isApproved,
- );
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- await orderWatcher.addOrderAsync(signedOrder);
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.false();
- const invalidOrderState = orderState as OrderStateInvalid;
- expect(invalidOrderState.orderHash).to.be.equal(orderHash);
- expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance);
- });
- orderWatcher.subscribe(callback);
- isApproved = false;
- await contractWrappers.erc721Token.setProxyApprovalForAllAsync(
- makerErc721TokenAddress,
- makerAddress,
- isApproved,
- );
- })().catch(done);
- });
- it('should emit orderStateInvalid when maker moves NFT backing watched order', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerErc721AssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableErc721Amount,
- );
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- await orderWatcher.addOrderAsync(signedOrder);
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.false();
- const invalidOrderState = orderState as OrderStateInvalid;
- expect(invalidOrderState.orderHash).to.be.equal(orderHash);
- expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerBalance);
- });
- orderWatcher.subscribe(callback);
- await contractWrappers.erc721Token.transferFromAsync(
- makerErc721TokenAddress,
- coinbase,
- makerAddress,
- tokenId,
- );
- })().catch(done);
- });
- });
- describe('multiAsset', async () => {
- const tokenId = new BigNumber(42);
- const [makerErc721TokenAddress] = tokenUtils.getDummyERC721TokenAddresses();
- const makerErc721AssetData = assetDataUtils.encodeERC721AssetData(makerErc721TokenAddress, tokenId);
- const fillableErc721Amount = new BigNumber(1);
- const [makerErc20TokenAddress] = tokenUtils.getDummyERC20TokenAddresses();
- const makerErc20AssetData = assetDataUtils.encodeERC20AssetData(makerErc20TokenAddress);
- const fillableErc20Amount = new BigNumber(2);
- const multiAssetAmounts = [fillableErc721Amount, fillableErc20Amount];
- const nestedAssetData = [makerErc721AssetData, makerErc20AssetData];
- const makerMultiAssetData = assetDataUtils.encodeMultiAssetData(multiAssetAmounts, nestedAssetData);
- it('should emit orderStateInvalid when maker allowance of ERC721 token set to 0 for watched order', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerMultiAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableErc721Amount,
- );
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- await orderWatcher.addOrderAsync(signedOrder);
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.false();
- const invalidOrderState = orderState as OrderStateInvalid;
- expect(invalidOrderState.orderHash).to.be.equal(orderHash);
- expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance);
- });
- orderWatcher.subscribe(callback);
- await contractWrappers.erc721Token.setApprovalAsync(
- makerErc721TokenAddress,
- constants.NULL_ADDRESS,
- tokenId,
- );
- })().catch(done);
- });
- it('should emit orderStateInvalid when maker allowance for all of ERC721 token set to 0 for watched order', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerMultiAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableErc721Amount,
- );
- await contractWrappers.erc721Token.setApprovalAsync(
- makerErc721TokenAddress,
- constants.NULL_ADDRESS,
- tokenId,
- );
- let isApproved = true;
- await contractWrappers.erc721Token.setProxyApprovalForAllAsync(
- makerErc721TokenAddress,
- makerAddress,
- isApproved,
- );
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- await orderWatcher.addOrderAsync(signedOrder);
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.false();
- const invalidOrderState = orderState as OrderStateInvalid;
- expect(invalidOrderState.orderHash).to.be.equal(orderHash);
- expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance);
- });
- orderWatcher.subscribe(callback);
- isApproved = false;
- await contractWrappers.erc721Token.setProxyApprovalForAllAsync(
- makerErc721TokenAddress,
- makerAddress,
- isApproved,
- );
- })().catch(done);
- });
- it('should emit orderStateInvalid when maker moves ERC721 backing watched order', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerMultiAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableErc721Amount,
- );
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- await orderWatcher.addOrderAsync(signedOrder);
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.false();
- const invalidOrderState = orderState as OrderStateInvalid;
- expect(invalidOrderState.orderHash).to.be.equal(orderHash);
- expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerBalance);
- });
- orderWatcher.subscribe(callback);
- await contractWrappers.erc721Token.transferFromAsync(
- makerErc721TokenAddress,
- coinbase,
- makerAddress,
- tokenId,
- );
- })().catch(done);
- });
- it('should emit orderStateInvalid when maker allowance of ERC20 token set to 0 for watched order', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerMultiAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableErc721Amount,
- );
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- await orderWatcher.addOrderAsync(signedOrder);
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.false();
- const invalidOrderState = orderState as OrderStateInvalid;
- expect(invalidOrderState.orderHash).to.be.equal(orderHash);
- expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance);
- });
- orderWatcher.subscribe(callback);
- await contractWrappers.erc20Token.setProxyAllowanceAsync(
- makerErc20TokenAddress,
- makerAddress,
- new BigNumber(0),
- );
- })().catch(done);
- });
- it('should not emit an orderState event when irrelevant ERC20 Transfer event received', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerMultiAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- await orderWatcher.addOrderAsync(signedOrder);
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((_orderState: OrderState) => {
- throw new Error('OrderState callback fired for irrelevant order');
- });
- orderWatcher.subscribe(callback);
- const notTheMaker = userAddresses[0];
- const anyRecipient = takerAddress;
- const transferAmount = new BigNumber(2);
- await contractWrappers.erc20Token.transferAsync(
- makerTokenAddress,
- notTheMaker,
- anyRecipient,
- transferAmount,
- );
- setTimeout(() => {
- done();
- }, TIMEOUT_MS);
- })().catch(done);
- });
- it('should emit orderStateInvalid when makerAddress moves ERC20 balance backing watched order', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerMultiAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- await orderWatcher.addOrderAsync(signedOrder);
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.false();
- const invalidOrderState = orderState as OrderStateInvalid;
- expect(invalidOrderState.orderHash).to.be.equal(orderHash);
- expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerBalance);
- });
- orderWatcher.subscribe(callback);
- const anyRecipient = takerAddress;
- const makerBalance = await contractWrappers.erc20Token.getBalanceAsync(
- makerTokenAddress,
- makerAddress,
- );
- await contractWrappers.erc20Token.transferAsync(
- makerTokenAddress,
- makerAddress,
- anyRecipient,
- makerBalance,
- );
- })().catch(done);
- });
- // TODO(abandeali1): The following test will fail until the MAP has been deployed and activated.
- it.skip('should emit orderStateInvalid when watched order fully filled', (done: DoneCallback) => {
- (async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerMultiAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- const orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- await orderWatcher.addOrderAsync(signedOrder);
-
- const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => {
- expect(orderState.isValid).to.be.false();
- const invalidOrderState = orderState as OrderStateInvalid;
- expect(invalidOrderState.orderHash).to.be.equal(orderHash);
- expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderRemainingFillAmountZero);
- });
- orderWatcher.subscribe(callback);
-
- await contractWrappers.exchange.fillOrderAsync(signedOrder, fillableAmount, takerAddress);
- })().catch(done);
- });
- });
- });
-}); // tslint:disable:max-file-line-count
diff --git a/packages/order-watcher/test/order_watcher_web_socket_server_test.ts b/packages/order-watcher/test/order_watcher_web_socket_server_test.ts
deleted file mode 100644
index 36135f65c..000000000
--- a/packages/order-watcher/test/order_watcher_web_socket_server_test.ts
+++ /dev/null
@@ -1,312 +0,0 @@
-import { ContractAddresses } from '@0x/contract-addresses';
-import { ContractWrappers } from '@0x/contract-wrappers';
-import { tokenUtils } from '@0x/contract-wrappers/lib/test/utils/token_utils';
-import { BlockchainLifecycle } from '@0x/dev-utils';
-import { FillScenarios } from '@0x/fill-scenarios';
-import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
-import { ExchangeContractErrs, OrderStateInvalid, SignedOrder } from '@0x/types';
-import { BigNumber, logUtils } from '@0x/utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import * as chai from 'chai';
-import 'mocha';
-import * as WebSocket from 'websocket';
-
-import { OrderWatcherWebSocketServer } from '../src/order_watcher/order_watcher_web_socket_server';
-import { AddOrderRequest, OrderWatcherMethod, RemoveOrderRequest } from '../src/types';
-
-import { chaiSetup } from './utils/chai_setup';
-import { constants } from './utils/constants';
-import { migrateOnceAsync } from './utils/migrate';
-import { provider, web3Wrapper } from './utils/web3_wrapper';
-
-chaiSetup.configure();
-const expect = chai.expect;
-const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
-
-interface WsMessage {
- data: string;
-}
-
-describe('OrderWatcherWebSocketServer', async () => {
- let contractWrappers: ContractWrappers;
- let wsServer: OrderWatcherWebSocketServer;
- let wsClient: WebSocket.w3cwebsocket;
- let wsClientTwo: WebSocket.w3cwebsocket;
- let fillScenarios: FillScenarios;
- let userAddresses: string[];
- let makerAssetData: string;
- let takerAssetData: string;
- let makerTokenAddress: string;
- let takerTokenAddress: string;
- let makerAddress: string;
- let takerAddress: string;
- let zrxTokenAddress: string;
- let signedOrder: SignedOrder;
- let orderHash: string;
- let addOrderPayload: AddOrderRequest;
- let removeOrderPayload: RemoveOrderRequest;
- let networkId: number;
- let contractAddresses: ContractAddresses;
- const decimals = constants.ZRX_DECIMALS;
- const fillableAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(5), decimals);
-
- before(async () => {
- // Set up constants
- contractAddresses = await migrateOnceAsync();
- await blockchainLifecycle.startAsync();
- networkId = constants.TESTRPC_NETWORK_ID;
- const config = {
- networkId,
- contractAddresses,
- };
- contractWrappers = new ContractWrappers(provider, config);
- userAddresses = await web3Wrapper.getAvailableAddressesAsync();
- zrxTokenAddress = contractAddresses.zrxToken;
- [makerAddress, takerAddress] = userAddresses;
- [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses();
- [makerAssetData, takerAssetData] = [
- assetDataUtils.encodeERC20AssetData(makerTokenAddress),
- assetDataUtils.encodeERC20AssetData(takerTokenAddress),
- ];
- fillScenarios = new FillScenarios(
- provider,
- userAddresses,
- zrxTokenAddress,
- contractAddresses.exchange,
- contractAddresses.erc20Proxy,
- contractAddresses.erc721Proxy,
- );
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerAssetData,
- takerAssetData,
- makerAddress,
- takerAddress,
- fillableAmount,
- );
- orderHash = orderHashUtils.getOrderHashHex(signedOrder);
- addOrderPayload = {
- id: 1,
- jsonrpc: '2.0',
- method: OrderWatcherMethod.AddOrder,
- params: { signedOrder },
- };
- removeOrderPayload = {
- id: 1,
- jsonrpc: '2.0',
- method: OrderWatcherMethod.RemoveOrder,
- params: { orderHash },
- };
- });
- after(async () => {
- await blockchainLifecycle.revertAsync();
- });
- beforeEach(async () => {
- // Prepare OrderWatcher WebSocket server
- const orderWatcherConfig = {
- isVerbose: true,
- };
- wsServer = new OrderWatcherWebSocketServer(provider, networkId, contractAddresses, orderWatcherConfig);
- wsServer.start();
- await blockchainLifecycle.startAsync();
- wsClient = new WebSocket.w3cwebsocket('ws://127.0.0.1:8080/');
- logUtils.log(`${new Date()} [Client] Connected.`);
- });
- afterEach(async () => {
- wsClient.close();
- await blockchainLifecycle.revertAsync();
- wsServer.stop();
- logUtils.log(`${new Date()} [Client] Closed.`);
- });
-
- it('responds to getStats requests correctly', (done: any) => {
- const payload = {
- id: 1,
- jsonrpc: '2.0',
- method: 'GET_STATS',
- };
- wsClient.onopen = () => wsClient.send(JSON.stringify(payload));
- wsClient.onmessage = (msg: any) => {
- const responseData = JSON.parse(msg.data);
- expect(responseData.id).to.be.eq(1);
- expect(responseData.jsonrpc).to.be.eq('2.0');
- expect(responseData.method).to.be.eq('GET_STATS');
- expect(responseData.result.orderCount).to.be.eq(0);
- done();
- };
- });
-
- it('throws an error when an invalid method is attempted', async () => {
- const invalidMethodPayload = {
- id: 1,
- jsonrpc: '2.0',
- method: 'BAD_METHOD',
- };
- wsClient.onopen = () => wsClient.send(JSON.stringify(invalidMethodPayload));
- const errorMsg = await onMessageAsync(wsClient, null);
- const errorData = JSON.parse(errorMsg.data);
- // tslint:disable-next-line:no-unused-expression
- expect(errorData.id).to.be.null;
- // tslint:disable-next-line:no-unused-expression
- expect(errorData.method).to.be.null;
- expect(errorData.jsonrpc).to.be.eq('2.0');
- expect(errorData.error).to.match(/^Error: Expected request to conform to schema/);
- });
-
- it('throws an error when jsonrpc field missing from request', async () => {
- const noJsonRpcPayload = {
- id: 1,
- method: 'GET_STATS',
- };
- wsClient.onopen = () => wsClient.send(JSON.stringify(noJsonRpcPayload));
- const errorMsg = await onMessageAsync(wsClient, null);
- const errorData = JSON.parse(errorMsg.data);
- // tslint:disable-next-line:no-unused-expression
- expect(errorData.method).to.be.null;
- expect(errorData.jsonrpc).to.be.eq('2.0');
- expect(errorData.error).to.match(/^Error: Expected request to conform to schema/);
- });
-
- it('throws an error when we try to add an order without a signedOrder', async () => {
- const noSignedOrderAddOrderPayload = {
- id: 1,
- jsonrpc: '2.0',
- method: 'ADD_ORDER',
- orderHash: '0x7337e2f2a9aa2ed6afe26edc2df7ad79c3ffa9cf9b81a964f707ea63f5272355',
- };
- wsClient.onopen = () => wsClient.send(JSON.stringify(noSignedOrderAddOrderPayload));
- const errorMsg = await onMessageAsync(wsClient, null);
- const errorData = JSON.parse(errorMsg.data);
- // tslint:disable-next-line:no-unused-expression
- expect(errorData.id).to.be.null;
- // tslint:disable-next-line:no-unused-expression
- expect(errorData.method).to.be.null;
- expect(errorData.jsonrpc).to.be.eq('2.0');
- expect(errorData.error).to.match(/^Error: Expected request to conform to schema/);
- });
-
- it('throws an error when we try to add a bad signedOrder', async () => {
- const invalidAddOrderPayload = {
- id: 1,
- jsonrpc: '2.0',
- method: 'ADD_ORDER',
- signedOrder: {
- makerAddress: '0x0',
- },
- };
- wsClient.onopen = () => wsClient.send(JSON.stringify(invalidAddOrderPayload));
- const errorMsg = await onMessageAsync(wsClient, null);
- const errorData = JSON.parse(errorMsg.data);
- // tslint:disable-next-line:no-unused-expression
- expect(errorData.id).to.be.null;
- // tslint:disable-next-line:no-unused-expression
- expect(errorData.method).to.be.null;
- expect(errorData.error).to.match(/^Error: Expected request to conform to schema/);
- });
-
- it('executes addOrder and removeOrder requests correctly', async () => {
- wsClient.onopen = () => wsClient.send(JSON.stringify(addOrderPayload));
- const addOrderMsg = await onMessageAsync(wsClient, OrderWatcherMethod.AddOrder);
- const addOrderData = JSON.parse(addOrderMsg.data);
- expect(addOrderData.method).to.be.eq('ADD_ORDER');
- expect((wsServer as any)._orderWatcher._orderByOrderHash).to.deep.include({
- [orderHash]: signedOrder,
- });
-
- const clientOnMessagePromise = onMessageAsync(wsClient, OrderWatcherMethod.RemoveOrder);
- wsClient.send(JSON.stringify(removeOrderPayload));
- const removeOrderMsg = await clientOnMessagePromise;
- const removeOrderData = JSON.parse(removeOrderMsg.data);
- expect(removeOrderData.method).to.be.eq('REMOVE_ORDER');
- expect((wsServer as any)._orderWatcher._orderByOrderHash).to.not.deep.include({
- [orderHash]: signedOrder,
- });
- });
-
- it('broadcasts orderStateInvalid message when makerAddress allowance set to 0 for watched order', async () => {
- // Add the regular order
- wsClient.onopen = () => wsClient.send(JSON.stringify(addOrderPayload));
-
- // We register the onMessage callback before calling `setProxyAllowanceAsync` which we
- // expect will cause a message to be emitted. We do now "await" here, since we want to
- // check for messages _after_ calling `setProxyAllowanceAsync`
- const clientOnMessagePromise = onMessageAsync(wsClient, OrderWatcherMethod.Update);
-
- // Set the allowance to 0
- await contractWrappers.erc20Token.setProxyAllowanceAsync(makerTokenAddress, makerAddress, new BigNumber(0));
-
- // We now await the `onMessage` promise to check for the message
- const orderWatcherUpdateMsg = await clientOnMessagePromise;
- const orderWatcherUpdateData = JSON.parse(orderWatcherUpdateMsg.data);
- expect(orderWatcherUpdateData.method).to.be.eq('UPDATE');
- const invalidOrderState = orderWatcherUpdateData.result as OrderStateInvalid;
- expect(invalidOrderState.isValid).to.be.false();
- expect(invalidOrderState.orderHash).to.be.eq(orderHash);
- expect(invalidOrderState.error).to.be.eq(ExchangeContractErrs.InsufficientMakerAllowance);
- });
-
- it('broadcasts to multiple clients when an order backing ZRX allowance changes', async () => {
- // Prepare order
- const makerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(2), decimals);
- const takerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(0), decimals);
- const nonZeroMakerFeeSignedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- makerAssetData,
- takerAssetData,
- makerFee,
- takerFee,
- makerAddress,
- takerAddress,
- fillableAmount,
- takerAddress,
- );
- const nonZeroMakerFeeOrderPayload = {
- id: 1,
- jsonrpc: '2.0',
- method: 'ADD_ORDER',
- params: {
- signedOrder: nonZeroMakerFeeSignedOrder,
- },
- };
-
- // Set up a second client and have it add the order
- wsClientTwo = new WebSocket.w3cwebsocket('ws://127.0.0.1:8080/');
- logUtils.log(`${new Date()} [Client] Connected.`);
- wsClientTwo.onopen = () => wsClientTwo.send(JSON.stringify(nonZeroMakerFeeOrderPayload));
-
- // Setup the onMessage callbacks, but don't await them yet
- const clientOneOnMessagePromise = onMessageAsync(wsClient, OrderWatcherMethod.Update);
- const clientTwoOnMessagePromise = onMessageAsync(wsClientTwo, OrderWatcherMethod.Update);
-
- // Change the allowance
- await contractWrappers.erc20Token.setProxyAllowanceAsync(zrxTokenAddress, makerAddress, new BigNumber(0));
-
- // Check that both clients receive the emitted event by awaiting the onMessageAsync promises
- let updateMsg = await clientOneOnMessagePromise;
- let updateData = JSON.parse(updateMsg.data);
- let orderState = updateData.result as OrderStateInvalid;
- expect(orderState.isValid).to.be.false();
- expect(orderState.error).to.be.eq('INSUFFICIENT_MAKER_FEE_ALLOWANCE');
-
- updateMsg = await clientTwoOnMessagePromise;
- updateData = JSON.parse(updateMsg.data);
- orderState = updateData.result as OrderStateInvalid;
- expect(orderState.isValid).to.be.false();
- expect(orderState.error).to.be.eq('INSUFFICIENT_MAKER_FEE_ALLOWANCE');
-
- wsClientTwo.close();
- logUtils.log(`${new Date()} [Client] Closed.`);
- });
-});
-
-// HACK: createFillableSignedOrderAsync is Promise-based, which forces us
-// to use Promises instead of the done() callbacks for tests.
-// onmessage callback must thus be wrapped as a Promise.
-async function onMessageAsync(client: WebSocket.w3cwebsocket, method: string | null): Promise<WsMessage> {
- return new Promise<WsMessage>(resolve => {
- client.onmessage = (msg: WsMessage) => {
- const data = JSON.parse(msg.data);
- if (data.method === method) {
- resolve(msg);
- }
- };
- });
-}
diff --git a/packages/order-watcher/test/utils/chai_setup.ts b/packages/order-watcher/test/utils/chai_setup.ts
deleted file mode 100644
index 1a8733093..000000000
--- a/packages/order-watcher/test/utils/chai_setup.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import * as chai from 'chai';
-import chaiAsPromised = require('chai-as-promised');
-import ChaiBigNumber = require('chai-bignumber');
-import * as dirtyChai from 'dirty-chai';
-
-export const chaiSetup = {
- configure(): void {
- chai.config.includeStack = true;
- chai.use(ChaiBigNumber());
- chai.use(dirtyChai);
- chai.use(chaiAsPromised);
- },
-};
diff --git a/packages/order-watcher/test/utils/constants.ts b/packages/order-watcher/test/utils/constants.ts
deleted file mode 100644
index 78037647c..000000000
--- a/packages/order-watcher/test/utils/constants.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export const constants = {
- NULL_ADDRESS: '0x0000000000000000000000000000000000000000',
- TESTRPC_NETWORK_ID: 50,
- ZRX_DECIMALS: 18,
-};
diff --git a/packages/order-watcher/test/utils/migrate.ts b/packages/order-watcher/test/utils/migrate.ts
deleted file mode 100644
index 665ce0faa..000000000
--- a/packages/order-watcher/test/utils/migrate.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { ContractAddresses } from '@0x/contract-addresses';
-import { devConstants } from '@0x/dev-utils';
-import { runMigrationsOnceAsync } from '@0x/migrations';
-
-import { provider } from './web3_wrapper';
-
-/**
- * Configures and runs the migrations exactly once. Any subsequent times this is
- * called, it returns the cached addresses.
- * @returns The addresses of contracts that were deployed during the migrations.
- */
-export async function migrateOnceAsync(): Promise<ContractAddresses> {
- const txDefaults = {
- gas: devConstants.GAS_LIMIT,
- from: devConstants.TESTRPC_FIRST_ADDRESS,
- };
- return runMigrationsOnceAsync(provider, txDefaults);
-}
diff --git a/packages/order-watcher/test/utils/web3_wrapper.ts b/packages/order-watcher/test/utils/web3_wrapper.ts
deleted file mode 100644
index accfcb7fe..000000000
--- a/packages/order-watcher/test/utils/web3_wrapper.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { web3Factory } from '@0x/dev-utils';
-import { Web3Wrapper } from '@0x/web3-wrapper';
-import { Provider } from 'ethereum-types';
-
-const provider: Provider = web3Factory.getRpcProvider({ shouldUseInProcessGanache: true });
-const web3Wrapper = new Web3Wrapper(provider);
-
-export { provider, web3Wrapper };
diff --git a/packages/order-watcher/tsconfig.json b/packages/order-watcher/tsconfig.json
deleted file mode 100644
index 2ee711adc..000000000
--- a/packages/order-watcher/tsconfig.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "extends": "../../tsconfig",
- "compilerOptions": {
- "outDir": "lib",
- "rootDir": "."
- },
- "include": ["./src/**/*", "./test/**/*"]
-}
diff --git a/packages/order-watcher/tslint.json b/packages/order-watcher/tslint.json
deleted file mode 100644
index 4ade3b924..000000000
--- a/packages/order-watcher/tslint.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "rules": {
- "prefer-readonly": true
- },
- "extends": ["@0x/tslint-config"]
-}
diff --git a/packages/order-watcher/typedoc-tsconfig.json b/packages/order-watcher/typedoc-tsconfig.json
deleted file mode 100644
index c9b0af1ae..000000000
--- a/packages/order-watcher/typedoc-tsconfig.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "extends": "../../typedoc-tsconfig",
- "compilerOptions": {
- "outDir": "lib"
- },
- "include": ["./src/**/*", "./test/**/*"]
-}