From a8128c577298000b13e4d596ac5716abdb48a3a3 Mon Sep 17 00:00:00 2001 From: Xianny <8582774+xianny@users.noreply.github.com> Date: Wed, 14 Aug 2019 14:34:59 -0700 Subject: [PATCH] Remove order-watcher (#2067) * remove order-watcher --- .circleci/config.yml | 8 - .github/autolabeler.yml | 1 - README.md | 3 +- package.json | 2 +- packages/0x.js/CHANGELOG.json | 8 + packages/0x.js/README.md | 2 +- packages/0x.js/package.json | 1 - packages/0x.js/src/index.ts | 9 - packages/json-schemas/CHANGELOG.json | 8 + ...der_watcher_web_socket_request_schema.json | 52 - ...atcher_web_socket_utf8_message_schema.json | 10 - packages/json-schemas/src/schemas.ts | 4 - packages/json-schemas/tsconfig.json | 2 - packages/order-watcher/.npmignore | 9 - packages/order-watcher/CHANGELOG.json | 598 ----------- packages/order-watcher/CHANGELOG.md | 255 ----- packages/order-watcher/Dockerfile | 13 - packages/order-watcher/README.md | 169 ---- packages/order-watcher/coverage/.gitkeep | 0 packages/order-watcher/package.json | 86 -- packages/order-watcher/src/index.ts | 33 - .../collision_resistant_abi_decoder.ts | 57 -- .../dependent_order_hashes_tracker.ts | 245 ----- .../src/order_watcher/event_watcher.ts | 156 --- .../src/order_watcher/expiration_watcher.ts | 89 -- .../src/order_watcher/order_watcher.ts | 514 ---------- .../order_watcher_web_socket_server.ts | 200 ---- .../order_watcher_partial_config_schema.ts | 13 - packages/order-watcher/src/server.ts | 45 - packages/order-watcher/src/types.ts | 97 -- packages/order-watcher/src/utils/assert.ts | 28 - packages/order-watcher/src/utils/utils.ts | 11 - .../test/expiration_watcher_test.ts | 198 ---- packages/order-watcher/test/global_hooks.ts | 6 - .../order-watcher/test/order_watcher_test.ts | 938 ------------------ .../order_watcher_web_socket_server_test.ts | 311 ------ .../order-watcher/test/utils/chai_setup.ts | 13 - .../order-watcher/test/utils/constants.ts | 5 - packages/order-watcher/test/utils/migrate.ts | 18 - .../order-watcher/test/utils/web3_wrapper.ts | 8 - packages/order-watcher/tsconfig.json | 8 - packages/order-watcher/tslint.json | 6 - packages/order-watcher/typedoc-tsconfig.json | 7 - packages/sra-spec/src/md/introduction.md | 2 +- .../md/docs/order_watcher/1/installation.md | 17 - .../md/docs/order_watcher/1/introduction.md | 1 - .../md/docs/order_watcher/2/installation.md | 17 - .../md/docs/order_watcher/2/introduction.md | 3 - packages/website/public/sitemap.txt | 1 - .../containers/order_watcher_documentation.ts | 47 - packages/website/ts/index.tsx | 7 - .../ts/pages/documentation/doc_page.tsx | 1 - .../ts/pages/documentation/docs_home.tsx | 8 - packages/website/ts/types.ts | 3 - python-packages/sra_client/README.md | 2 +- tsconfig.json | 1 - 56 files changed, 21 insertions(+), 4335 deletions(-) delete mode 100644 packages/json-schemas/schemas/order_watcher_web_socket_request_schema.json delete mode 100644 packages/json-schemas/schemas/order_watcher_web_socket_utf8_message_schema.json delete mode 100644 packages/order-watcher/.npmignore delete mode 100644 packages/order-watcher/CHANGELOG.json delete mode 100644 packages/order-watcher/CHANGELOG.md delete mode 100644 packages/order-watcher/Dockerfile delete mode 100644 packages/order-watcher/README.md delete mode 100644 packages/order-watcher/coverage/.gitkeep delete mode 100644 packages/order-watcher/package.json delete mode 100644 packages/order-watcher/src/index.ts delete mode 100644 packages/order-watcher/src/order_watcher/collision_resistant_abi_decoder.ts delete mode 100644 packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts delete mode 100644 packages/order-watcher/src/order_watcher/event_watcher.ts delete mode 100644 packages/order-watcher/src/order_watcher/expiration_watcher.ts delete mode 100644 packages/order-watcher/src/order_watcher/order_watcher.ts delete mode 100644 packages/order-watcher/src/order_watcher/order_watcher_web_socket_server.ts delete mode 100644 packages/order-watcher/src/schemas/order_watcher_partial_config_schema.ts delete mode 100644 packages/order-watcher/src/server.ts delete mode 100644 packages/order-watcher/src/types.ts delete mode 100644 packages/order-watcher/src/utils/assert.ts delete mode 100644 packages/order-watcher/src/utils/utils.ts delete mode 100644 packages/order-watcher/test/expiration_watcher_test.ts delete mode 100644 packages/order-watcher/test/global_hooks.ts delete mode 100644 packages/order-watcher/test/order_watcher_test.ts delete mode 100644 packages/order-watcher/test/order_watcher_web_socket_server_test.ts delete mode 100644 packages/order-watcher/test/utils/chai_setup.ts delete mode 100644 packages/order-watcher/test/utils/constants.ts delete mode 100644 packages/order-watcher/test/utils/migrate.ts delete mode 100644 packages/order-watcher/test/utils/web3_wrapper.ts delete mode 100644 packages/order-watcher/tsconfig.json delete mode 100644 packages/order-watcher/tslint.json delete mode 100644 packages/order-watcher/typedoc-tsconfig.json delete mode 100644 packages/website/md/docs/order_watcher/1/installation.md delete mode 100644 packages/website/md/docs/order_watcher/1/introduction.md delete mode 100644 packages/website/md/docs/order_watcher/2/installation.md delete mode 100644 packages/website/md/docs/order_watcher/2/introduction.md delete mode 100644 packages/website/ts/containers/order_watcher_documentation.ts diff --git a/.circleci/config.yml b/.circleci/config.yml index 57aed10ce2..c30a5c87e2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -109,7 +109,6 @@ jobs: - run: yarn wsrun test:circleci @0x/dev-utils - run: yarn wsrun test:circleci @0x/json-schemas - run: yarn wsrun test:circleci @0x/order-utils - - run: yarn wsrun test:circleci @0x/order-watcher - run: yarn wsrun test:circleci @0x/sol-compiler - run: yarn wsrun test:circleci @0x/sol-tracing-utils - run: yarn wsrun test:circleci @0x/sol-doc @@ -153,10 +152,6 @@ jobs: key: coverage-order-utils-{{ .Environment.CIRCLE_SHA1 }} paths: - ~/repo/packages/order-utils/coverage/lcov.info - - save_cache: - key: coverage-order-watcher-{{ .Environment.CIRCLE_SHA1 }} - paths: - - ~/repo/packages/order-watcher/coverage/lcov.info - save_cache: key: coverage-sol-compiler-{{ .Environment.CIRCLE_SHA1 }} paths: @@ -350,9 +345,6 @@ jobs: - restore_cache: keys: - coverage-order-utils-{{ .Environment.CIRCLE_SHA1 }} - - restore_cache: - keys: - - coverage-order-watcher-{{ .Environment.CIRCLE_SHA1 }} - restore_cache: keys: - coverage-sol-compiler-{{ .Environment.CIRCLE_SHA1 }} diff --git a/.github/autolabeler.yml b/.github/autolabeler.yml index 93de7be30b..56e045a82e 100644 --- a/.github/autolabeler.yml +++ b/.github/autolabeler.yml @@ -21,7 +21,6 @@ contracts: ['contracts'] @0x/utils: ['packages/utils'] @0x/tslint-config: ['packages/tslint-config'] @0x/asset-buyer: ['packages/asset-buyer'] -@0x/order-watcher: ['packages/order-watcher'] @0x/order-utils: ['packages/order-utils'] @0x/assert: ['packages/assert'] @0x/base-contract: ['packages/base-contract'] diff --git a/README.md b/README.md index b22fa67f82..0e25ed58b1 100644 --- a/README.md +++ b/README.md @@ -63,8 +63,7 @@ These packages are all under development. See [/contracts/README.md](/contracts/ | [`@0x/contract-addresses`](/packages/contract-addresses) | [![npm](https://img.shields.io/npm/v/@0x/contract-addresses.svg)](https://www.npmjs.com/package/@0x/contract-addresses) | A tiny utility library for getting known deployed contract addresses for a particular network. | | [`@0x/contract-wrappers`](/packages/contract-wrappers) | [![npm](https://img.shields.io/npm/v/@0x/contract-wrappers.svg)](https://www.npmjs.com/package/@0x/contract-wrappers) | JS/TS wrappers for interacting with the 0x smart contracts | | [`@0x/order-utils`](/packages/order-utils) | [![npm](https://img.shields.io/npm/v/@0x/order-utils.svg)](https://www.npmjs.com/package/@0x/order-utils) | A set of utilities for generating, parsing, signing and validating 0x orders | -| [`@0x/json-schemas`](/packages/json-schemas) | [![npm](https://img.shields.io/npm/v/@0x/json-schemas.svg)](https://www.npmjs.com/package/@0x/json-schemas) | 0x-related JSON schemas | -| [`@0x/order-watcher`](/packages/order-watcher) | [![npm](https://img.shields.io/npm/v/@0x/order-watcher.svg)](https://www.npmjs.com/package/@0x/order-watcher) | An order watcher daemon that watches for order validity | +| [`@0x/json-schemas`](/packages/json-schemas) | [![npm](https://img.shields.io/npm/v/@0x/json-schemas.svg)](https://www.npmjs.com/package/@0x/json-schemas) | 0x-related JSON schemas | | | [`@0x/migrations`](/packages/migrations) | [![npm](https://img.shields.io/npm/v/@0x/migrations.svg)](https://www.npmjs.com/package/@0x/migrations) | Migration tool for deploying 0x smart contracts on private testnets | | [`@0x/contract-artifacts`](/packages/contract-artifacts) | [![npm](https://img.shields.io/npm/v/@0x/contract-artifacts.svg)](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts | | [`@0x/abi-gen-wrappers`](/packages/abi-gen-wrappers) | [![npm](https://img.shields.io/npm/v/@0x/abi-gen-wrappers.svg)](https://www.npmjs.com/package/@0x/abi-gen-wrappers) | Low-level 0x smart contract wrappers generated using `@0x/abi-gen` | diff --git a/package.json b/package.json index fcb13cadcd..934e2e5610 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "config": { "contractsPackages": "@0x/contracts-asset-proxy @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-exchange-libs @0x/contracts-extensions @0x/contracts-multisig @0x/contracts-test-utils @0x/contracts-utils @0x/contracts-coordinator @0x/contracts-dev-utils", "mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic", - "packagesWithDocPages": "0x.js connect json-schemas subproviders web3-wrapper order-utils order-watcher sol-compiler sol-coverage sol-profiler sol-trace ethereum-types asset-buyer migrations", + "packagesWithDocPages": "0x.js connect json-schemas subproviders web3-wrapper order-utils sol-compiler sol-coverage sol-profiler sol-trace ethereum-types asset-buyer migrations", "ignoreDependencyVersions": "@types/styled-components @types/node", "ignoreDependencyVersionsForPackage": "website instant dev-tools-pages contract-wrappers" }, diff --git a/packages/0x.js/CHANGELOG.json b/packages/0x.js/CHANGELOG.json index 59fcf3a706..862d91dd88 100644 --- a/packages/0x.js/CHANGELOG.json +++ b/packages/0x.js/CHANGELOG.json @@ -1,4 +1,12 @@ [ + { + "version": "7.0.0", + "changes": [ + { + "note": "Removed @0x/order-watcher" + } + ] + }, { "timestamp": 1565296576, "version": "6.0.15", diff --git a/packages/0x.js/README.md b/packages/0x.js/README.md index 5b7a2308cb..30d61f0d8b 100644 --- a/packages/0x.js/README.md +++ b/packages/0x.js/README.md @@ -1,6 +1,6 @@ ## 0x.js -A TypeScript/Javascript library for interacting with the 0x protocol. It is a high level package which combines a number of underlying packages such as order-utils and order-watcher. +A TypeScript/Javascript library for interacting with the 0x protocol. It is a high level package which combines a number of underlying packages such as order-utils and asset-data-utils. ### Read the [Documentation](https://0xproject.com/docs/0x.js). diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json index cc2b8898aa..83f44b0a8a 100644 --- a/packages/0x.js/package.json +++ b/packages/0x.js/package.json @@ -78,7 +78,6 @@ "@0x/base-contract": "^5.3.1", "@0x/contract-wrappers": "9.1.7", "@0x/order-utils": "^8.2.5", - "@0x/order-watcher": "^4.0.17", "@0x/subproviders": "^5.0.1", "@0x/types": "^2.4.1", "@0x/typescript-typings": "^4.2.4", diff --git a/packages/0x.js/src/index.ts b/packages/0x.js/src/index.ts index 8d3890babe..b79026f287 100644 --- a/packages/0x.js/src/index.ts +++ b/packages/0x.js/src/index.ts @@ -71,8 +71,6 @@ export { ExchangeEvents, } from '@0x/abi-gen-wrappers'; -export { OrderWatcher, OnOrderStateChangeCallback, OrderWatcherConfig } from '@0x/order-watcher'; - export import Web3ProviderEngine = require('web3-provider-engine'); export { @@ -88,14 +86,10 @@ export { AbiDecoder, DecodedCalldata } from '@0x/utils'; export { BigNumber } from '@0x/utils'; export { - ExchangeContractErrs, Order, SignedOrder, DutchAuctionData, ECSignature, - OrderStateValid, - OrderStateInvalid, - OrderState, AssetProxyId, AssetData, SingleAssetData, @@ -106,9 +100,6 @@ export { MultiAssetDataWithRecursiveDecoding, StaticCallAssetData, SignatureType, - ObjectMap, - OrderRelevantState, - Stats, ZeroExTransaction, SignedZeroExTransaction, } from '@0x/types'; diff --git a/packages/json-schemas/CHANGELOG.json b/packages/json-schemas/CHANGELOG.json index b23b488eac..c2c70f40b9 100644 --- a/packages/json-schemas/CHANGELOG.json +++ b/packages/json-schemas/CHANGELOG.json @@ -1,4 +1,12 @@ [ + { + "version": "4.0.0", + "changes": [ + { + "note": "Removed @0x/order-watcher" + } + ] + }, { "timestamp": 1565296576, "version": "3.1.13", diff --git a/packages/json-schemas/schemas/order_watcher_web_socket_request_schema.json b/packages/json-schemas/schemas/order_watcher_web_socket_request_schema.json deleted file mode 100644 index b0c419f94f..0000000000 --- a/packages/json-schemas/schemas/order_watcher_web_socket_request_schema.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "id": "/orderWatcherWebSocketRequestSchema", - "type": "object", - "definitions": { - "signedOrderParam": { - "type": "object", - "properties": { - "signedOrder": { "$ref": "/signedOrderSchema" } - }, - "required": ["signedOrder"] - }, - "orderHashParam": { - "type": "object", - "properties": { - "orderHash": { "$ref": "/hexSchema" } - }, - "required": ["orderHash"] - } - }, - "oneOf": [ - { - "type": "object", - "properties": { - "id": { "type": "number" }, - "jsonrpc": { "type": "string" }, - "method": { "enum": ["ADD_ORDER"] }, - "params": { "$ref": "#/definitions/signedOrderParam" } - }, - "required": ["id", "jsonrpc", "method", "params"] - }, - { - "type": "object", - "properties": { - "id": { "type": "number" }, - "jsonrpc": { "type": "string" }, - "method": { "enum": ["REMOVE_ORDER"] }, - "params": { "$ref": "#/definitions/orderHashParam" } - }, - "required": ["id", "jsonrpc", "method", "params"] - }, - { - "type": "object", - "properties": { - "id": { "type": "number" }, - "jsonrpc": { "type": "string" }, - "method": { "enum": ["GET_STATS"] }, - "params": {} - }, - "required": ["id", "jsonrpc", "method"] - } - ] -} \ No newline at end of file diff --git a/packages/json-schemas/schemas/order_watcher_web_socket_utf8_message_schema.json b/packages/json-schemas/schemas/order_watcher_web_socket_utf8_message_schema.json deleted file mode 100644 index 154d6d754d..0000000000 --- a/packages/json-schemas/schemas/order_watcher_web_socket_utf8_message_schema.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "id": "/orderWatcherWebSocketUtf8MessageSchema", - "properties": { - "utf8Data": { "type": "string" } - }, - "required": [ - "utf8Data" - ], - "type": "object" -} diff --git a/packages/json-schemas/src/schemas.ts b/packages/json-schemas/src/schemas.ts index 9e8eb6959f..44673383d3 100644 --- a/packages/json-schemas/src/schemas.ts +++ b/packages/json-schemas/src/schemas.ts @@ -16,8 +16,6 @@ import * as orderFillOrKillRequestsSchema from '../schemas/order_fill_or_kill_re import * as orderFillRequestsSchema from '../schemas/order_fill_requests_schema.json'; import * as orderHashSchema from '../schemas/order_hash_schema.json'; import * as orderSchema from '../schemas/order_schema.json'; -import * as orderWatcherWebSocketRequestSchema from '../schemas/order_watcher_web_socket_request_schema.json'; -import * as orderWatcherWebSocketUtf8MessageSchema from '../schemas/order_watcher_web_socket_utf8_message_schema.json'; import * as orderBookRequestSchema from '../schemas/orderbook_request_schema.json'; import * as ordersRequestOptsSchema from '../schemas/orders_request_opts_schema.json'; import * as ordersSchema from '../schemas/orders_schema.json'; @@ -68,8 +66,6 @@ export const schemas = { jsNumber, requestOptsSchema, pagedRequestOptsSchema, - orderWatcherWebSocketRequestSchema, - orderWatcherWebSocketUtf8MessageSchema, ordersRequestOptsSchema, orderBookRequestSchema, orderConfigRequestSchema, diff --git a/packages/json-schemas/tsconfig.json b/packages/json-schemas/tsconfig.json index 7d7ce1d7e6..11e68b6fb6 100644 --- a/packages/json-schemas/tsconfig.json +++ b/packages/json-schemas/tsconfig.json @@ -23,8 +23,6 @@ "./schemas/order_schema.json", "./schemas/signed_order_schema.json", "./schemas/orders_schema.json", - "./schemas/order_watcher_web_socket_request_schema.json", - "./schemas/order_watcher_web_socket_utf8_message_schema.json", "./schemas/paginated_collection_schema.json", "./schemas/relayer_api_asset_data_pairs_response_schema.json", "./schemas/relayer_api_asset_data_pairs_schema.json", diff --git a/packages/order-watcher/.npmignore b/packages/order-watcher/.npmignore deleted file mode 100644 index ea588d4859..0000000000 --- a/packages/order-watcher/.npmignore +++ /dev/null @@ -1,9 +0,0 @@ -# Blacklist all files -.* -* -# Whitelist lib -!lib/**/* -# Blacklist tests and publish scripts -/lib/test/* -/lib/monorepo_scripts/ -# Package specific ignore diff --git a/packages/order-watcher/CHANGELOG.json b/packages/order-watcher/CHANGELOG.json deleted file mode 100644 index bcc5903b58..0000000000 --- a/packages/order-watcher/CHANGELOG.json +++ /dev/null @@ -1,598 +0,0 @@ -[ - { - "timestamp": 1565296576, - "version": "4.0.17", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1564604963, - "version": "4.0.16", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563957393, - "version": "4.0.15", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563193019, - "version": "4.0.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563047529, - "version": "4.0.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563006338, - "version": "4.0.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1558712885, - "version": "4.0.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557961111, - "version": "4.0.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "4.0.9", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1557799313 - }, - { - "version": "4.0.7", - "changes": [ - { - "note": "Fix race-condition bug due to async callback modifying shared state", - "pr": 1789 - }, - { - "note": "Fix bug where WETH deposit/withdrawal events would not trigger an order state update", - "pr": 1809 - } - ], - "timestamp": 1557507213 - }, - { - "version": "4.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1554997931 - }, - { - "timestamp": 1553183790, - "version": "4.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "4.0.4", - "changes": [ - { - "note": "Update websocket from ^1.0.25 to ^1.0.26", - "pr": 1685 - }, - { - "note": "Fix issue where ERC721 Approval events could cause a lookup on undefined object", - "pr": 1692 - }, - { - "note": "Fix race-condition bugs due to async event callbacks modifying shared state", - "pr": 1718 - }, - { - "note": "Run Web3ProviderEngine without excess block polling", - "pr": 1695 - } - ], - "timestamp": 1553091633 - }, - { - "timestamp": 1551479279, - "version": "4.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551299797, - "version": "4.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551220833, - "version": "4.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "4.0.0", - "changes": [ - { - "note": "Add support for EIP1193 providers & Web3.js providers >= 1.0-beta.38", - "pr": 1627 - }, - { - "note": "Update provider params to type SupportedProvider which outlines all supported providers", - "pr": 1627 - } - ], - "timestamp": 1551130135 - }, - { - "timestamp": 1549733923, - "version": "3.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1549547375 - }, - { - "timestamp": 1549504360, - "version": "3.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1549452781, - "version": "3.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.0.0", - "changes": [ - { - "note": "Upgrade the bignumber.js to v8.0.2", - "pr": 1517 - } - ], - "timestamp": 1549373905 - }, - { - "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 a92d8695dd..0000000000 --- a/packages/order-watcher/CHANGELOG.md +++ /dev/null @@ -1,255 +0,0 @@ - - -CHANGELOG - -## v4.0.17 - _August 8, 2019_ - - * Dependencies updated - -## v4.0.16 - _July 31, 2019_ - - * Dependencies updated - -## v4.0.15 - _July 24, 2019_ - - * Dependencies updated - -## v4.0.14 - _July 15, 2019_ - - * Dependencies updated - -## v4.0.13 - _July 13, 2019_ - - * Dependencies updated - -## v4.0.12 - _July 13, 2019_ - - * Dependencies updated - -## v4.0.11 - _May 24, 2019_ - - * Dependencies updated - -## v4.0.10 - _May 15, 2019_ - - * Dependencies updated - -## v4.0.9 - _May 14, 2019_ - - * Dependencies updated - -## v4.0.7 - _May 10, 2019_ - - * Fix race-condition bug due to async callback modifying shared state (#1789) - * Fix bug where WETH deposit/withdrawal events would not trigger an order state update (#1809) - -## v4.0.6 - _April 11, 2019_ - - * Dependencies updated - -## v4.0.5 - _March 21, 2019_ - - * Dependencies updated - -## v4.0.4 - _March 20, 2019_ - - * Update websocket from ^1.0.25 to ^1.0.26 (#1685) - * Fix issue where ERC721 Approval events could cause a lookup on undefined object (#1692) - * Fix race-condition bugs due to async event callbacks modifying shared state (#1718) - * Run Web3ProviderEngine without excess block polling (#1695) - -## v4.0.3 - _March 1, 2019_ - - * Dependencies updated - -## v4.0.2 - _February 27, 2019_ - - * Dependencies updated - -## v4.0.1 - _February 26, 2019_ - - * Dependencies updated - -## v4.0.0 - _February 25, 2019_ - - * Add support for EIP1193 providers & Web3.js providers >= 1.0-beta.38 (#1627) - * Update provider params to type SupportedProvider which outlines all supported providers (#1627) - -## v3.0.4 - _February 9, 2019_ - - * Dependencies updated - -## v3.0.3 - _February 7, 2019_ - - * Dependencies updated - -## v3.0.2 - _February 7, 2019_ - - * Dependencies updated - -## v3.0.1 - _February 6, 2019_ - - * Dependencies updated - -## v3.0.0 - _February 5, 2019_ - - * Upgrade the bignumber.js to v8.0.2 (#1517) - -## 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 3ffa1b72fa..0000000000 --- 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 b2de5450d6..0000000000 --- a/packages/order-watcher/README.md +++ /dev/null @@ -1,169 +0,0 @@ -## OrderWatcher [Deprecated] - -:no_entry: WARNING: This project is deprecated. Please use [0x Mesh](https://github.com/0xProject/0x-mesh) for all your orderbook pruning needs. It can be used with or without order sharing enabled. If you have any questions about how to use Mesh, reach out to us in the [#mesh channel on Discord](https://discordapp.com/invite/d3FTX3M) :no_entry: - -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: }`. For `REMOVE_ORDER`, provide `{ 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: }, -}; -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 e69de29bb2..0000000000 diff --git a/packages/order-watcher/package.json b/packages/order-watcher/package.json deleted file mode 100644 index e951302e1d..0000000000 --- a/packages/order-watcher/package.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "name": "@0x/order-watcher", - "version": "4.0.17", - "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 .", - "fix": "tslint --fix --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" - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/0x-monorepo" - }, - "license": "Apache-2.0", - "engines": { - "node": ">=6.0.0" - }, - "devDependencies": { - "@0x/dev-utils": "^2.3.0", - "@0x/migrations": "^4.2.0", - "@0x/subproviders": "^5.0.1", - "@0x/tslint-config": "^3.0.1", - "@types/bintrees": "^1.0.2", - "@types/lodash": "4.14.104", - "@types/mocha": "^5.2.7", - "@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": "^6.2.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": "^5.2.0", - "@0x/assert": "^2.1.3", - "@0x/base-contract": "^5.3.1", - "@0x/contract-addresses": "^3.0.3", - "@0x/contract-artifacts": "^2.0.4", - "@0x/contract-wrappers": "9.1.7", - "@0x/fill-scenarios": "^3.0.16", - "@0x/json-schemas": "^3.1.13", - "@0x/order-utils": "^8.2.5", - "@0x/types": "^2.4.1", - "@0x/typescript-typings": "^4.2.4", - "@0x/utils": "^4.5.0", - "@0x/web3-wrapper": "^6.0.10", - "bintrees": "^1.0.2", - "ethereum-types": "^2.1.4", - "ethereumjs-blockstream": "6.0.0", - "ethers": "~4.0.4", - "lodash": "^4.17.11", - "semaphore-async-await": "^1.5.1", - "websocket": "^1.0.26" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/packages/order-watcher/src/index.ts b/packages/order-watcher/src/index.ts deleted file mode 100644 index e9449c5cf0..0000000000 --- a/packages/order-watcher/src/index.ts +++ /dev/null @@ -1,33 +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, - SupportedProvider, - JSONRPCResponsePayload, - JSONRPCResponseError, - Web3JsProvider, - GanacheProvider, - EIP1193Provider, - ZeroExProvider, - EIP1193Event, - Web3JsV1Provider, - Web3JsV2Provider, - Web3JsV3Provider, -} 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 52f28cd4a3..0000000000 --- a/packages/order-watcher/src/order_watcher/collision_resistant_abi_decoder.ts +++ /dev/null @@ -1,57 +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(log: LogEntry): LogWithDecodedArgs | RawLog { - let maybeDecodedLog = log; - if (this._knownERC20Tokens.has(log.address)) { - maybeDecodedLog = this._erc20AbiDecoder.tryToDecodeLogOrNoop(log); - } else if (this._knownERC721Tokens.has(log.address)) { - maybeDecodedLog = this._erc721AbiDecoder.tryToDecodeLogOrNoop(log); - } - // Fall back to the supplied ABIs for decoding if the ERC20/ERC721 decoding fails - // This ensures we hit events like Deposit and Withdraw given WETH can be a known ERC20Token - const isLogDecoded = ((maybeDecodedLog as any) as LogWithDecodedArgs).event !== undefined; - if (!isLogDecoded) { - 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 2f6476dcb3..0000000000 --- a/packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts +++ /dev/null @@ -1,245 +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; -} - -export interface OrderHashesByERC20ByMakerAddress { - [makerAddress: string]: { - [erc20TokenAddress: string]: Set; - }; -} - -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; - }; - }; -} - -/** - */ -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[] { - if ( - this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress] === undefined || - this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress][tokenAddress] === undefined - ) { - return []; - } - 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 ( - this._orderHashesByERC20ByMakerAddress[makerAddress] !== undefined && - this._orderHashesByERC20ByMakerAddress[makerAddress][tokenAddress] !== undefined - ) { - 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 ( - this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress] !== undefined && - this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress][tokenAddress] !== undefined && - this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress][tokenAddress][tokenId.toString()] !== - undefined - ) { - dependentOrderHashes = Array.from( - this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress][tokenAddress][tokenId.toString()], - ); - } - return dependentOrderHashes; - } - private _addToERC20DependentOrderHashes(signedOrder: SignedOrder, erc20TokenAddress: string): void { - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - if (this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress] === undefined) { - this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress] = {}; - } - if (this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress][erc20TokenAddress] === undefined) { - 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 (this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress] === undefined) { - this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress] = {}; - } - - if ( - this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress] === - undefined - ) { - this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress] = {}; - } - - if ( - this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress][ - tokenId.toString() - ] === undefined - ) { - 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 (this._orderHashesByMakerAddress[signedOrder.makerAddress] === undefined) { - 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 91f18fd187..0000000000 --- a/packages/order-watcher/src/order_watcher/event_watcher.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { intervalUtils, logUtils } from '@0x/utils'; -import { marshaller, Web3Wrapper } from '@0x/web3-wrapper'; -import { BlockParamLiteral, FilterObject, LogEntry, RawLogEntry, SupportedProvider } 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 | undefined; - private _blockAndLogStreamIntervalIfExists?: NodeJS.Timer; - private _onLogAddedSubscriptionToken: string | undefined; - private _onLogRemovedSubscriptionToken: string | undefined; - private readonly _pollingIntervalMs: number; - constructor( - supportedProvider: SupportedProvider, - pollingIntervalIfExistsMs: undefined | number, - isVerbose: boolean, - ) { - this._isVerbose = isVerbose; - this._web3Wrapper = new Web3Wrapper(supportedProvider); - this._pollingIntervalMs = - pollingIntervalIfExistsMs === undefined ? 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 (this._blockAndLogStreamIntervalIfExists !== undefined) { - throw new Error(OrderWatcherError.SubscriptionAlreadyPresent); - } - this._startBlockAndLogStream(callback); - } - public unsubscribe(): void { - if (this._blockAndLogStreamIntervalIfExists === undefined) { - throw new Error(OrderWatcherError.SubscriptionNotFound); - } - this._stopBlockAndLogStream(); - } - private _startBlockAndLogStream(callback: EventWatcherCallback): void { - if (this._blockAndLogStreamerIfExists !== undefined) { - 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 { - const shouldIncludeTransactionData = false; - const blockOrNull = await this._web3Wrapper.sendRawPayloadAsync({ - 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 { - const shouldIncludeTransactionData = false; - const blockOrNull = await this._web3Wrapper.sendRawPayloadAsync({ - 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 { - const logs = await this._web3Wrapper.sendRawPayloadAsync({ - method: 'eth_getLogs', - params: [filterOptions], - }); - return logs as RawLogEntry[]; - } - private _stopBlockAndLogStream(): void { - if (this._blockAndLogStreamerIfExists === undefined) { - 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 { - const log: LogEntry = marshaller.unmarshalLog(rawLog); - await this._emitDifferencesAsync(log, isRemoved ? LogEventState.Removed : LogEventState.Added, callback); - } - private async _reconcileBlockAsync(): Promise { - const latestBlockOrNull = await this._blockstreamGetLatestBlockOrNullAsync(); - if (latestBlockOrNull === null) { - return; // noop - } - // We need to coerce to Block type cause Web3.Block includes types for mempool blocks - if (this._blockAndLogStreamerIfExists !== undefined) { - // 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 { - const logEvent = { - removed: logEventState === LogEventState.Removed, - ...log, - }; - if (this._blockAndLogStreamIntervalIfExists !== undefined) { - 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 fd66d628ff..0000000000 --- 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; - 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 (this._orderExpirationCheckingIntervalIdIfExists !== undefined) { - 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 (this._orderExpirationCheckingIntervalIdIfExists === undefined) { - 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 (this._expiration[orderHash] === undefined) { - 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 = this._orderExpirationCheckingIntervalIdIfExists === undefined; - 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 78c619859f..0000000000 --- a/packages/order-watcher/src/order_watcher/order_watcher.ts +++ /dev/null @@ -1,514 +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, providerUtils } from '@0x/utils'; -import { - BlockParamLiteral, - LogEntryEvent, - LogWithDecodedArgs, - SupportedProvider, - ZeroExProvider, -} from 'ethereum-types'; -import * as _ from 'lodash'; -import { Lock } from 'semaphore-async-await'; - -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 _lock = new Lock(); - private readonly _eventWatcher: EventWatcher; - private readonly _provider: ZeroExProvider; - 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 supportedProvider 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( - supportedProvider: SupportedProvider, - networkId: number, - contractAddresses?: ContractAddresses, - partialConfig: Partial = DEFAULT_ORDER_WATCHER_CONFIG, - ) { - const provider = providerUtils.standardizeOrThrow(supportedProvider); - 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, 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 = config === undefined ? 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 { - 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 (signedOrder === undefined) { - 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 (this._callbackIfExists !== undefined) { - throw new Error(OrderWatcherError.SubscriptionAlreadyPresent); - } - this._callbackIfExists = callback; - this._eventWatcher.subscribe( - this._addLockToCallbackAsync.bind(this, this._onEventWatcherCallbackAsync.bind(this)), - ); - this._expirationWatcher.subscribe(this._addLockToCallbackAsync.bind(this, this._onOrderExpired.bind(this))); - this._cleanupJobIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval( - this._addLockToCallbackAsync.bind(this, this._cleanupAsync.bind(this)), - this._cleanupJobInterval, - (err: Error) => { - this.unsubscribe(); - callback(err); - }, - ); - } - /** - * Ends an orderWatcher subscription. - */ - public unsubscribe(): void { - if (this._callbackIfExists === undefined || this._cleanupJobIntervalIdIfExists === undefined) { - 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 _addLockToCallbackAsync(cbAsync: any, ...params: any[]): Promise { - await this._lock.acquire(); - try { - await cbAsync(...params); - await this._lock.release(); - } catch (err) { - // Make sure to releasee the lock if an error is thrown - await this._lock.release(); - throw err; - } - } - private async _cleanupAsync(): Promise { - 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 (this._orderByOrderHash[orderHash] !== undefined) { - this.removeOrder(orderHash); - if (this._callbackIfExists !== undefined) { - this._callbackIfExists(null, orderState); - } - } - } - private async _onEventWatcherCallbackAsync(err: Error | null, logIfExists?: LogEntryEvent): Promise { - if (err !== null) { - if (this._callbackIfExists !== undefined) { - this._callbackIfExists(err); - } - return; - } - const maybeDecodedLog = this._collisionResistantAbiDecoder.tryToDecodeLogOrNoop( - // At this moment we are sure that no error occured and log is defined. - logIfExists as LogEntryEvent, - ); - const isLogDecoded = ((maybeDecodedLog as any) as LogWithDecodedArgs).event !== undefined; - if (!isLogDecoded) { - return; // noop - } - const decodedLog = (maybeDecodedLog as any) as LogWithDecodedArgs; - 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 (decodedLog.args._value !== undefined) { - // 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 (decodedLog.args._value !== undefined) { - // 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 = this._orderByOrderHash[orderHash] !== undefined; - 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 = this._orderByOrderHash[orderHash] !== undefined; - 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 { - for (const orderHash of orderHashes) { - const signedOrder = this._orderByOrderHash[orderHash]; - if (signedOrder === undefined) { - continue; - } - // 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 (this._callbackIfExists === undefined) { - 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); - } - } -} // tslint:disable:max-file-line-count 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 f372711a4f..0000000000 --- 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 { SupportedProvider } 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; - 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 supportedProvider 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( - supportedProvider: SupportedProvider, - networkId: number, - contractAddresses?: ContractAddresses, - orderWatcherConfig?: Partial, - ) { - this._isVerbose = - orderWatcherConfig !== undefined && orderWatcherConfig.isVerbose !== undefined - ? orderWatcherConfig.isVerbose - : true; - this._orderWatcher = new OrderWatcher(supportedProvider, 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 { - 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 { - 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 8bfced063a..0000000000 --- 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 9afb4c65d8..0000000000 --- a/packages/order-watcher/src/server.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { getContractAddressesForNetworkOrThrow } from '@0x/contract-addresses'; -import { RPCSubprovider, Web3ProviderEngine } from '@0x/subproviders'; -import { providerUtils } from '@0x/utils'; -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); -providerUtils.startProviderEngine(provider); - -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 2b529a9391..0000000000 --- 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 ed28aebc6a..0000000000 --- a/packages/order-watcher/src/utils/assert.ts +++ /dev/null @@ -1,28 +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 { SupportedProvider } from 'ethereum-types'; - -import { signatureUtils } from '@0x/order-utils'; - -export const assert = { - ...sharedAssert, - async isValidSignatureAsync( - supportedProvider: SupportedProvider, - orderHash: string, - signature: string, - signerAddress: string, - ): Promise { - const isValid = await signatureUtils.isValidSignatureAsync( - supportedProvider, - 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 9c3849ff19..0000000000 --- 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 885994ce8f..0000000000 --- a/packages/order-watcher/test/expiration_watcher_test.ts +++ /dev/null @@ -1,198 +0,0 @@ -import { BlockchainLifecycle, callbackErrorReporter, tokenUtils } 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 26c37158f7..0000000000 --- a/packages/order-watcher/test/global_hooks.ts +++ /dev/null @@ -1,6 +0,0 @@ -before('set up mocha', async function(): Promise { - // 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 6776ee0b4c..0000000000 --- a/packages/order-watcher/test/order_watcher_test.ts +++ /dev/null @@ -1,938 +0,0 @@ -// tslint:disable:no-unnecessary-type-assertion -import { ContractAddresses, ContractWrappers } from '@0x/contract-wrappers'; -import { BlockchainLifecycle, callbackErrorReporter, tokenUtils } from '@0x/dev-utils'; -import { FillScenarios } from '@0x/fill-scenarios'; -import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; -import { orderFactory } from '@0x/order-utils/lib/src/order_factory'; -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; - let contractAddresses: ContractAddresses; - const decimals = constants.ZRX_DECIMALS; - const fillableAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(5), decimals); - before(async () => { - 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('DependentOrderHashesTracker', async () => { - let makerErc721TokenAddress: string; - [makerErc721TokenAddress] = tokenUtils.getDummyERC721TokenAddresses(); - it('should handle lookups on unknown addresses', async () => { - // Regression test - // ApprovalForAll events on a token from an untracked address could cause - // nested lookups on undefined object - // #1550 - const dependentOrderHashesTracker = (orderWatcher as any) - ._dependentOrderHashesTracker as DependentOrderHashesTracker; - dependentOrderHashesTracker.getDependentOrderHashesByERC721ByMaker(takerAddress, makerErc721TokenAddress); - }); - }); - 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 () => { - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - orderWatcher.unsubscribe(); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - orderWatcher.removeOrder(orderHash); - await blockchainLifecycle.revertAsync(); - }); - 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); - }); - it('should emit orderStateInvalid when makerAddress is unfunded by withdrawing WETH', (done: DoneCallback) => { - (async () => { - const etherTokenAddress = contractAddresses.etherToken; - const wethAssetData = assetDataUtils.encodeERC20AssetData(etherTokenAddress); - await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, makerAddress); - const depositAmount = fillableAmount.times(2); - await contractWrappers.etherToken.depositAsync(etherTokenAddress, depositAmount, makerAddress); - // WETH for ZRX order - signedOrder = await orderFactory.createSignedOrderAsync( - web3Wrapper.getProvider(), - makerAddress, - fillableAmount, - wethAssetData, - fillableAmount, - takerAssetData, - contractAddresses.exchange, - ); - 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.etherToken.withdrawAsync( - contractAddresses.etherToken, - depositAmount, - makerAddress, - ); - })().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 60a3204a98..0000000000 --- a/packages/order-watcher/test/order_watcher_web_socket_server_test.ts +++ /dev/null @@ -1,311 +0,0 @@ -import { ContractAddresses } from '@0x/contract-addresses'; -import { ContractWrappers } from '@0x/contract-wrappers'; -import { BlockchainLifecycle, tokenUtils } 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 { - return new Promise(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 1a87330932..0000000000 --- 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 78037647cb..0000000000 --- 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 665ce0faaa..0000000000 --- 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 { - 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 32f8543267..0000000000 --- a/packages/order-watcher/test/utils/web3_wrapper.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { web3Factory } from '@0x/dev-utils'; -import { Web3ProviderEngine } from '@0x/subproviders'; -import { Web3Wrapper } from '@0x/web3-wrapper'; - -const provider: Web3ProviderEngine = 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 2ee711adcc..0000000000 --- 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 4ade3b924a..0000000000 --- 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 c9b0af1ae6..0000000000 --- a/packages/order-watcher/typedoc-tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../typedoc-tsconfig", - "compilerOptions": { - "outDir": "lib" - }, - "include": ["./src/**/*", "./test/**/*"] -} diff --git a/packages/sra-spec/src/md/introduction.md b/packages/sra-spec/src/md/introduction.md index 3f7431c516..63ac98062d 100644 --- a/packages/sra-spec/src/md/introduction.md +++ b/packages/sra-spec/src/md/introduction.md @@ -200,7 +200,7 @@ For more information see [the Asset Proxy](https://github.com/0xProject/0x-proto In v2 of the standard relayer API we added the `metaData` field. It is meant to provide a standard place for relayers to put optional, custom or non-standard fields that may of interest to the consumer of the API. -A good example of such a field is `remainingTakerAssetAmount`, which is a convenience field that communicates how much of a 0x order is potentially left to be filled. Unlike the other fields in a 0x order, it is not guaranteed to be correct as it is derived from whatever mechanism the implementer (ie. the relayer) is using. While convenient for prototyping and low stakes situations, we recommend validating the value of the field by checking the state of the blockchain yourself, such as by using [Order Watcher](https://0xproject.com/wiki#0x-OrderWatcher). +A good example of such a field is `remainingTakerAssetAmount`, which is a convenience field that communicates how much of a 0x order is potentially left to be filled. Unlike the other fields in a 0x order, it is not guaranteed to be correct as it is derived from whatever mechanism the implementer (ie. the relayer) is using. While convenient for prototyping and low stakes situations, we recommend validating the value of the field by checking the state of the blockchain yourself. # Misc. diff --git a/packages/website/md/docs/order_watcher/1/installation.md b/packages/website/md/docs/order_watcher/1/installation.md deleted file mode 100644 index 4b28f583d3..0000000000 --- a/packages/website/md/docs/order_watcher/1/installation.md +++ /dev/null @@ -1,17 +0,0 @@ -**Install** - -```bash -yarn add @0xproject/order-watcher -``` - -**Import** - -```javascript -import { OrderWatcher } from '@0xproject/order-watcher'; -``` - -or - -```javascript -var OrderWatcher = require('@0xproject/order-utils').OrderWatcher; -``` diff --git a/packages/website/md/docs/order_watcher/1/introduction.md b/packages/website/md/docs/order_watcher/1/introduction.md deleted file mode 100644 index f922d922f8..0000000000 --- a/packages/website/md/docs/order_watcher/1/introduction.md +++ /dev/null @@ -1 +0,0 @@ -Welcome to the [@0xproject/order-watcher](https://github.com/0xProject/0x-monorepo/tree/development/packages/order-watcher) documentation! OrderWatcher is a daemon that efficiently watches a set of orders, emitting events whenever the validity of an order changes. It can be used by relayers to prune an orderbook, or by traders to keep orders fetched from a Relayer up-to-date. diff --git a/packages/website/md/docs/order_watcher/2/installation.md b/packages/website/md/docs/order_watcher/2/installation.md deleted file mode 100644 index 883eb40e56..0000000000 --- a/packages/website/md/docs/order_watcher/2/installation.md +++ /dev/null @@ -1,17 +0,0 @@ -**Install** - -```bash -yarn add @0x/order-watcher -``` - -**Import** - -```javascript -import { OrderWatcher } from '@0x/order-watcher'; -``` - -or - -```javascript -var OrderWatcher = require('@0x/order-utils').OrderWatcher; -``` diff --git a/packages/website/md/docs/order_watcher/2/introduction.md b/packages/website/md/docs/order_watcher/2/introduction.md deleted file mode 100644 index 912cc55e27..0000000000 --- a/packages/website/md/docs/order_watcher/2/introduction.md +++ /dev/null @@ -1,3 +0,0 @@ -**DEPRECATED: This project is deprecated. Please use [0x Mesh](https://github.com/0xProject/0x-mesh) for all your orderbook pruning needs. It can be used with or without order sharing enabled. If you have any questions about how to use Mesh, reach out to us in the [#mesh channel on Discord](https://discordapp.com/invite/d3FTX3M)** - -Welcome to the [order-watcher](https://github.com/0xProject/0x-monorepo/tree/development/packages/order-watcher) documentation! OrderWatcher is a daemon that efficiently watches a set of orders, emitting events whenever the validity of an order changes. It can be used by relayers to prune an orderbook, or by traders to keep orders fetched from a Relayer up-to-date. diff --git a/packages/website/public/sitemap.txt b/packages/website/public/sitemap.txt index 5ee7cb843f..17c24535df 100644 --- a/packages/website/public/sitemap.txt +++ b/packages/website/public/sitemap.txt @@ -23,7 +23,6 @@ https://0x.org/docs/contracts https://0x.org/docs/connect https://0x.org/docs/web3-wrapper https://0x.org/docs/contract-wrappers -https://0x.org/docs/order-watcher https://0x.org/docs/sol-compiler https://0x.org/docs/json-schemas https://0x.org/docs/sol-coverage diff --git a/packages/website/ts/containers/order_watcher_documentation.ts b/packages/website/ts/containers/order_watcher_documentation.ts deleted file mode 100644 index f82947c3a6..0000000000 --- a/packages/website/ts/containers/order_watcher_documentation.ts +++ /dev/null @@ -1,47 +0,0 @@ -import * as React from 'react'; -import { connect } from 'react-redux'; -import { DocPage as DocPageComponent, DocPageProps } from 'ts/pages/documentation/doc_page'; -import { DocPackages } from 'ts/types'; - -import { DocsInfoConfig, SupportedDocJson } from '../types'; -import { getMapStateToProps, mapDispatchToProps } from '../utils/documentation_container'; - -/* tslint:disable:no-var-requires */ -const IntroMarkdown1 = require('md/docs/order_watcher/1/introduction'); -const InstallationMarkdown1 = require('md/docs/order_watcher/1/installation'); -const IntroMarkdown2 = require('md/docs/order_watcher/2/introduction'); -const InstallationMarkdown2 = require('md/docs/order_watcher/2/installation'); -/* tslint:enable:no-var-requires */ - -const markdownSections = { - introduction: 'introduction', - installation: 'installation', -}; - -const docsInfoConfig: DocsInfoConfig = { - id: DocPackages.OrderWatcher, - packageName: '@0x/order-watcher', - type: SupportedDocJson.TypeDoc, - displayName: 'Order Watcher', - packageUrl: 'https://github.com/0xProject/0x-monorepo/packages/order-watcher', - markdownMenu: { - 'getting-started': [markdownSections.introduction, markdownSections.installation], - }, - sectionNameToMarkdownByVersion: { - '0.0.1': { - [markdownSections.introduction]: IntroMarkdown1, - [markdownSections.installation]: InstallationMarkdown1, - }, - '2.2.0': { - [markdownSections.introduction]: IntroMarkdown2, - [markdownSections.installation]: InstallationMarkdown2, - }, - }, - markdownSections, -}; -const mapStateToProps = getMapStateToProps(docsInfoConfig); - -export const Documentation: React.ComponentClass = connect( - mapStateToProps, - mapDispatchToProps, -)(DocPageComponent); diff --git a/packages/website/ts/index.tsx b/packages/website/ts/index.tsx index 096ac91983..2d81629617 100644 --- a/packages/website/ts/index.tsx +++ b/packages/website/ts/index.tsx @@ -59,9 +59,6 @@ const LazyContractWrappersDocumentation = createLazyComponent('Documentation', a const LazyMigrationsDocumentation = createLazyComponent('Documentation', async () => import(/* webpackChunkName: "migrationsDocs" */ 'ts/containers/migrations_documentation'), ); -const LazyOrderWatcherDocumentation = createLazyComponent('Documentation', async () => - import(/* webpackChunkName: "orderWatcherDocs" */ 'ts/containers/order_watcher_documentation'), -); const LazySmartContractsDocumentation = createLazyComponent('Documentation', async () => import(/* webpackChunkName: "smartContractDocs" */ 'ts/containers/smart_contracts_documentation'), ); @@ -168,10 +165,6 @@ render( path={`${WebsitePaths.Migrations}/:version?`} component={LazyMigrationsDocumentation} /> - = { to: WebsitePaths.OrderUtils, }, }, - { - description: - "A daemon that watches a set of 0x orders and emits events when an order's fillability has changed. Can be used by a relayer to prune their orderbook or by a trader to keep their view of the market up-to-date.", - link: { - title: '@0x/order-watcher [Deprecated]', - to: WebsitePaths.OrderWatcher, - }, - }, { description: 'A tiny utility library for getting known deployed contract addresses for a particular network.', diff --git a/packages/website/ts/types.ts b/packages/website/ts/types.ts index 1b9b1256de..18a3165d2f 100644 --- a/packages/website/ts/types.ts +++ b/packages/website/ts/types.ts @@ -464,7 +464,6 @@ export enum WebsitePaths { Connect = '/docs/connect', Web3Wrapper = '/docs/web3-wrapper', ContractWrappers = '/docs/contract-wrappers', - OrderWatcher = '/docs/order-watcher', SolCompiler = '/docs/sol-compiler', JSONSchemas = '/docs/json-schemas', SolCoverage = '/docs/sol-coverage', @@ -497,7 +496,6 @@ export enum DocPackages { OrderUtils = 'ORDER_UTILS', EthereumTypes = 'ETHEREUM_TYPES', ContractWrappers = 'CONTRACT_WRAPPERS', - OrderWatcher = 'ORDER_WATCHER', AssetBuyer = 'ASSET_BUYER', AssetSwapper = 'ASSET_SWAPPER', Migrations = 'MIGRATIONS', @@ -561,7 +559,6 @@ export enum Key { Subproviders = 'SUBPROVIDERS', ZeroExJs = '0X_JS', ContractWrappers = 'CONTRACT_WRAPPERS', - OrderWatcher = 'ORDER_WATCHER', AssetBuyer = 'ASSET_BUYER', AssetSwapper = 'ASSET_SWAPPER', Blog = 'BLOG', diff --git a/python-packages/sra_client/README.md b/python-packages/sra_client/README.md index 6771f8dede..331fe9578c 100644 --- a/python-packages/sra_client/README.md +++ b/python-packages/sra_client/README.md @@ -217,7 +217,7 @@ For more information see [the Asset Proxy](https://github.com/0xProject/0x-proto In v2 of the standard relayer API we added the `metaData` field. It is meant to provide a standard place for relayers to put optional, custom or non-standard fields that may of interest to the consumer of the API. -A good example of such a field is `remainingTakerAssetAmount`, which is a convenience field that communicates how much of a 0x order is potentially left to be filled. Unlike the other fields in a 0x order, it is not guaranteed to be correct as it is derived from whatever mechanism the implementer (ie. the relayer) is using. While convenient for prototyping and low stakes situations, we recommend validating the value of the field by checking the state of the blockchain yourself, such as by using [Order Watcher](https://0xproject.com/wiki#0x-OrderWatcher). +A good example of such a field is `remainingTakerAssetAmount`, which is a convenience field that communicates how much of a 0x order is potentially left to be filled. Unlike the other fields in a 0x order, it is not guaranteed to be correct as it is derived from whatever mechanism the implementer (ie. the relayer) is using. While convenient for prototyping and low stakes situations, we recommend validating the value of the field by checking the state of the blockchain yourself. # Misc. diff --git a/tsconfig.json b/tsconfig.json index 7c4ea8f832..1016f89682 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -49,7 +49,6 @@ { "path": "./packages/migrations" }, { "path": "./packages/monorepo-scripts" }, { "path": "./packages/order-utils" }, - { "path": "./packages/order-watcher" }, { "path": "./packages/sol-compiler" }, { "path": "./packages/sol-coverage" }, { "path": "./packages/sol-profiler" },