From a551d0a6ddbc25f53612702ec7c6fa6ff2ca3aba Mon Sep 17 00:00:00 2001 From: Alex Browne Date: Thu, 23 Aug 2018 16:45:18 -0700 Subject: [PATCH 001/120] fix: Use yarn version 1.9.4 on CI --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0d3c2f1083..2f139841bd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -18,8 +18,8 @@ jobs: - yarn-packages-master - yarn-packages- - run: - name: yarn - command: yarn --frozen-lockfile install || true + name: install-yarn + command: sudo npm install --global yarn@1.9.4 - run: name: yarn command: yarn --frozen-lockfile install @@ -254,4 +254,4 @@ workflows: - build - submit-coverage: requires: - - test-rest \ No newline at end of file + - test-rest From 1040826b8b04d24e053c6afc21e69c4845151d2f Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 23 Aug 2018 17:17:45 -0700 Subject: [PATCH 002/120] Add documentation for connect v2 --- packages/website/md/docs/connect/2.0.0/introduction.md | 3 +++ packages/website/ts/containers/connect_documentation.ts | 5 +++++ 2 files changed, 8 insertions(+) create mode 100644 packages/website/md/docs/connect/2.0.0/introduction.md diff --git a/packages/website/md/docs/connect/2.0.0/introduction.md b/packages/website/md/docs/connect/2.0.0/introduction.md new file mode 100644 index 0000000000..de7ece7aef --- /dev/null +++ b/packages/website/md/docs/connect/2.0.0/introduction.md @@ -0,0 +1,3 @@ +**NOTE:** Release candidate versions are meant to work with V2 of the Standard Relayer API. To interact with V1, select a 1.X version of connect. + +Welcome to the [0x Connect](https://github.com/0xProject/0x-monorepo/tree/development/packages/connect) documentation! 0x Connect is a Javascript library that makes it easy to interact with relayers that conform to the [Standard Relayer API](https://github.com/0xProject/standard-relayer-api). Functionality includes getting supported asset pairs from a relayer, getting orders filtered by different attributes, getting individual orders specified by order hash, getting orderbooks for specific asset pairs, getting fee information, and submitting orders. diff --git a/packages/website/ts/containers/connect_documentation.ts b/packages/website/ts/containers/connect_documentation.ts index 8b13081c61..90137243c1 100644 --- a/packages/website/ts/containers/connect_documentation.ts +++ b/packages/website/ts/containers/connect_documentation.ts @@ -10,6 +10,7 @@ import { Translate } from 'ts/utils/translate'; /* tslint:disable:no-var-requires */ const IntroMarkdownV1 = require('md/docs/connect/1.0.0/introduction'); +const IntroMarkdownV2 = require('md/docs/connect/2.0.0/introduction'); const InstallationMarkdownV1 = require('md/docs/connect/1.0.0/installation'); /* tslint:enable:no-var-requires */ @@ -33,6 +34,10 @@ const docsInfoConfig: DocsInfoConfig = { [markdownSections.introduction]: IntroMarkdownV1, [markdownSections.installation]: InstallationMarkdownV1, }, + '2.0.0-rc.1': { + [markdownSections.introduction]: IntroMarkdownV2, + [markdownSections.installation]: InstallationMarkdownV1, + }, }, markdownSections, }; From d603d8da4786e34d4d63ef4283d4ba8d841d3f39 Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 23 Aug 2018 11:56:08 -0700 Subject: [PATCH 003/120] Rename sra-api to sra-spec --- README.md | 2 +- packages/{sra-api => sra-spec}/.discharge.json | 2 +- packages/{sra-api => sra-spec}/.npmignore | 0 packages/{sra-api => sra-spec}/CHANGELOG.json | 0 packages/{sra-api => sra-spec}/CHANGELOG.md | 0 packages/{sra-api => sra-spec}/README.md | 12 ++++++------ .../{sra-api => sra-spec}/build_scripts/buildJson.ts | 0 packages/{sra-api => sra-spec}/package.json | 4 ++-- packages/{sra-api => sra-spec}/public/api.json | 0 packages/{sra-api => sra-spec}/public/index.html | 0 packages/{sra-api => sra-spec}/src/api.ts | 0 packages/{sra-api => sra-spec}/src/errors.ts | 0 .../{sra-api => sra-spec}/src/examples/errors.ts | 0 packages/{sra-api => sra-spec}/src/examples/index.ts | 0 .../src/examples/relayerApiAssetDataPairsResponse.ts | 0 .../src/examples/relayerApiFeeRecipientsResponse.ts | 0 .../src/examples/relayerApiOrder.ts | 0 .../src/examples/relayerApiOrderConfigPayload.ts | 0 .../src/examples/relayerApiOrderConfigResponse.ts | 0 .../src/examples/relayerApiOrderbookResponse.ts | 0 .../src/examples/relayerApiOrdersResponse.ts | 0 .../src/examples/signedOrder.ts | 0 packages/{sra-api => sra-spec}/src/headers.ts | 0 packages/{sra-api => sra-spec}/src/index.ts | 0 packages/{sra-api => sra-spec}/src/json-schemas.ts | 0 packages/{sra-api => sra-spec}/src/md/index.ts | 0 .../{sra-api => sra-spec}/src/md/introduction.md | 0 packages/{sra-api => sra-spec}/src/parameters.ts | 0 packages/{sra-api => sra-spec}/src/responses.ts | 0 packages/{sra-api => sra-spec}/tsconfig.json | 0 packages/{sra-api => sra-spec}/tslint.json | 0 31 files changed, 10 insertions(+), 10 deletions(-) rename packages/{sra-api => sra-spec}/.discharge.json (91%) rename packages/{sra-api => sra-spec}/.npmignore (100%) rename packages/{sra-api => sra-spec}/CHANGELOG.json (100%) rename packages/{sra-api => sra-spec}/CHANGELOG.md (100%) rename packages/{sra-api => sra-spec}/README.md (86%) rename packages/{sra-api => sra-spec}/build_scripts/buildJson.ts (100%) rename packages/{sra-api => sra-spec}/package.json (97%) rename packages/{sra-api => sra-spec}/public/api.json (100%) rename packages/{sra-api => sra-spec}/public/index.html (100%) rename packages/{sra-api => sra-spec}/src/api.ts (100%) rename packages/{sra-api => sra-spec}/src/errors.ts (100%) rename packages/{sra-api => sra-spec}/src/examples/errors.ts (100%) rename packages/{sra-api => sra-spec}/src/examples/index.ts (100%) rename packages/{sra-api => sra-spec}/src/examples/relayerApiAssetDataPairsResponse.ts (100%) rename packages/{sra-api => sra-spec}/src/examples/relayerApiFeeRecipientsResponse.ts (100%) rename packages/{sra-api => sra-spec}/src/examples/relayerApiOrder.ts (100%) rename packages/{sra-api => sra-spec}/src/examples/relayerApiOrderConfigPayload.ts (100%) rename packages/{sra-api => sra-spec}/src/examples/relayerApiOrderConfigResponse.ts (100%) rename packages/{sra-api => sra-spec}/src/examples/relayerApiOrderbookResponse.ts (100%) rename packages/{sra-api => sra-spec}/src/examples/relayerApiOrdersResponse.ts (100%) rename packages/{sra-api => sra-spec}/src/examples/signedOrder.ts (100%) rename packages/{sra-api => sra-spec}/src/headers.ts (100%) rename packages/{sra-api => sra-spec}/src/index.ts (100%) rename packages/{sra-api => sra-spec}/src/json-schemas.ts (100%) rename packages/{sra-api => sra-spec}/src/md/index.ts (100%) rename packages/{sra-api => sra-spec}/src/md/introduction.md (100%) rename packages/{sra-api => sra-spec}/src/parameters.ts (100%) rename packages/{sra-api => sra-spec}/src/responses.ts (100%) rename packages/{sra-api => sra-spec}/tsconfig.json (100%) rename packages/{sra-api => sra-spec}/tslint.json (100%) diff --git a/README.md b/README.md index a8bd7413e6..9e56dc475d 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ If you're developing on 0x now or are interested in using 0x infrastructure in t | [`@0xproject/monorepo-scripts`](/packages/monorepo-scripts) | [![npm](https://img.shields.io/npm/v/@0xproject/monorepo-scripts.svg)](https://www.npmjs.com/package/@0xproject/monorepo-scripts) | Monorepo scripts | | [`@0xproject/react-docs`](/packages/react-docs) | [![npm](https://img.shields.io/npm/v/@0xproject/react-docs.svg)](https://www.npmjs.com/package/@0xproject/react-docs) | React documentation component for rendering TypeDoc & Doxity generated JSON | | [`@0xproject/react-shared`](/packages/react-shared) | [![npm](https://img.shields.io/npm/v/@0xproject/react-shared.svg)](https://www.npmjs.com/package/@0xproject/react-shared) | 0x shared react components | -| [`@0xproject/sra-api`](/packages/sra-api) | [![npm](https://img.shields.io/npm/v/@0xproject/sra-api.svg)](https://www.npmjs.com/package/@0xproject/sra-api) | OpenAPI specification for the standard relayer API | +| [`@0xproject/sra-spec`](/packages/sra-spec) | [![npm](https://img.shields.io/npm/v/@0xproject/sra-spec.svg)](https://www.npmjs.com/package/@0xproject/sra-spec) | OpenAPI specification for the standard relayer API | | [`@0xproject/sra-report`](/packages/sra-report) | [![npm](https://img.shields.io/npm/v/@0xproject/sra-report.svg)](https://www.npmjs.com/package/@0xproject/sra-report) | Generate reports for standard relayer API compliance | | [`@0xproject/sol-cov`](/packages/sol-cov) | [![npm](https://img.shields.io/npm/v/@0xproject/sol-cov.svg)](https://www.npmjs.com/package/@0xproject/sol-cov) | Solidity test coverage tool | | [`@0xproject/subproviders`](/packages/subproviders) | [![npm](https://img.shields.io/npm/v/@0xproject/subproviders.svg)](https://www.npmjs.com/package/@0xproject/subproviders) | Useful web3 subproviders (e.g LedgerSubprovider) | diff --git a/packages/sra-api/.discharge.json b/packages/sra-spec/.discharge.json similarity index 91% rename from packages/sra-api/.discharge.json rename to packages/sra-spec/.discharge.json index df2cce0f4c..80ede84f36 100644 --- a/packages/sra-api/.discharge.json +++ b/packages/sra-spec/.discharge.json @@ -1,5 +1,5 @@ { - "domain": "sra-api", + "domain": "sra-spec", "build_command": "yarn build-json", "upload_directory": "public", "index_key": "index.html", diff --git a/packages/sra-api/.npmignore b/packages/sra-spec/.npmignore similarity index 100% rename from packages/sra-api/.npmignore rename to packages/sra-spec/.npmignore diff --git a/packages/sra-api/CHANGELOG.json b/packages/sra-spec/CHANGELOG.json similarity index 100% rename from packages/sra-api/CHANGELOG.json rename to packages/sra-spec/CHANGELOG.json diff --git a/packages/sra-api/CHANGELOG.md b/packages/sra-spec/CHANGELOG.md similarity index 100% rename from packages/sra-api/CHANGELOG.md rename to packages/sra-spec/CHANGELOG.md diff --git a/packages/sra-api/README.md b/packages/sra-spec/README.md similarity index 86% rename from packages/sra-api/README.md rename to packages/sra-spec/README.md index dec66c498a..7eee6396b5 100644 --- a/packages/sra-api/README.md +++ b/packages/sra-spec/README.md @@ -1,15 +1,15 @@ -## @0xproject/sra-api +## @0xproject/sra-spec Contains the Standard Relayer API [OpenAPI Spec](https://github.com/OAI/OpenAPI-Specification). The package distributes both a javascript object version and a json version. -A deployed [ReDoc](https://github.com/Rebilly/ReDoc) static site with the API can be found here http://sra-api.s3-website-us-east-1.amazonaws.com/. +A deployed [ReDoc](https://github.com/Rebilly/ReDoc) static site with the API can be found here http://sra-spec.s3-website-us-east-1.amazonaws.com/. ## Usage ``` -import { api } from '@0xproject/sra-api'; +import { api } from '@0xproject/sra-spec'; ``` ## Installation @@ -53,18 +53,18 @@ yarn install To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory: ```bash -PKG=@0xproject/sra-api yarn build +PKG=@0xproject/sra-spec yarn build ``` Or continuously rebuild on change: ```bash -PKG=@0xproject/sra-api yarn watch +PKG=@0xproject/sra-spec yarn watch ``` ### Static Site -We also [host a static HTML version of the docs on S3](http://sra-api.s3-website-us-east-1.amazonaws.com/) for easy sharing. +We also [host a static HTML version of the docs on S3](http://sra-spec.s3-website-us-east-1.amazonaws.com/) for easy sharing. To build and deploy the site run diff --git a/packages/sra-api/build_scripts/buildJson.ts b/packages/sra-spec/build_scripts/buildJson.ts similarity index 100% rename from packages/sra-api/build_scripts/buildJson.ts rename to packages/sra-spec/build_scripts/buildJson.ts diff --git a/packages/sra-api/package.json b/packages/sra-spec/package.json similarity index 97% rename from packages/sra-api/package.json rename to packages/sra-spec/package.json index a4a0a7b0b0..e52e727492 100644 --- a/packages/sra-api/package.json +++ b/packages/sra-spec/package.json @@ -1,5 +1,5 @@ { - "name": "@0xproject/sra-api", + "name": "@0xproject/sra-spec", "version": "1.0.1-rc.4", "engines": { "node": ">=6.12" @@ -31,7 +31,7 @@ "bugs": { "url": "https://github.com/0xProject/0x-monorepo/issues" }, - "homepage": "https://github.com/0xProject/0x-monorepo/packages/sra-api/README.md", + "homepage": "https://github.com/0xProject/0x-monorepo/packages/sra-spec/README.md", "dependencies": { "@0xproject/json-schemas": "^1.0.1-rc.4" }, diff --git a/packages/sra-api/public/api.json b/packages/sra-spec/public/api.json similarity index 100% rename from packages/sra-api/public/api.json rename to packages/sra-spec/public/api.json diff --git a/packages/sra-api/public/index.html b/packages/sra-spec/public/index.html similarity index 100% rename from packages/sra-api/public/index.html rename to packages/sra-spec/public/index.html diff --git a/packages/sra-api/src/api.ts b/packages/sra-spec/src/api.ts similarity index 100% rename from packages/sra-api/src/api.ts rename to packages/sra-spec/src/api.ts diff --git a/packages/sra-api/src/errors.ts b/packages/sra-spec/src/errors.ts similarity index 100% rename from packages/sra-api/src/errors.ts rename to packages/sra-spec/src/errors.ts diff --git a/packages/sra-api/src/examples/errors.ts b/packages/sra-spec/src/examples/errors.ts similarity index 100% rename from packages/sra-api/src/examples/errors.ts rename to packages/sra-spec/src/examples/errors.ts diff --git a/packages/sra-api/src/examples/index.ts b/packages/sra-spec/src/examples/index.ts similarity index 100% rename from packages/sra-api/src/examples/index.ts rename to packages/sra-spec/src/examples/index.ts diff --git a/packages/sra-api/src/examples/relayerApiAssetDataPairsResponse.ts b/packages/sra-spec/src/examples/relayerApiAssetDataPairsResponse.ts similarity index 100% rename from packages/sra-api/src/examples/relayerApiAssetDataPairsResponse.ts rename to packages/sra-spec/src/examples/relayerApiAssetDataPairsResponse.ts diff --git a/packages/sra-api/src/examples/relayerApiFeeRecipientsResponse.ts b/packages/sra-spec/src/examples/relayerApiFeeRecipientsResponse.ts similarity index 100% rename from packages/sra-api/src/examples/relayerApiFeeRecipientsResponse.ts rename to packages/sra-spec/src/examples/relayerApiFeeRecipientsResponse.ts diff --git a/packages/sra-api/src/examples/relayerApiOrder.ts b/packages/sra-spec/src/examples/relayerApiOrder.ts similarity index 100% rename from packages/sra-api/src/examples/relayerApiOrder.ts rename to packages/sra-spec/src/examples/relayerApiOrder.ts diff --git a/packages/sra-api/src/examples/relayerApiOrderConfigPayload.ts b/packages/sra-spec/src/examples/relayerApiOrderConfigPayload.ts similarity index 100% rename from packages/sra-api/src/examples/relayerApiOrderConfigPayload.ts rename to packages/sra-spec/src/examples/relayerApiOrderConfigPayload.ts diff --git a/packages/sra-api/src/examples/relayerApiOrderConfigResponse.ts b/packages/sra-spec/src/examples/relayerApiOrderConfigResponse.ts similarity index 100% rename from packages/sra-api/src/examples/relayerApiOrderConfigResponse.ts rename to packages/sra-spec/src/examples/relayerApiOrderConfigResponse.ts diff --git a/packages/sra-api/src/examples/relayerApiOrderbookResponse.ts b/packages/sra-spec/src/examples/relayerApiOrderbookResponse.ts similarity index 100% rename from packages/sra-api/src/examples/relayerApiOrderbookResponse.ts rename to packages/sra-spec/src/examples/relayerApiOrderbookResponse.ts diff --git a/packages/sra-api/src/examples/relayerApiOrdersResponse.ts b/packages/sra-spec/src/examples/relayerApiOrdersResponse.ts similarity index 100% rename from packages/sra-api/src/examples/relayerApiOrdersResponse.ts rename to packages/sra-spec/src/examples/relayerApiOrdersResponse.ts diff --git a/packages/sra-api/src/examples/signedOrder.ts b/packages/sra-spec/src/examples/signedOrder.ts similarity index 100% rename from packages/sra-api/src/examples/signedOrder.ts rename to packages/sra-spec/src/examples/signedOrder.ts diff --git a/packages/sra-api/src/headers.ts b/packages/sra-spec/src/headers.ts similarity index 100% rename from packages/sra-api/src/headers.ts rename to packages/sra-spec/src/headers.ts diff --git a/packages/sra-api/src/index.ts b/packages/sra-spec/src/index.ts similarity index 100% rename from packages/sra-api/src/index.ts rename to packages/sra-spec/src/index.ts diff --git a/packages/sra-api/src/json-schemas.ts b/packages/sra-spec/src/json-schemas.ts similarity index 100% rename from packages/sra-api/src/json-schemas.ts rename to packages/sra-spec/src/json-schemas.ts diff --git a/packages/sra-api/src/md/index.ts b/packages/sra-spec/src/md/index.ts similarity index 100% rename from packages/sra-api/src/md/index.ts rename to packages/sra-spec/src/md/index.ts diff --git a/packages/sra-api/src/md/introduction.md b/packages/sra-spec/src/md/introduction.md similarity index 100% rename from packages/sra-api/src/md/introduction.md rename to packages/sra-spec/src/md/introduction.md diff --git a/packages/sra-api/src/parameters.ts b/packages/sra-spec/src/parameters.ts similarity index 100% rename from packages/sra-api/src/parameters.ts rename to packages/sra-spec/src/parameters.ts diff --git a/packages/sra-api/src/responses.ts b/packages/sra-spec/src/responses.ts similarity index 100% rename from packages/sra-api/src/responses.ts rename to packages/sra-spec/src/responses.ts diff --git a/packages/sra-api/tsconfig.json b/packages/sra-spec/tsconfig.json similarity index 100% rename from packages/sra-api/tsconfig.json rename to packages/sra-spec/tsconfig.json diff --git a/packages/sra-api/tslint.json b/packages/sra-spec/tslint.json similarity index 100% rename from packages/sra-api/tslint.json rename to packages/sra-spec/tslint.json From a75c298de01e46a048e92272dec97c80625aa4e0 Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 23 Aug 2018 17:31:11 -0700 Subject: [PATCH 004/120] Point to new s3 bucket --- packages/sra-spec/public/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sra-spec/public/index.html b/packages/sra-spec/public/index.html index 868047d4fe..e75ae7f047 100644 --- a/packages/sra-spec/public/index.html +++ b/packages/sra-spec/public/index.html @@ -18,7 +18,7 @@ - + \ No newline at end of file From 1d6699585ebd2640733346473063bd5594940fda Mon Sep 17 00:00:00 2001 From: fragosti Date: Thu, 23 Aug 2018 17:53:21 -0700 Subject: [PATCH 005/120] Add sra-spec to prettier ignore --- .prettierignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.prettierignore b/.prettierignore index 3a69fc8de1..ce7a9d57bf 100644 --- a/.prettierignore +++ b/.prettierignore @@ -15,7 +15,7 @@ lib /packages/contract-wrappers/src/artifacts /packages/order-watcher/src/artifacts /packages/metacoin/artifacts -/packages/sra-api/public/ +/packages/sra-spec/public/ /packages/contract-wrappers/test/artifacts /packages/order-watcher/test/artifacts /packages/migrations/artifacts/1.0.0 From 8f6a96740eebd0ddbb0ff1eed0d13f78891f4871 Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 24 Aug 2018 08:25:34 -0700 Subject: [PATCH 006/120] Remove superflous id from relayer api fee recipients json schema --- .../schemas/relayer_api_fee_recipients_response_schema.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/json-schemas/schemas/relayer_api_fee_recipients_response_schema.ts b/packages/json-schemas/schemas/relayer_api_fee_recipients_response_schema.ts index 4f96e5a2d0..5f6bc05303 100644 --- a/packages/json-schemas/schemas/relayer_api_fee_recipients_response_schema.ts +++ b/packages/json-schemas/schemas/relayer_api_fee_recipients_response_schema.ts @@ -6,7 +6,6 @@ export const relayerApiFeeRecipientsResponseSchema = { { properties: { records: { - id: '/relayerApiFeeRecipientsSchema', type: 'array', items: { $ref: '/addressSchema' }, }, From c1b4fe999cbe9e40b9358058d6c59c8c8625494e Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Fri, 24 Aug 2018 17:41:33 +0100 Subject: [PATCH 007/120] Excessive command --- packages/0x.js/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json index 54a896bfc0..bb0799f4b3 100644 --- a/packages/0x.js/package.json +++ b/packages/0x.js/package.json @@ -20,7 +20,6 @@ "build:all": "run-p build:umd:prod build:commonjs", "lint": "tslint --project . --exclude **/src/generated_contract_wrappers/**/*", "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", From fb6d5118116268b68051191f9d44dad815ccad16 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Fri, 24 Aug 2018 17:44:14 +0100 Subject: [PATCH 008/120] Added missing entry for RC package --- packages/fill-scenarios/CHANGELOG.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/fill-scenarios/CHANGELOG.json b/packages/fill-scenarios/CHANGELOG.json index 06f12a85f5..ae53b709a4 100644 --- a/packages/fill-scenarios/CHANGELOG.json +++ b/packages/fill-scenarios/CHANGELOG.json @@ -1,4 +1,12 @@ [ + { + "version": "1.0.1-rc.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "1.0.1-rc.3", "changes": [ From d4592c0a607fca35241fae8f10f682817c2a82e1 Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 24 Aug 2018 10:20:17 -0700 Subject: [PATCH 009/120] Run prettier --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e56dc475d..0962d36fbf 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ If you're developing on 0x now or are interested in using 0x infrastructure in t | [`@0xproject/monorepo-scripts`](/packages/monorepo-scripts) | [![npm](https://img.shields.io/npm/v/@0xproject/monorepo-scripts.svg)](https://www.npmjs.com/package/@0xproject/monorepo-scripts) | Monorepo scripts | | [`@0xproject/react-docs`](/packages/react-docs) | [![npm](https://img.shields.io/npm/v/@0xproject/react-docs.svg)](https://www.npmjs.com/package/@0xproject/react-docs) | React documentation component for rendering TypeDoc & Doxity generated JSON | | [`@0xproject/react-shared`](/packages/react-shared) | [![npm](https://img.shields.io/npm/v/@0xproject/react-shared.svg)](https://www.npmjs.com/package/@0xproject/react-shared) | 0x shared react components | -| [`@0xproject/sra-spec`](/packages/sra-spec) | [![npm](https://img.shields.io/npm/v/@0xproject/sra-spec.svg)](https://www.npmjs.com/package/@0xproject/sra-spec) | OpenAPI specification for the standard relayer API | +| [`@0xproject/sra-spec`](/packages/sra-spec) | [![npm](https://img.shields.io/npm/v/@0xproject/sra-spec.svg)](https://www.npmjs.com/package/@0xproject/sra-spec) | OpenAPI specification for the standard relayer API | | [`@0xproject/sra-report`](/packages/sra-report) | [![npm](https://img.shields.io/npm/v/@0xproject/sra-report.svg)](https://www.npmjs.com/package/@0xproject/sra-report) | Generate reports for standard relayer API compliance | | [`@0xproject/sol-cov`](/packages/sol-cov) | [![npm](https://img.shields.io/npm/v/@0xproject/sol-cov.svg)](https://www.npmjs.com/package/@0xproject/sol-cov) | Solidity test coverage tool | | [`@0xproject/subproviders`](/packages/subproviders) | [![npm](https://img.shields.io/npm/v/@0xproject/subproviders.svg)](https://www.npmjs.com/package/@0xproject/subproviders) | Useful web3 subproviders (e.g LedgerSubprovider) | From 029ea52979f9ba7347d20ec4fab962e1b79ee01f Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Fri, 24 Aug 2018 18:58:12 +0100 Subject: [PATCH 010/120] Small fixes to publish script --- packages/monorepo-scripts/src/publish.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/monorepo-scripts/src/publish.ts b/packages/monorepo-scripts/src/publish.ts index d9e09bdebf..7e2e645369 100644 --- a/packages/monorepo-scripts/src/publish.ts +++ b/packages/monorepo-scripts/src/publish.ts @@ -18,7 +18,6 @@ import { DocGenerateAndUploadUtils } from './utils/doc_generate_and_upload_utils import { publishReleaseNotesAsync } from './utils/github_release_utils'; import { utils } from './utils/utils'; -const DOC_GEN_COMMAND = 'docs:json'; const NPM_NAMESPACE = '@0xproject/'; const TODAYS_TIMESTAMP = moment().unix(); @@ -88,7 +87,7 @@ async function confirmAsync(message: string): Promise { function getPackagesWithDocs(allUpdatedPackages: Package[]): Package[] { const rootPackageJsonPath = `${constants.monorepoRootPath}/package.json`; const rootPackageJson = JSON.parse(fs.readFileSync(rootPackageJsonPath).toString()); - const packagesWithDocPagesStringIfExist = _.get(rootPackageJson, 'configs.packagesWithDocPages', undefined); + const packagesWithDocPagesStringIfExist = _.get(rootPackageJson, 'config.packagesWithDocPages', undefined); if (_.isUndefined(packagesWithDocPagesStringIfExist)) { return []; // None to generate & publish } From 2d1c88c20dcfb46e79c3873dbcd4e31865588ae5 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Fri, 24 Aug 2018 18:58:34 +0100 Subject: [PATCH 011/120] Updated api.json --- packages/sra-api/public/api.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sra-api/public/api.json b/packages/sra-api/public/api.json index fc2409abbe..9701555ca4 100644 --- a/packages/sra-api/public/api.json +++ b/packages/sra-api/public/api.json @@ -1 +1 @@ -{"openapi":"3.0.0","info":{"version":"2.0.0","title":"Standard Relayer REST API","description":"# Testing\n\nUse the [sra-report](https://github.com/0xProject/0x-monorepo/tree/development/packages/sra-report) command line tool to test your API for SRA compliance.\n\n# Schemas\n\nThe [JSON schemas](http://json-schema.org/) for the API payloads and responses can be found in [@0xproject/json-schemas](https://github.com/0xProject/0x.js/tree/development/packages/json-schemas). Examples of each payload and response can be found in the library's [test suite](https://github.com/0xProject/0x.js/blob/development/packages/json-schemas/test/schema_test.ts#L1).\n\n```bash\nnpm install @0xproject/json-schemas --save\n```\n\nYou can easily validate your API's payloads and responses using the [@0xproject/json-schemas](https://github.com/0xProject/0x.js/tree/development/packages/json-schemas) package:\n\n```js\nimport {SchemaValidator, ValidatorResult, schemas} from '@0xproject/json-schemas';\n\nconst {relayerApiTokenPairsResponseSchema} = schemas;\nconst validator = new SchemaValidator();\n\nconst tokenPairsResponse = {\n ...\n};\nconst validatorResult: ValidatorResult = validator.validate(tokenPairsResponse, relayerApiTokenPairsResponseSchema);\n```\n\n# Pagination\n\nRequests that return potentially large collections should respond to the **?page** and **?perPage** parameters. For example:\n\n```bash\n$ curl https://api.example-relayer.com/v2/asset_pairs?page=3&perPage=20\n```\n\nPage numbering should be 1-indexed, not 0-indexed. If a query provides an unreasonable (ie. too high) `perPage` value, the response can return a validation error as specified in the [errors section](#section/Errors). If the query specifies a `page` that does not exist (ie. there are not enough `records`), the response should just return an empty `records` array.\n\nAll endpoints that are paginated should return a `total`, `page`, `perPage` and a `records` value in the top level of the collection. The value of `total` should be the total number of records for a given query, whereas `records` should be an array representing the response to the query for that page. `page` and `perPage`, are the same values that were specified in the request. See the note in [miscellaneous](#section/Misc.) about formatting `snake_case` vs. `lowerCamelCase`.\n\nThese requests include the [`/v2/asset_pairs`](#operation/getAssetPairs), [`/v2/orders`](#operation/getOrders), [`/v2/fee_recipients`](#operation/getFeeRecipients) and [`/v2/orderbook`](#operation/getOrderbook) endpoints.\n\n# Network Id\n\nAll requests should be able to specify a **?networkId** query param for all supported networks. For example:\n\n```bash\n$ curl https://api.example-relayer.com/v2/asset_pairs?networkId=1\n```\n\nIf the query param is not provided, it should default to **1** (mainnet).\n\nNetworks and their Ids:\n\n| Network Id | Network Name |\n| ---------- | ------------ |\n| 1 | Mainnet |\n| 42 | Kovan |\n| 3 | Ropsten |\n| 4 | Rinkeby |\n\nIf a certain network is not supported, the response should **400** as specified in the [error response](#section/Errors) section. For example:\n\n```json\n{\n \"code\": 100,\n \"reason\": \"Validation failed\",\n \"validationErrors\": [\n {\n \"field\": \"networkId\",\n \"code\": 1006,\n \"reason\": \"Network id 42 is not supported\"\n }\n ]\n}\n```\n\n# Link Header\n\nA [Link Header](https://tools.ietf.org/html/rfc5988) can be included in a response to provide clients with more context about paging\nFor example:\n\n```bash\nLink: ; rel=\"next\",\n; rel=\"last\"\n```\n\nThis `Link` response header contains one or more Hypermedia link relations.\n\nThe possible `rel` values are:\n\n| Name | Description |\n| ----- | ------------------------------------------------------------- |\n| next | The link relation for the immediate next page of results. |\n| last | The link relation for the last page of results. |\n| first | The link relation for the first page of results. |\n| prev | The link relation for the immediate previous page of results. |\n\n# Rate Limits\n\nRate limit guidance for clients can be optionally returned in the response headers:\n\n| Header Name | Description |\n| --------------------- | ---------------------------------------------------------------------------- |\n| X-RateLimit-Limit | The maximum number of requests you're permitted to make per hour. |\n| X-RateLimit-Remaining | The number of requests remaining in the current rate limit window. |\n| X-RateLimit-Reset | The time at which the current rate limit window resets in UTC epoch seconds. |\n\nFor example:\n\n```bash\n$ curl -i https://api.example-relayer.com/v2/asset_pairs\nHTTP/1.1 200 OK\nDate: Mon, 20 Oct 2017 12:30:06 GMT\nStatus: 200 OK\nX-RateLimit-Limit: 60\nX-RateLimit-Remaining: 56\nX-RateLimit-Reset: 1372700873\n```\n\nWhen a rate limit is exceeded, a status of **429 Too Many Requests** should be returned.\n\n# Errors\n\nUnless the spec defines otherwise, errors to bad requests should respond with HTTP 4xx or status codes.\n\n## Common error codes\n\n| Code | Reason |\n| ---- | --------------------------------------- |\n| 400 | Bad Request – Invalid request format |\n| 404 | Not found |\n| 429 | Too many requests - Rate limit exceeded |\n| 500 | Internal Server Error |\n| 501 | Not Implemented |\n\n## Error reporting format\n\nFor all **400** responses, see the [error response schema](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_error_response_schema.ts#L1).\n\n```json\n{\n \"code\": 101,\n \"reason\": \"Validation failed\",\n \"validationErrors\": [\n {\n \"field\": \"maker\",\n \"code\": 1002,\n \"reason\": \"Invalid address\"\n }\n ]\n}\n```\n\nGeneral error codes:\n\n```bash\n100 - Validation Failed\n101 - Malformed JSON\n102 - Order submission disabled\n103 - Throttled\n```\n\nValidation error codes:\n\n```bash\n1000 - Required field\n1001 - Incorrect format\n1002 - Invalid address\n1003 - Address not supported\n1004 - Value out of range\n1005 - Invalid signature or hash\n1006 - Unsupported option\n```\n\n# Asset Data Encoding\n\nAs we now support multiple [token transfer proxies](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxy), the identifier of which proxy to use for the token transfer must be encoded, along with the token information. Each proxy in 0x v2 has a unique identifier. If you're using 0x.js there will be helper methods for this [encoding](https://0xproject.com/docs/0x.js#zeroEx-encodeERC20AssetData) and [decoding](https://0xproject.com/docs/0x.js#zeroEx-decodeAssetProxyId).\n\nThe identifier for the Proxy uses a similar scheme to [ABI function selectors](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI#function-selector).\n\n```js\n// ERC20 Proxy ID 0xf47261b0\nbytes4(keccak256('ERC20Token(address)'));\n// ERC721 Proxy ID 0x08e937fa\nbytes4(keccak256('ERC721Token(address,uint256)'));\n```\n\nAsset data is encoded using [ABI encoding](https://solidity.readthedocs.io/en/develop/abi-spec.html).\n\nFor example, encoding the ERC20 token contract (address: 0x1dc4c1cefef38a777b15aa20260a54e584b16c48) using the ERC20 Transfer Proxy (id: 0xf47261b0) would be:\n\n```bash\n0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48\n```\n\nEncoding the ERC721 token contract (address: `0x371b13d97f4bf77d724e78c16b7dc74099f40e84`), token id (id: `99`, which hex encoded is `0x63`) and the ERC721 Transfer Proxy (id: 0x08e937fa) would be:\n\n```bash\n0x08e937fa000000000000000000000000371b13d97f4bf77d724e78c16b7dc74099f40e840000000000000000000000000000000000000000000000000000000000000063\n```\n\nFor more information see [the Asset Proxy](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#erc20proxy) section of the v2 spec and the [Ethereum ABI Spec](https://solidity.readthedocs.io/en/develop/abi-spec.html).\n\n# Meta Data in Order Responses\n\nIn 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.\n\nA 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).\n\n# Misc.\n\n* All requests and responses should be of **application/json** content type\n* All token amounts are sent in amounts of the smallest level of precision (base units). (e.g if a token has 18 decimal places, selling 1 token would show up as selling `'1000000000000000000'` units by this API).\n* All addresses are sent as lower-case (non-checksummed) Ethereum addresses with the `0x` prefix.\n* All parameters are to be written in `lowerCamelCase`.\n","license":{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0.html"}},"paths":{"/v2/asset_pairs":{"get":{"description":"Retrieves a list of available asset pairs and the information required to trade them (in any order). Setting only `assetDataA` or `assetDataB` returns pairs filtered by that asset only.","operationId":"getAssetPairs","parameters":[{"name":"assetDataA","in":"query","description":"The assetData value for the first asset in the pair.","example":"0xf47261b04c32345ced77393b3530b1eed0f346429d","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"assetDataB","in":"query","description":"The assetData value for the second asset in the pair.","example":"0x0257179264389b814a946f3e92105513705ca6b990","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}},{"name":"page","in":"query","description":"The number of the page to request in the collection.","example":3,"schema":{"type":"number","default":1}},{"name":"perPage","in":"query","description":"The number of records to return per page.","example":10,"schema":{"type":"number","default":100}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"Returns a collection of available asset pairs with some meta info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiAssetDataPairsResponseSchema"},"example":{"total":43,"page":1,"perPage":100,"records":[{"assetDataA":{"minAmount":"0","maxAmount":"10000000000000000000","precision":5,"assetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d"},"assetDataB":{"minAmount":"0","maxAmount":"50000000000000000000","precision":5,"assetData":"0x0257179264389b814a946f3e92105513705ca6b990"}}]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/orders":{"get":{"description":"Retrieves a list of orders given query parameters. This endpoint should be [paginated](#section/Pagination). For querying an entire orderbook snapshot, the [orderbook endpoint](#operation/getOrderbook) is recommended. If both makerAssetData and takerAssetData are specified, returned orders will be sorted by price determined by (takerTokenAmount/makerTokenAmount) in ascending order. By default, orders returned by this endpoint are unsorted.","operationId":"getOrders","parameters":[{"name":"makerAssetProxyId","in":"query","description":"The maker [asset proxy id](https://0xproject.com/docs/0x.js#types-AssetProxyId) (example: \"0xf47261b0\" for ERC20, \"0x02571792\" for ERC721).","example":"0xf47261b0","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"takerAssetProxyId","in":"query","description":"The taker asset [asset proxy id](https://0xproject.com/docs/0x.js#types-AssetProxyId) (example: \"0xf47261b0\" for ERC20, \"0x02571792\" for ERC721).","example":"0x02571792","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"makerAssetAddress","in":"query","description":"The contract address for the maker asset.","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"takerAssetAddress","in":"query","description":"The contract address for the taker asset.","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"exchangeAddress","in":"query","description":"Same as exchangeAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"senderAddress","in":"query","description":"Same as senderAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"makerAssetData","in":"query","description":"Same as makerAssetData in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"takerAssetData","in":"query","description":"Same as takerAssetData in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"traderAssetData","in":"query","description":"Same as traderAssetData in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"makerAddress","in":"query","description":"Same as makerAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"takerAddress","in":"query","description":"Same as takerAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"traderAddress","in":"query","description":"Same as traderAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"feeRecipientAddress","in":"query","description":"Same as feeRecipientAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}},{"name":"page","in":"query","description":"The number of the page to request in the collection.","example":3,"schema":{"type":"number","default":1}},{"name":"perPage","in":"query","description":"The number of records to return per page.","example":10,"schema":{"type":"number","default":100}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"A collection of 0x orders with meta-data as specified by query params","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrdersResponseSchema"},"example":{"total":984,"page":1,"perPage":100,"records":[{"order":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerFee":"100000000000000","takerFee":"200000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33"},"metaData":{}}]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/order/{orderHash}":{"get":{"description":"Retrieves the 0x order with meta info that is associated with the hash.","operationId":"getOrder","parameters":[{"name":"orderHash","in":"path","description":"The hash of the desired 0x order.","example":"0xd4b103c42d2512eef3fee775e097f044291615d25f5d71e0ac70dbd49d223591","schema":{"$ref":"#/components/schemas/orderHashSchema"}},{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"The order and meta info associated with the orderHash","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrderSchema"},"example":{"order":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerFee":"100000000000000","takerFee":"200000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33"},"metaData":{}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/orderbook":{"get":{"description":"Retrieves the orderbook for a given asset pair. This endpoint should be [paginated](#section/Pagination). Bids will be sorted in descending order by price, and asks will be sorted in ascending order by price. Within the price sorted orders, the orders are further sorted by _taker fee price_ which is defined as the **takerFee** divided by **takerTokenAmount**. After _taker fee price_, orders are to be sorted by expiration in ascending order. The way pagination works for this endpoint is that the **page** and **perPage** query params apply to both `bids` and `asks` collections, and if `page` * `perPage` > `total` for a certain collection, the `records` for that collection should just be empty. ","operationId":"getOrderbook","parameters":[{"name":"baseAssetData","in":"query","description":"assetData (makerAssetData or takerAssetData) designated as the base currency in the [currency pair calculation](https://en.wikipedia.org/wiki/Currency_pair) of price.","required":true,"example":"0xf47261b04c32345ced77393b3530b1eed0f346429d","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"quoteAssetData","in":"query","description":"assetData (makerAssetData or takerAssetData) designated as the quote currency in the currency pair calculation of price (required).","required":true,"example":"0xf47261b04c32345ced77393b3530b1eed0f346429d","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}},{"name":"page","in":"query","description":"The number of the page to request in the collection.","example":3,"schema":{"type":"number","default":1}},{"name":"perPage","in":"query","description":"The number of records to return per page.","example":10,"schema":{"type":"number","default":100}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"The sorted order book for the specified asset pair.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrderbookResponseSchema"},"example":{"bids":{"total":325,"page":2,"perPage":100,"records":[{"order":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerFee":"100000000000000","takerFee":"200000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33"},"metaData":{}}]},"asks":{"total":500,"page":2,"perPage":100,"records":[{"order":{"makerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","takerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"20000000000000000","takerAssetAmount":"10000000000000000","makerFee":"200000000000000","takerFee":"100000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","takerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x013842a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b3518891"},"metaData":{}}]}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/order_config":{"get":{"description":"Relayers have full discretion over the orders that they are willing to host on their orderbooks (e.g what fees they charge, etc...). In order for traders to discover their requirements programmatically, they can send an incomplete order to this endpoint and receive the missing fields, specifc to that order. This gives relayers a large amount of flexibility to tailor fees to unique traders, trading pairs and volume amounts. Submit a partial order and receive information required to complete the order: `senderAddress`, `feeRecipientAddress`, `makerFee`, `takerFee`. ","operationId":"getOrderConfig","parameters":[{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}}],"requestBody":{"description":"The fields of a 0x order the relayer may want to decide what configuration to send back.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrderConfigPayloadSchema"},"example":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","expirationTimeSeconds":"1532560590"}}}},"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"The additional fields necessary in order to submit an order to the relayer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrderConfigResponseSchema"},"example":{"senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","makerFee":"100000000000000","takerFee":"200000000000000"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/fee_recipients":{"get":{"description":"Retrieves a collection of all fee recipient addresses for a relayer. This endpoint should be [paginated](#section/Pagination).","operationId":"getFeeRecipients","parameters":[{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}},{"name":"page","in":"query","description":"The number of the page to request in the collection.","example":3,"schema":{"type":"number","default":1}},{"name":"perPage","in":"query","description":"The number of records to return per page.","example":10,"schema":{"type":"number","default":100}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"A collection of all used fee recipient addresses.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiFeeRecipientsResponseSchema"},"example":{"total":3,"page":1,"perPage":10,"records":["0x6eC92694ea172ebC430C30fa31De87620967A082","0x9e56625509c2f60af937f23b7b532600390e8c8b","0xa2b31dacf30a9c50ca473337c01d8a201ae33e32"]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/order":{"post":{"description":"Submit a signed order to the relayer.","operationId":"postOrder","parameters":[{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}}],"requestBody":{"description":"A valid signed 0x order based on the schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/signedOrderSchema"},"example":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerFee":"100000000000000","takerFee":"200000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33"}}}},"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"OK","content":{}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}}},"components":{"schemas":{"numberSchema":{"type":"string","pattern":"^\\d+(\\.\\d+)?$"},"addressSchema":{"type":"string","pattern":"^0x[0-9a-f]{40}$"},"hexSchema":{"type":"string","pattern":"^0x(([0-9a-f][0-9a-f])+)?$"},"orderHashSchema":{"type":"string","pattern":"^0x[0-9a-fA-F]{64}$"},"orderSchema":{"properties":{"makerAddress":{"$ref":"#/components/schemas/addressSchema"},"takerAddress":{"$ref":"#/components/schemas/addressSchema"},"makerFee":{"$ref":"#/components/schemas/numberSchema"},"takerFee":{"$ref":"#/components/schemas/numberSchema"},"senderAddress":{"$ref":"#/components/schemas/addressSchema"},"makerAssetAmount":{"$ref":"#/components/schemas/numberSchema"},"takerAssetAmount":{"$ref":"#/components/schemas/numberSchema"},"makerAssetData":{"$ref":"#/components/schemas/hexSchema"},"takerAssetData":{"$ref":"#/components/schemas/hexSchema"},"salt":{"$ref":"#/components/schemas/numberSchema"},"exchangeAddress":{"$ref":"#/components/schemas/addressSchema"},"feeRecipientAddress":{"$ref":"#/components/schemas/addressSchema"},"expirationTimeSeconds":{"$ref":"#/components/schemas/numberSchema"}},"required":["makerAddress","takerAddress","makerFee","takerFee","senderAddress","makerAssetAmount","takerAssetAmount","makerAssetData","takerAssetData","salt","exchangeAddress","feeRecipientAddress","expirationTimeSeconds"],"type":"object"},"signedOrderSchema":{"allOf":[{"$ref":"#/components/schemas/orderSchema"},{"properties":{"signature":{"$ref":"#/components/schemas/hexSchema"}},"required":["signature"]}]},"signedOrdersSchema":{"type":"array","items":{"$ref":"#/components/schemas/signedOrderSchema"}},"ordersSchema":{"type":"array","items":{"$ref":"#/components/schemas/orderSchema"}},"paginatedCollectionSchema":{"type":"object","properties":{"total":{"type":"number"},"perPage":{"type":"number"},"page":{"type":"number"}},"required":["total","perPage","page"]},"relayerApiErrorResponseSchema":{"type":"object","properties":{"code":{"type":"integer","minimum":100,"maximum":103},"reason":{"type":"string"},"validationErrors":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"code":{"type":"integer","minimum":1000,"maximum":1006},"reason":{"type":"string"}},"required":["field","code","reason"]}}},"required":["code","reason"]},"relayerApiFeeRecipientsResponseSchema":{"type":"object","allOf":[{"$ref":"#/components/schemas/paginatedCollectionSchema"},{"properties":{"records":{"id":"#/components/schemas/relayerApiFeeRecipientsSchema","type":"array","items":{"$ref":"#/components/schemas/addressSchema"}}},"required":["records"]}]},"relayerApiOrderSchema":{"type":"object","properties":{"order":{"$ref":"#/components/schemas/orderSchema"},"metaData":{"type":"object"}},"required":["order","metaData"]},"relayerApiOrdersSchema":{"type":"array","items":{"$ref":"#/components/schemas/relayerApiOrderSchema"}},"relayerApiOrderConfigPayloadSchema":{"type":"object","properties":{"makerAddress":{"$ref":"#/components/schemas/addressSchema"},"takerAddress":{"$ref":"#/components/schemas/addressSchema"},"makerAssetAmount":{"$ref":"#/components/schemas/numberSchema"},"takerAssetAmount":{"$ref":"#/components/schemas/numberSchema"},"makerAssetData":{"$ref":"#/components/schemas/hexSchema"},"takerAssetData":{"$ref":"#/components/schemas/hexSchema"},"exchangeAddress":{"$ref":"#/components/schemas/addressSchema"},"expirationTimeSeconds":{"$ref":"#/components/schemas/numberSchema"}},"required":["makerAddress","takerAddress","makerAssetAmount","takerAssetAmount","makerAssetData","takerAssetData","exchangeAddress","expirationTimeSeconds"]},"relayerApiOrderConfigResponseSchema":{"type":"object","properties":{"makerFee":{"$ref":"#/components/schemas/numberSchema"},"takerFee":{"$ref":"#/components/schemas/numberSchema"},"feeRecipientAddress":{"$ref":"#/components/schemas/addressSchema"},"senderAddress":{"$ref":"#/components/schemas/addressSchema"}},"required":["makerFee","takerFee","feeRecipientAddress","senderAddress"]},"relayerApiOrderbookResponseSchema":{"type":"object","properties":{"bids":{"$ref":"#/components/schemas/relayerApiOrdersResponseSchema"},"asks":{"$ref":"#/components/schemas/relayerApiOrdersResponseSchema"}},"required":["bids","asks"]},"relayerApiAssetDataPairsResponseSchema":{"type":"object","allOf":[{"$ref":"#/components/schemas/paginatedCollectionSchema"},{"properties":{"records":{"$ref":"#/components/schemas/relayerApiAssetDataPairsSchema"}},"required":["records"]}]},"relayerApiAssetDataTradeInfoSchema":{"type":"object","properties":{"assetData":{"$ref":"#/components/schemas/hexSchema"},"minAmount":{"$ref":"#/components/schemas/numberSchema"},"maxAmount":{"$ref":"#/components/schemas/numberSchema"},"precision":{"type":"number"}},"required":["assetData"]},"relayerApiOrdersChannelSubscribeSchema":{"type":"object","properties":{"type":{"enum":["subscribe"]},"channel":{"enum":["orders"]},"requestId":{"type":"string"},"payload":{"$ref":"#/components/schemas/relayerApiOrdersChannelSubscribePayload"}},"required":["type","channel","requestId"]},"relayerApiOrdersChannelSubscribePayload":{"type":"object","properties":{"makerAssetProxyId":{"$ref":"#/components/schemas/hexSchema"},"takerAssetProxyId":{"$ref":"#/components/schemas/hexSchema"},"networkId":{"type":"number"},"makerAssetAddress":{"$ref":"#/components/schemas/addressSchema"},"takerAssetAddress":{"$ref":"#/components/schemas/addressSchema"},"makerAssetData":{"$ref":"#/components/schemas/hexSchema"},"takerAssetData":{"$ref":"#/components/schemas/hexSchema"},"traderAssetData":{"$ref":"#/components/schemas/hexSchema"}}},"relayerApiOrdersChannelUpdateSchema":{"type":"object","properties":{"type":{"enum":["update"]},"channel":{"enum":["orders"]},"requestId":{"type":"string"},"payload":{"$ref":"#/components/schemas/relayerApiOrdersSchema"}},"required":["type","channel","requestId"]},"relayerApiOrdersResponseSchema":{"type":"object","allOf":[{"$ref":"#/components/schemas/paginatedCollectionSchema"},{"properties":{"records":{"$ref":"#/components/schemas/relayerApiOrdersSchema"}},"required":["records"]}]},"relayerApiAssetDataPairsSchema":{"type":"array","items":{"properties":{"assetDataA":{"$ref":"#/components/schemas/relayerApiAssetDataTradeInfoSchema"},"assetDataB":{"$ref":"#/components/schemas/relayerApiAssetDataTradeInfoSchema"}},"required":["assetDataA","assetDataB"],"type":"object"}}}}} \ No newline at end of file +{"openapi":"3.0.0","info":{"version":"2.0.0","title":"Standard Relayer REST API","description":"# Testing\n\nUse the [sra-report](https://github.com/0xProject/0x-monorepo/tree/development/packages/sra-report) command line tool to test your API for SRA compliance.\n\n# Schemas\n\nThe [JSON schemas](http://json-schema.org/) for the API payloads and responses can be found in [@0xproject/json-schemas](https://github.com/0xProject/0x.js/tree/development/packages/json-schemas). Examples of each payload and response can be found in the library's [test suite](https://github.com/0xProject/0x.js/blob/development/packages/json-schemas/test/schema_test.ts#L1).\n\n```bash\nnpm install @0xproject/json-schemas --save\n```\n\nYou can easily validate your API's payloads and responses using the [@0xproject/json-schemas](https://github.com/0xProject/0x.js/tree/development/packages/json-schemas) package:\n\n```js\nimport {SchemaValidator, ValidatorResult, schemas} from '@0xproject/json-schemas';\n\nconst {relayerApiTokenPairsResponseSchema} = schemas;\nconst validator = new SchemaValidator();\n\nconst tokenPairsResponse = {\n ...\n};\nconst validatorResult: ValidatorResult = validator.validate(tokenPairsResponse, relayerApiTokenPairsResponseSchema);\n```\n\n# Pagination\n\nRequests that return potentially large collections should respond to the **?page** and **?perPage** parameters. For example:\n\n```bash\n$ curl https://api.example-relayer.com/v2/asset_pairs?page=3&perPage=20\n```\n\nPage numbering should be 1-indexed, not 0-indexed. If a query provides an unreasonable (ie. too high) `perPage` value, the response can return a validation error as specified in the [errors section](#section/Errors). If the query specifies a `page` that does not exist (ie. there are not enough `records`), the response should just return an empty `records` array.\n\nAll endpoints that are paginated should return a `total`, `page`, `perPage` and a `records` value in the top level of the collection. The value of `total` should be the total number of records for a given query, whereas `records` should be an array representing the response to the query for that page. `page` and `perPage`, are the same values that were specified in the request. See the note in [miscellaneous](#section/Misc.) about formatting `snake_case` vs. `lowerCamelCase`.\n\nThese requests include the [`/v2/asset_pairs`](#operation/getAssetPairs), [`/v2/orders`](#operation/getOrders), [`/v2/fee_recipients`](#operation/getFeeRecipients) and [`/v2/orderbook`](#operation/getOrderbook) endpoints.\n\n# Network Id\n\nAll requests should be able to specify a **?networkId** query param for all supported networks. For example:\n\n```bash\n$ curl https://api.example-relayer.com/v2/asset_pairs?networkId=1\n```\n\nIf the query param is not provided, it should default to **1** (mainnet).\n\nNetworks and their Ids:\n\n| Network Id | Network Name |\n| ---------- | ------------ |\n| 1 | Mainnet |\n| 42 | Kovan |\n| 3 | Ropsten |\n| 4 | Rinkeby |\n\nIf a certain network is not supported, the response should **400** as specified in the [error response](#section/Errors) section. For example:\n\n```json\n{\n \"code\": 100,\n \"reason\": \"Validation failed\",\n \"validationErrors\": [\n {\n \"field\": \"networkId\",\n \"code\": 1006,\n \"reason\": \"Network id 42 is not supported\"\n }\n ]\n}\n```\n\n# Link Header\n\nA [Link Header](https://tools.ietf.org/html/rfc5988) can be included in a response to provide clients with more context about paging\nFor example:\n\n```bash\nLink: ; rel=\"next\",\n; rel=\"last\"\n```\n\nThis `Link` response header contains one or more Hypermedia link relations.\n\nThe possible `rel` values are:\n\n| Name | Description |\n| ----- | ------------------------------------------------------------- |\n| next | The link relation for the immediate next page of results. |\n| last | The link relation for the last page of results. |\n| first | The link relation for the first page of results. |\n| prev | The link relation for the immediate previous page of results. |\n\n# Rate Limits\n\nRate limit guidance for clients can be optionally returned in the response headers:\n\n| Header Name | Description |\n| --------------------- | ---------------------------------------------------------------------------- |\n| X-RateLimit-Limit | The maximum number of requests you're permitted to make per hour. |\n| X-RateLimit-Remaining | The number of requests remaining in the current rate limit window. |\n| X-RateLimit-Reset | The time at which the current rate limit window resets in UTC epoch seconds. |\n\nFor example:\n\n```bash\n$ curl -i https://api.example-relayer.com/v2/asset_pairs\nHTTP/1.1 200 OK\nDate: Mon, 20 Oct 2017 12:30:06 GMT\nStatus: 200 OK\nX-RateLimit-Limit: 60\nX-RateLimit-Remaining: 56\nX-RateLimit-Reset: 1372700873\n```\n\nWhen a rate limit is exceeded, a status of **429 Too Many Requests** should be returned.\n\n# Errors\n\nUnless the spec defines otherwise, errors to bad requests should respond with HTTP 4xx or status codes.\n\n## Common error codes\n\n| Code | Reason |\n| ---- | --------------------------------------- |\n| 400 | Bad Request – Invalid request format |\n| 404 | Not found |\n| 429 | Too many requests - Rate limit exceeded |\n| 500 | Internal Server Error |\n| 501 | Not Implemented |\n\n## Error reporting format\n\nFor all **400** responses, see the [error response schema](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_error_response_schema.ts#L1).\n\n```json\n{\n \"code\": 101,\n \"reason\": \"Validation failed\",\n \"validationErrors\": [\n {\n \"field\": \"maker\",\n \"code\": 1002,\n \"reason\": \"Invalid address\"\n }\n ]\n}\n```\n\nGeneral error codes:\n\n```bash\n100 - Validation Failed\n101 - Malformed JSON\n102 - Order submission disabled\n103 - Throttled\n```\n\nValidation error codes:\n\n```bash\n1000 - Required field\n1001 - Incorrect format\n1002 - Invalid address\n1003 - Address not supported\n1004 - Value out of range\n1005 - Invalid signature or hash\n1006 - Unsupported option\n```\n\n# Asset Data Encoding\n\nAs we now support multiple [token transfer proxies](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxy), the identifier of which proxy to use for the token transfer must be encoded, along with the token information. Each proxy in 0x v2 has a unique identifier. If you're using 0x.js there will be helper methods for this [encoding](https://0xproject.com/docs/0x.js#zeroEx-encodeERC20AssetData) and [decoding](https://0xproject.com/docs/0x.js#zeroEx-decodeAssetProxyId).\n\nThe identifier for the Proxy uses a similar scheme to [ABI function selectors](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI#function-selector).\n\n```js\n// ERC20 Proxy ID 0xf47261b0\nbytes4(keccak256('ERC20Token(address)'));\n// ERC721 Proxy ID 0x08e937fa\nbytes4(keccak256('ERC721Token(address,uint256)'));\n```\n\nAsset data is encoded using [ABI encoding](https://solidity.readthedocs.io/en/develop/abi-spec.html).\n\nFor example, encoding the ERC20 token contract (address: 0x1dc4c1cefef38a777b15aa20260a54e584b16c48) using the ERC20 Transfer Proxy (id: 0xf47261b0) would be:\n\n```bash\n0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48\n```\n\nEncoding the ERC721 token contract (address: `0x371b13d97f4bf77d724e78c16b7dc74099f40e84`), token id (id: `99`, which hex encoded is `0x63`) and the ERC721 Transfer Proxy (id: 0x08e937fa) would be:\n\n```bash\n0x08e937fa000000000000000000000000371b13d97f4bf77d724e78c16b7dc74099f40e840000000000000000000000000000000000000000000000000000000000000063\n```\n\nFor more information see [the Asset Proxy](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#erc20proxy) section of the v2 spec and the [Ethereum ABI Spec](https://solidity.readthedocs.io/en/develop/abi-spec.html).\n\n# Meta Data in Order Responses\n\nIn 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.\n\nA 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).\n\n# Misc.\n\n* All requests and responses should be of **application/json** content type\n* All token amounts are sent in amounts of the smallest level of precision (base units). (e.g if a token has 18 decimal places, selling 1 token would show up as selling `'1000000000000000000'` units by this API).\n* All addresses are sent as lower-case (non-checksummed) Ethereum addresses with the `0x` prefix.\n* All parameters are to be written in `lowerCamelCase`.\n","license":{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0.html"}},"paths":{"/v2/asset_pairs":{"get":{"description":"Retrieves a list of available asset pairs and the information required to trade them (in any order). Setting only `assetDataA` or `assetDataB` returns pairs filtered by that asset only.","operationId":"getAssetPairs","parameters":[{"name":"assetDataA","in":"query","description":"The assetData value for the first asset in the pair.","example":"0xf47261b04c32345ced77393b3530b1eed0f346429d","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"assetDataB","in":"query","description":"The assetData value for the second asset in the pair.","example":"0x0257179264389b814a946f3e92105513705ca6b990","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}},{"name":"page","in":"query","description":"The number of the page to request in the collection.","example":3,"schema":{"type":"number","default":1}},{"name":"perPage","in":"query","description":"The number of records to return per page.","example":10,"schema":{"type":"number","default":100}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"Returns a collection of available asset pairs with some meta info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiAssetDataPairsResponseSchema"},"example":{"total":43,"page":1,"perPage":100,"records":[{"assetDataA":{"minAmount":"0","maxAmount":"10000000000000000000","precision":5,"assetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d"},"assetDataB":{"minAmount":"0","maxAmount":"50000000000000000000","precision":5,"assetData":"0x0257179264389b814a946f3e92105513705ca6b990"}}]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/orders":{"get":{"description":"Retrieves a list of orders given query parameters. This endpoint should be [paginated](#section/Pagination). For querying an entire orderbook snapshot, the [orderbook endpoint](#operation/getOrderbook) is recommended. If both makerAssetData and takerAssetData are specified, returned orders will be sorted by price determined by (takerTokenAmount/makerTokenAmount) in ascending order. By default, orders returned by this endpoint are unsorted.","operationId":"getOrders","parameters":[{"name":"makerAssetProxyId","in":"query","description":"The maker [asset proxy id](https://0xproject.com/docs/0x.js#types-AssetProxyId) (example: \"0xf47261b0\" for ERC20, \"0x02571792\" for ERC721).","example":"0xf47261b0","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"takerAssetProxyId","in":"query","description":"The taker asset [asset proxy id](https://0xproject.com/docs/0x.js#types-AssetProxyId) (example: \"0xf47261b0\" for ERC20, \"0x02571792\" for ERC721).","example":"0x02571792","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"makerAssetAddress","in":"query","description":"The contract address for the maker asset.","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"takerAssetAddress","in":"query","description":"The contract address for the taker asset.","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"exchangeAddress","in":"query","description":"Same as exchangeAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"senderAddress","in":"query","description":"Same as senderAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"makerAssetData","in":"query","description":"Same as makerAssetData in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"takerAssetData","in":"query","description":"Same as takerAssetData in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"traderAssetData","in":"query","description":"Same as traderAssetData in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"makerAddress","in":"query","description":"Same as makerAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"takerAddress","in":"query","description":"Same as takerAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"traderAddress","in":"query","description":"Same as traderAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"feeRecipientAddress","in":"query","description":"Same as feeRecipientAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}},{"name":"page","in":"query","description":"The number of the page to request in the collection.","example":3,"schema":{"type":"number","default":1}},{"name":"perPage","in":"query","description":"The number of records to return per page.","example":10,"schema":{"type":"number","default":100}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"A collection of 0x orders with meta-data as specified by query params","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrdersResponseSchema"},"example":{"total":984,"page":1,"perPage":100,"records":[{"order":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerFee":"100000000000000","takerFee":"200000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33"},"metaData":{}}]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/order/{orderHash}":{"get":{"description":"Retrieves the 0x order with meta info that is associated with the hash.","operationId":"getOrder","parameters":[{"name":"orderHash","in":"path","description":"The hash of the desired 0x order.","example":"0xd4b103c42d2512eef3fee775e097f044291615d25f5d71e0ac70dbd49d223591","schema":{"$ref":"#/components/schemas/orderHashSchema"}},{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"The order and meta info associated with the orderHash","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrderSchema"},"example":{"order":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerFee":"100000000000000","takerFee":"200000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33"},"metaData":{}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/orderbook":{"get":{"description":"Retrieves the orderbook for a given asset pair. This endpoint should be [paginated](#section/Pagination). Bids will be sorted in descending order by price, and asks will be sorted in ascending order by price. Within the price sorted orders, the orders are further sorted by _taker fee price_ which is defined as the **takerFee** divided by **takerTokenAmount**. After _taker fee price_, orders are to be sorted by expiration in ascending order. The way pagination works for this endpoint is that the **page** and **perPage** query params apply to both `bids` and `asks` collections, and if `page` * `perPage` > `total` for a certain collection, the `records` for that collection should just be empty. ","operationId":"getOrderbook","parameters":[{"name":"baseAssetData","in":"query","description":"assetData (makerAssetData or takerAssetData) designated as the base currency in the [currency pair calculation](https://en.wikipedia.org/wiki/Currency_pair) of price.","required":true,"example":"0xf47261b04c32345ced77393b3530b1eed0f346429d","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"quoteAssetData","in":"query","description":"assetData (makerAssetData or takerAssetData) designated as the quote currency in the currency pair calculation of price (required).","required":true,"example":"0xf47261b04c32345ced77393b3530b1eed0f346429d","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}},{"name":"page","in":"query","description":"The number of the page to request in the collection.","example":3,"schema":{"type":"number","default":1}},{"name":"perPage","in":"query","description":"The number of records to return per page.","example":10,"schema":{"type":"number","default":100}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"The sorted order book for the specified asset pair.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrderbookResponseSchema"},"example":{"bids":{"total":325,"page":2,"perPage":100,"records":[{"order":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerFee":"100000000000000","takerFee":"200000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33"},"metaData":{}}]},"asks":{"total":500,"page":2,"perPage":100,"records":[{"order":{"makerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","takerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"20000000000000000","takerAssetAmount":"10000000000000000","makerFee":"200000000000000","takerFee":"100000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","takerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x013842a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b3518891"},"metaData":{}}]}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/order_config":{"get":{"description":"Relayers have full discretion over the orders that they are willing to host on their orderbooks (e.g what fees they charge, etc...). In order for traders to discover their requirements programmatically, they can send an incomplete order to this endpoint and receive the missing fields, specifc to that order. This gives relayers a large amount of flexibility to tailor fees to unique traders, trading pairs and volume amounts. Submit a partial order and receive information required to complete the order: `senderAddress`, `feeRecipientAddress`, `makerFee`, `takerFee`. ","operationId":"getOrderConfig","parameters":[{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}}],"requestBody":{"description":"The fields of a 0x order the relayer may want to decide what configuration to send back.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrderConfigPayloadSchema"},"example":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","expirationTimeSeconds":"1532560590"}}}},"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"The additional fields necessary in order to submit an order to the relayer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrderConfigResponseSchema"},"example":{"senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","makerFee":"100000000000000","takerFee":"200000000000000"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/fee_recipients":{"get":{"description":"Retrieves a collection of all fee recipient addresses for a relayer. This endpoint should be [paginated](#section/Pagination).","operationId":"getFeeRecipients","parameters":[{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}},{"name":"page","in":"query","description":"The number of the page to request in the collection.","example":3,"schema":{"type":"number","default":1}},{"name":"perPage","in":"query","description":"The number of records to return per page.","example":10,"schema":{"type":"number","default":100}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"A collection of all used fee recipient addresses.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiFeeRecipientsResponseSchema"},"example":{"total":3,"page":1,"perPage":10,"records":["0x6eC92694ea172ebC430C30fa31De87620967A082","0x9e56625509c2f60af937f23b7b532600390e8c8b","0xa2b31dacf30a9c50ca473337c01d8a201ae33e32"]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/order":{"post":{"description":"Submit a signed order to the relayer.","operationId":"postOrder","parameters":[{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}}],"requestBody":{"description":"A valid signed 0x order based on the schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/signedOrderSchema"},"example":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerFee":"100000000000000","takerFee":"200000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33"}}}},"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"OK","content":{}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}}},"components":{"schemas":{"numberSchema":{"type":"string","pattern":"^\\d+(\\.\\d+)?$"},"addressSchema":{"type":"string","pattern":"^0x[0-9a-f]{40}$"},"hexSchema":{"type":"string","pattern":"^0x(([0-9a-f][0-9a-f])+)?$"},"orderHashSchema":{"type":"string","pattern":"^0x[0-9a-fA-F]{64}$"},"orderSchema":{"properties":{"makerAddress":{"$ref":"#/components/schemas/addressSchema"},"takerAddress":{"$ref":"#/components/schemas/addressSchema"},"makerFee":{"$ref":"#/components/schemas/numberSchema"},"takerFee":{"$ref":"#/components/schemas/numberSchema"},"senderAddress":{"$ref":"#/components/schemas/addressSchema"},"makerAssetAmount":{"$ref":"#/components/schemas/numberSchema"},"takerAssetAmount":{"$ref":"#/components/schemas/numberSchema"},"makerAssetData":{"$ref":"#/components/schemas/hexSchema"},"takerAssetData":{"$ref":"#/components/schemas/hexSchema"},"salt":{"$ref":"#/components/schemas/numberSchema"},"exchangeAddress":{"$ref":"#/components/schemas/addressSchema"},"feeRecipientAddress":{"$ref":"#/components/schemas/addressSchema"},"expirationTimeSeconds":{"$ref":"#/components/schemas/numberSchema"}},"required":["makerAddress","takerAddress","makerFee","takerFee","senderAddress","makerAssetAmount","takerAssetAmount","makerAssetData","takerAssetData","salt","exchangeAddress","feeRecipientAddress","expirationTimeSeconds"],"type":"object"},"signedOrderSchema":{"allOf":[{"$ref":"#/components/schemas/orderSchema"},{"properties":{"signature":{"$ref":"#/components/schemas/hexSchema"}},"required":["signature"]}]},"signedOrdersSchema":{"type":"array","items":{"$ref":"#/components/schemas/signedOrderSchema"}},"ordersSchema":{"type":"array","items":{"$ref":"#/components/schemas/orderSchema"}},"paginatedCollectionSchema":{"type":"object","properties":{"total":{"type":"number"},"perPage":{"type":"number"},"page":{"type":"number"}},"required":["total","perPage","page"]},"relayerApiErrorResponseSchema":{"type":"object","properties":{"code":{"type":"integer","minimum":100,"maximum":103},"reason":{"type":"string"},"validationErrors":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"code":{"type":"integer","minimum":1000,"maximum":1006},"reason":{"type":"string"}},"required":["field","code","reason"]}}},"required":["code","reason"]},"relayerApiFeeRecipientsResponseSchema":{"type":"object","allOf":[{"$ref":"#/components/schemas/paginatedCollectionSchema"},{"properties":{"records":{"type":"array","items":{"$ref":"#/components/schemas/addressSchema"}}},"required":["records"]}]},"relayerApiOrderSchema":{"type":"object","properties":{"order":{"$ref":"#/components/schemas/orderSchema"},"metaData":{"type":"object"}},"required":["order","metaData"]},"relayerApiOrdersSchema":{"type":"array","items":{"$ref":"#/components/schemas/relayerApiOrderSchema"}},"relayerApiOrderConfigPayloadSchema":{"type":"object","properties":{"makerAddress":{"$ref":"#/components/schemas/addressSchema"},"takerAddress":{"$ref":"#/components/schemas/addressSchema"},"makerAssetAmount":{"$ref":"#/components/schemas/numberSchema"},"takerAssetAmount":{"$ref":"#/components/schemas/numberSchema"},"makerAssetData":{"$ref":"#/components/schemas/hexSchema"},"takerAssetData":{"$ref":"#/components/schemas/hexSchema"},"exchangeAddress":{"$ref":"#/components/schemas/addressSchema"},"expirationTimeSeconds":{"$ref":"#/components/schemas/numberSchema"}},"required":["makerAddress","takerAddress","makerAssetAmount","takerAssetAmount","makerAssetData","takerAssetData","exchangeAddress","expirationTimeSeconds"]},"relayerApiOrderConfigResponseSchema":{"type":"object","properties":{"makerFee":{"$ref":"#/components/schemas/numberSchema"},"takerFee":{"$ref":"#/components/schemas/numberSchema"},"feeRecipientAddress":{"$ref":"#/components/schemas/addressSchema"},"senderAddress":{"$ref":"#/components/schemas/addressSchema"}},"required":["makerFee","takerFee","feeRecipientAddress","senderAddress"]},"relayerApiOrderbookResponseSchema":{"type":"object","properties":{"bids":{"$ref":"#/components/schemas/relayerApiOrdersResponseSchema"},"asks":{"$ref":"#/components/schemas/relayerApiOrdersResponseSchema"}},"required":["bids","asks"]},"relayerApiAssetDataPairsResponseSchema":{"type":"object","allOf":[{"$ref":"#/components/schemas/paginatedCollectionSchema"},{"properties":{"records":{"$ref":"#/components/schemas/relayerApiAssetDataPairsSchema"}},"required":["records"]}]},"relayerApiAssetDataTradeInfoSchema":{"type":"object","properties":{"assetData":{"$ref":"#/components/schemas/hexSchema"},"minAmount":{"$ref":"#/components/schemas/numberSchema"},"maxAmount":{"$ref":"#/components/schemas/numberSchema"},"precision":{"type":"number"}},"required":["assetData"]},"relayerApiOrdersChannelSubscribeSchema":{"type":"object","properties":{"type":{"enum":["subscribe"]},"channel":{"enum":["orders"]},"requestId":{"type":"string"},"payload":{"$ref":"#/components/schemas/relayerApiOrdersChannelSubscribePayload"}},"required":["type","channel","requestId"]},"relayerApiOrdersChannelSubscribePayload":{"type":"object","properties":{"makerAssetProxyId":{"$ref":"#/components/schemas/hexSchema"},"takerAssetProxyId":{"$ref":"#/components/schemas/hexSchema"},"networkId":{"type":"number"},"makerAssetAddress":{"$ref":"#/components/schemas/addressSchema"},"takerAssetAddress":{"$ref":"#/components/schemas/addressSchema"},"makerAssetData":{"$ref":"#/components/schemas/hexSchema"},"takerAssetData":{"$ref":"#/components/schemas/hexSchema"},"traderAssetData":{"$ref":"#/components/schemas/hexSchema"}}},"relayerApiOrdersChannelUpdateSchema":{"type":"object","properties":{"type":{"enum":["update"]},"channel":{"enum":["orders"]},"requestId":{"type":"string"},"payload":{"$ref":"#/components/schemas/relayerApiOrdersSchema"}},"required":["type","channel","requestId"]},"relayerApiOrdersResponseSchema":{"type":"object","allOf":[{"$ref":"#/components/schemas/paginatedCollectionSchema"},{"properties":{"records":{"$ref":"#/components/schemas/relayerApiOrdersSchema"}},"required":["records"]}]},"relayerApiAssetDataPairsSchema":{"type":"array","items":{"properties":{"assetDataA":{"$ref":"#/components/schemas/relayerApiAssetDataTradeInfoSchema"},"assetDataB":{"$ref":"#/components/schemas/relayerApiAssetDataTradeInfoSchema"}},"required":["assetDataA","assetDataB"],"type":"object"}}}}} \ No newline at end of file From b38ef579fb75c777fac2eef3d4bcda2c97014f0b Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Fri, 24 Aug 2018 19:11:10 +0100 Subject: [PATCH 012/120] Updated CHANGELOGS --- packages/0x.js/CHANGELOG.json | 3 ++- packages/0x.js/CHANGELOG.md | 12 ++++++++---- packages/abi-gen/CHANGELOG.json | 9 +++++++++ packages/abi-gen/CHANGELOG.md | 12 ++++++++---- packages/assert/CHANGELOG.json | 9 +++++++++ packages/assert/CHANGELOG.md | 12 ++++++++---- packages/base-contract/CHANGELOG.json | 9 +++++++++ packages/base-contract/CHANGELOG.md | 12 ++++++++---- packages/connect/CHANGELOG.json | 3 ++- packages/connect/CHANGELOG.md | 11 ++++++++--- packages/contract-wrappers/CHANGELOG.json | 3 ++- packages/contract-wrappers/CHANGELOG.md | 10 ++++++++-- packages/dev-utils/CHANGELOG.json | 9 +++++++++ packages/dev-utils/CHANGELOG.md | 10 +++++++--- packages/ethereum-types/CHANGELOG.json | 9 +++++++++ packages/ethereum-types/CHANGELOG.md | 11 ++++++++--- packages/fill-scenarios/CHANGELOG.json | 3 ++- packages/fill-scenarios/CHANGELOG.md | 8 ++++++-- packages/forwarder-helper/CHANGELOG.json | 3 ++- packages/forwarder-helper/CHANGELOG.md | 10 ++++++++++ packages/json-schemas/CHANGELOG.json | 3 ++- packages/json-schemas/CHANGELOG.md | 10 +++++++--- packages/migrations/CHANGELOG.json | 9 +++++++++ packages/migrations/CHANGELOG.md | 10 +++++++--- packages/order-utils/CHANGELOG.json | 3 ++- packages/order-utils/CHANGELOG.md | 17 ++++++++++++++--- packages/order-watcher/CHANGELOG.json | 3 ++- packages/order-watcher/CHANGELOG.md | 9 +++++++-- packages/react-docs/CHANGELOG.json | 9 +++++++++ packages/react-docs/CHANGELOG.md | 12 ++++++++---- packages/react-shared/CHANGELOG.json | 9 +++++++++ packages/react-shared/CHANGELOG.md | 12 ++++++++---- packages/sol-compiler/CHANGELOG.json | 3 ++- packages/sol-compiler/CHANGELOG.md | 12 +++++++++--- packages/sol-cov/CHANGELOG.json | 3 ++- packages/sol-cov/CHANGELOG.md | 12 ++++++++---- packages/sol-resolver/CHANGELOG.json | 9 +++++++++ packages/sol-resolver/CHANGELOG.md | 12 ++++++++---- packages/sra-api/CHANGELOG.json | 3 ++- packages/sra-api/CHANGELOG.md | 6 +++++- packages/sra-report/CHANGELOG.json | 9 +++++++++ packages/sra-report/CHANGELOG.md | 10 +++++++--- packages/subproviders/CHANGELOG.json | 3 ++- packages/subproviders/CHANGELOG.md | 10 +++++++--- packages/tslint-config/CHANGELOG.json | 9 +++++++++ packages/tslint-config/CHANGELOG.md | 10 +++++++--- packages/types/CHANGELOG.json | 3 ++- packages/types/CHANGELOG.md | 10 +++++++--- packages/typescript-typings/CHANGELOG.json | 9 +++++++++ packages/typescript-typings/CHANGELOG.md | 10 +++++++--- packages/utils/CHANGELOG.json | 9 +++++++++ packages/utils/CHANGELOG.md | 13 +++++++++---- packages/web3-wrapper/CHANGELOG.json | 3 ++- packages/web3-wrapper/CHANGELOG.md | 14 ++++++++++---- 54 files changed, 359 insertions(+), 97 deletions(-) create mode 100644 packages/forwarder-helper/CHANGELOG.md diff --git a/packages/0x.js/CHANGELOG.json b/packages/0x.js/CHANGELOG.json index 0f5a10e434..3469389589 100644 --- a/packages/0x.js/CHANGELOG.json +++ b/packages/0x.js/CHANGELOG.json @@ -7,7 +7,8 @@ "Re-organize the exported interface of 0x.js. Remove the `ZeroEx` class, and instead export the same exports as `0x.js`'s sub-packages: `@0xproject/contract-wrappers`, `@0xproject/order-utils` and `@0xproject/order-watcher`", "pr": 963 } - ] + ], + "timestamp": 1535133899 }, { "version": "1.0.1-rc.3", diff --git a/packages/0x.js/CHANGELOG.md b/packages/0x.js/CHANGELOG.md index adeaed9ebd..e949073537 100644 --- a/packages/0x.js/CHANGELOG.md +++ b/packages/0x.js/CHANGELOG.md @@ -5,7 +5,11 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.1-rc.3 - _August 13, 2018_ +## v1.0.1-rc.4 - _August 24, 2018_ + + * Re-organize the exported interface of 0x.js. Remove the `ZeroEx` class, and instead export the same exports as `0x.js`'s sub-packages: `@0xproject/contract-wrappers`, `@0xproject/order-utils` and `@0xproject/order-watcher` (#963) + +## v1.0.1-rc.3 - _August 14, 2018_ * Dependencies updated * Update ecSignOrderHashAsync to return the signature as a string for immediate use in contracts (#914) @@ -22,11 +26,11 @@ CHANGELOG * Dependencies updated -## v1.0.0-rc.2 - _July 19, 2018_ +## v1.0.0-rc.2 - _July 20, 2018_ * Remove `zeroEx.assetData` and instead re-export it's static functions directly off `ZeroEx` -## v1.0.0-rc.1 - _July 19, 2018_ +## v1.0.0-rc.1 - _July 20, 2018_ * Remove tokenRegistry wrapper (#863) * Rename `zeroEx.token` to `zeroEx.erc20Token`, and add `zeroEx.erc721Token` (#863) @@ -66,7 +70,7 @@ CHANGELOG * Renamed createOrderStateWatcher to createOrderWatcherAsync since it is now async (#579) * Renamed ZeroExError to ContractWrappersErrors since they now lives in the @0xproject/contract-wrappers subpackage (#579) -## v0.37.2 - _May 4, 2018_ +## v0.37.2 - _May 5, 2018_ * Dependencies updated diff --git a/packages/abi-gen/CHANGELOG.json b/packages/abi-gen/CHANGELOG.json index d7b084fe68..0b6a9a052d 100644 --- a/packages/abi-gen/CHANGELOG.json +++ b/packages/abi-gen/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535133899, + "version": "1.0.6", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1534210131, "version": "1.0.5", diff --git a/packages/abi-gen/CHANGELOG.md b/packages/abi-gen/CHANGELOG.md index 5368ae3f01..477f69e2cb 100644 --- a/packages/abi-gen/CHANGELOG.md +++ b/packages/abi-gen/CHANGELOG.md @@ -5,7 +5,11 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.5 - _August 13, 2018_ +## v1.0.6 - _August 24, 2018_ + + * Dependencies updated + +## v1.0.5 - _August 14, 2018_ * Dependencies updated @@ -25,7 +29,7 @@ CHANGELOG * Fix the abi-gen entry point in package.json (#901) -## v1.0.0 - _July 19, 2018_ +## v1.0.0 - _July 20, 2018_ * Convert e_r_c to erc in generated file names (#822) * Remove the output directory before writing to it (#822) @@ -43,7 +47,7 @@ CHANGELOG * Dependencies updated -## v0.3.1 - _May 31, 2018_ +## v0.3.1 - _June 1, 2018_ * Incorrect publish that was unpublished @@ -51,7 +55,7 @@ CHANGELOG * Properly export the executable binary (#588) -## v0.2.13 - _May 4, 2018_ +## v0.2.13 - _May 5, 2018_ * Dependencies updated diff --git a/packages/assert/CHANGELOG.json b/packages/assert/CHANGELOG.json index 1deacb7b56..01fd4c567e 100644 --- a/packages/assert/CHANGELOG.json +++ b/packages/assert/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535133899, + "version": "1.0.6", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1534210131, "version": "1.0.5", diff --git a/packages/assert/CHANGELOG.md b/packages/assert/CHANGELOG.md index cdb5e45d47..ffa34c48c2 100644 --- a/packages/assert/CHANGELOG.md +++ b/packages/assert/CHANGELOG.md @@ -5,7 +5,11 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.5 - _August 13, 2018_ +## v1.0.6 - _August 24, 2018_ + + * Dependencies updated + +## v1.0.5 - _August 14, 2018_ * Dependencies updated @@ -25,7 +29,7 @@ CHANGELOG * Dependencies updated -## v1.0.0 - _July 19, 2018_ +## v1.0.0 - _July 20, 2018_ * Fix bug in string enum assertion. We erroneously were checking against the enum keys, not values (#821) @@ -41,7 +45,7 @@ CHANGELOG * Dependencies updated -## v0.2.11 - _May 31, 2018_ +## v0.2.11 - _June 1, 2018_ * Incorrect publish that was unpublished @@ -49,7 +53,7 @@ CHANGELOG * Dependencies updated -## v0.2.9 - _May 4, 2018_ +## v0.2.9 - _May 5, 2018_ * Dependencies updated diff --git a/packages/base-contract/CHANGELOG.json b/packages/base-contract/CHANGELOG.json index 39e3cbe5eb..3f01ab0eb7 100644 --- a/packages/base-contract/CHANGELOG.json +++ b/packages/base-contract/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535133899, + "version": "2.0.0", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.0.0-rc.1", "changes": [ diff --git a/packages/base-contract/CHANGELOG.md b/packages/base-contract/CHANGELOG.md index 002ad931b9..634b3f5a72 100644 --- a/packages/base-contract/CHANGELOG.md +++ b/packages/base-contract/CHANGELOG.md @@ -5,7 +5,11 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v2.0.0-rc.1 - _August 13, 2018_ +## v2.0.0 - _August 24, 2018_ + + * Dependencies updated + +## v2.0.0-rc.1 - _August 14, 2018_ * Added strict encoding/decoding checks for sendTransaction and call (#915) @@ -25,7 +29,7 @@ CHANGELOG * Dependencies updated -## v1.0.0 - _July 19, 2018_ +## v1.0.0 - _July 20, 2018_ * Dependencies updated @@ -41,7 +45,7 @@ CHANGELOG * Update EthersJs to fix the `value.toLowerCase()` is not a function bug caused by `ethers.js` breaking patch version https://github.com/ethers-io/ethers.js/issues/201 -## v0.3.3 - _May 31, 2018_ +## v0.3.3 - _June 1, 2018_ * Incorrect publish that was unpublished @@ -49,7 +53,7 @@ CHANGELOG * Dependencies updated -## v0.3.1 - _May 4, 2018_ +## v0.3.1 - _May 5, 2018_ * Dependencies updated diff --git a/packages/connect/CHANGELOG.json b/packages/connect/CHANGELOG.json index 1d0efac95a..6cf679b34a 100644 --- a/packages/connect/CHANGELOG.json +++ b/packages/connect/CHANGELOG.json @@ -10,7 +10,8 @@ "note": "Stopped exporting `Order` type", "pr": 924 } - ] + ], + "timestamp": 1535133899 }, { "timestamp": 1534210131, diff --git a/packages/connect/CHANGELOG.md b/packages/connect/CHANGELOG.md index f9d84ff9c9..a6821f064b 100644 --- a/packages/connect/CHANGELOG.md +++ b/packages/connect/CHANGELOG.md @@ -5,7 +5,12 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.5 - _August 13, 2018_ +## v2.0.0-rc.1 - _August 24, 2018_ + + * Updated for SRA v2 (#974) + * Stopped exporting `Order` type (#924) + +## v1.0.5 - _August 14, 2018_ * Dependencies updated @@ -25,7 +30,7 @@ CHANGELOG * Dependencies updated -## v1.0.0 - _July 19, 2018_ +## v1.0.0 - _July 20, 2018_ * Remove `WebSocketOrderbookChannel` from the public interface and replace with `orderbookChannelFactory` @@ -49,7 +54,7 @@ CHANGELOG * Dependencies updated -## v0.6.12 - _May 4, 2018_ +## v0.6.12 - _May 5, 2018_ * Dependencies updated diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index 8e86d7d583..3809ad098e 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -16,7 +16,8 @@ "note": "Added Transaction Encoder for use with 0x Exchange executeTransaction", "pr": 975 } - ] + ], + "timestamp": 1535133899 }, { "version": "1.0.1-rc.3", diff --git a/packages/contract-wrappers/CHANGELOG.md b/packages/contract-wrappers/CHANGELOG.md index c2ad7218ec..b1003edfdb 100644 --- a/packages/contract-wrappers/CHANGELOG.md +++ b/packages/contract-wrappers/CHANGELOG.md @@ -5,7 +5,13 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.1-rc.3 - _August 13, 2018_ +## v1.0.1-rc.4 - _August 24, 2018_ + + * Export missing types: `TransactionEncoder`, `ContractAbi`, `JSONRPCRequestPayload`, `JSONRPCResponsePayload`, `JSONRPCErrorCallback`, `AbiDefinition`, `FunctionAbi`, `EventAbi`, `EventParameter`, `DecodedLogArgs`, `MethodAbi`, `ConstructorAbi`, `FallbackAbi`, `DataItem`, `ConstructorStateMutability`, `StateMutability` & `ExchangeSignatureValidatorApprovalEventArgs` (#924) + * Remove superfluous exported types: `ContractEvent`, `Token`, `OrderFillRequest`, `ContractEventArgs`, `LogEvent`, `OnOrderStateChangeCallback`, `ECSignature`, `OrderStateValid`, `OrderStateInvalid`, `OrderState`, `FilterObject`, `TransactionReceipt` & `TransactionReceiptWithDecodedLogs` (#924) + * Added Transaction Encoder for use with 0x Exchange executeTransaction (#975) + +## v1.0.1-rc.3 - _August 14, 2018_ * Added strict encoding/decoding checks for sendTransaction and call (#915) * Add ForwarderWrapper (#934) @@ -23,7 +29,7 @@ CHANGELOG * Dependencies updated -## v1.0.0-rc.1 - _July 19, 2018_ +## v1.0.0-rc.1 - _July 20, 2018_ * Update blockstream to v5.0 and propogate up caught errors to active subscriptions (#815) * Update to v2 of 0x rpotocol (#822) diff --git a/packages/dev-utils/CHANGELOG.json b/packages/dev-utils/CHANGELOG.json index 51ae117cfa..e0f08344b6 100644 --- a/packages/dev-utils/CHANGELOG.json +++ b/packages/dev-utils/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535133899, + "version": "1.0.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1534210131, "version": "1.0.4", diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index 1e244ee7d5..0e39de9264 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -5,7 +5,11 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.4 - _August 13, 2018_ +## v1.0.5 - _August 24, 2018_ + + * Dependencies updated + +## v1.0.4 - _August 14, 2018_ * Dependencies updated @@ -21,7 +25,7 @@ CHANGELOG * Dependencies updated -## v1.0.0 - _July 19, 2018_ +## v1.0.0 - _July 20, 2018_ * Dependencies updated @@ -47,7 +51,7 @@ CHANGELOG * Pass SolCompilerArtifactAdapter to CoverageSubprovider (#589) * Move callbackErrorReporter over from 0x.js (#579) -## v0.4.1 - _May 4, 2018_ +## v0.4.1 - _May 5, 2018_ * Dependencies updated diff --git a/packages/ethereum-types/CHANGELOG.json b/packages/ethereum-types/CHANGELOG.json index 64c6e6d27a..1db0e2785a 100644 --- a/packages/ethereum-types/CHANGELOG.json +++ b/packages/ethereum-types/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535133899, + "version": "1.0.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1534210131, "version": "1.0.4", diff --git a/packages/ethereum-types/CHANGELOG.md b/packages/ethereum-types/CHANGELOG.md index 67fa844372..76dd9ed193 100644 --- a/packages/ethereum-types/CHANGELOG.md +++ b/packages/ethereum-types/CHANGELOG.md @@ -5,7 +5,11 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.4 - _August 13, 2018_ +## v1.0.5 - _August 24, 2018_ + + * Dependencies updated + +## v1.0.4 - _August 14, 2018_ * Dependencies updated @@ -21,11 +25,12 @@ CHANGELOG * Dependencies updated -## v1.0.0 - _July 19, 2018_ +## v1.0.0 - _July 20, 2018_ * Add `TraceParams` interface for `debug_traceTransaction` parameters (#675) * Add `TransactionReceiptStatus` type (#812) + * Add Artifact types: `CompilerSettings`, `CompilerOptions`, `OutputField` (#924) -## v0.0.2 - _May 31, 2018_ +## v0.0.2 - _June 1, 2018_ * Initial publish (#642) diff --git a/packages/fill-scenarios/CHANGELOG.json b/packages/fill-scenarios/CHANGELOG.json index ae53b709a4..481273fc4c 100644 --- a/packages/fill-scenarios/CHANGELOG.json +++ b/packages/fill-scenarios/CHANGELOG.json @@ -5,7 +5,8 @@ { "note": "Dependencies updated" } - ] + ], + "timestamp": 1535133899 }, { "version": "1.0.1-rc.3", diff --git a/packages/fill-scenarios/CHANGELOG.md b/packages/fill-scenarios/CHANGELOG.md index 7efe163ec4..5ae50d1c40 100644 --- a/packages/fill-scenarios/CHANGELOG.md +++ b/packages/fill-scenarios/CHANGELOG.md @@ -5,7 +5,11 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.1-rc.3 - _August 13, 2018_ +## v1.0.1-rc.4 - _August 24, 2018_ + + * Dependencies updated + +## v1.0.1-rc.3 - _August 14, 2018_ * Updated to use latest orderFactory interface, fixed `feeRecipient` spelling error in public interface (#936) * Dependencies updated @@ -22,7 +26,7 @@ CHANGELOG * Dependencies updated -## v1.0.0-rc.1 - _July 19, 2018_ +## v1.0.0-rc.1 - _July 20, 2018_ * Make fill-scenarios compatible with V2 of 0x protocol (#656) diff --git a/packages/forwarder-helper/CHANGELOG.json b/packages/forwarder-helper/CHANGELOG.json index be5b244b35..b99a98b931 100644 --- a/packages/forwarder-helper/CHANGELOG.json +++ b/packages/forwarder-helper/CHANGELOG.json @@ -6,6 +6,7 @@ "note": "Add initial forwarderHelperFactory", "pr": 997 } - ] + ], + "timestamp": 1535133899 } ] diff --git a/packages/forwarder-helper/CHANGELOG.md b/packages/forwarder-helper/CHANGELOG.md new file mode 100644 index 0000000000..6d48268e6c --- /dev/null +++ b/packages/forwarder-helper/CHANGELOG.md @@ -0,0 +1,10 @@ + + +CHANGELOG + +## v1.0.1-rc.1 - _August 24, 2018_ + + * Add initial forwarderHelperFactory (#997) diff --git a/packages/json-schemas/CHANGELOG.json b/packages/json-schemas/CHANGELOG.json index f22b78c2af..b17267414f 100644 --- a/packages/json-schemas/CHANGELOG.json +++ b/packages/json-schemas/CHANGELOG.json @@ -6,7 +6,8 @@ "note": "Update incorrect relayer api fee recipients response schema", "pr": 974 } - ] + ], + "timestamp": 1535133899 }, { "version": "1.0.1-rc.4", diff --git a/packages/json-schemas/CHANGELOG.md b/packages/json-schemas/CHANGELOG.md index 0ebc3d2374..e3fa8078d1 100644 --- a/packages/json-schemas/CHANGELOG.md +++ b/packages/json-schemas/CHANGELOG.md @@ -5,7 +5,11 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.1-rc.4 - _August 13, 2018_ +## v1.0.1-rc.5 - _August 24, 2018_ + + * Update incorrect relayer api fee recipients response schema (#974) + +## v1.0.1-rc.4 - _August 14, 2018_ * Allow for additional properties in txData schema (#938) * Change hexSchema to match `0x` (#937) @@ -27,7 +31,7 @@ CHANGELOG * Dependencies updated -## v1.0.0-rc.1 - _July 19, 2018_ +## v1.0.0-rc.1 - _July 20, 2018_ * Update schemas for V2 or 0x Protocol (#615) * Added CallData schema (#821) @@ -53,7 +57,7 @@ CHANGELOG * Dependencies updated -## v0.7.23 - _May 4, 2018_ +## v0.7.23 - _May 5, 2018_ * Dependencies updated diff --git a/packages/migrations/CHANGELOG.json b/packages/migrations/CHANGELOG.json index f92bb48b43..17f185a9d2 100644 --- a/packages/migrations/CHANGELOG.json +++ b/packages/migrations/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535133899, + "version": "1.0.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1534210131, "version": "1.0.4", diff --git a/packages/migrations/CHANGELOG.md b/packages/migrations/CHANGELOG.md index 7388c6ebc9..0ebd03575f 100644 --- a/packages/migrations/CHANGELOG.md +++ b/packages/migrations/CHANGELOG.md @@ -5,7 +5,11 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.4 - _August 13, 2018_ +## v1.0.5 - _August 24, 2018_ + + * Dependencies updated + +## v1.0.4 - _August 14, 2018_ * Dependencies updated @@ -21,7 +25,7 @@ CHANGELOG * Dependencies updated -## v1.0.0 - _July 19, 2018_ +## v1.0.0 - _July 20, 2018_ * Added migrations for 0x Protocol v2 @@ -45,7 +49,7 @@ CHANGELOG * Dependencies updated -## v0.0.5 - _May 4, 2018_ +## v0.0.5 - _May 5, 2018_ * Dependencies updated diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json index 871bc50a18..81782b5015 100644 --- a/packages/order-utils/CHANGELOG.json +++ b/packages/order-utils/CHANGELOG.json @@ -39,7 +39,8 @@ "Update `findFeeOrdersThatCoverFeesForTargetOrders` to round the the nearest integer when calculating required fees", "pr": 997 } - ] + ], + "timestamp": 1535133899 }, { "version": "1.0.1-rc.3", diff --git a/packages/order-utils/CHANGELOG.md b/packages/order-utils/CHANGELOG.md index 0df2a6a757..7af51fc619 100644 --- a/packages/order-utils/CHANGELOG.md +++ b/packages/order-utils/CHANGELOG.md @@ -5,7 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.1-rc.3 - _August 13, 2018_ +## v1.0.1-rc.4 - _August 24, 2018_ + + * Remove rounding error being thrown when maker amount is very small (#959) + * Added rateUtils and sortingUtils (#953) + * Update marketUtils api such that all optional parameters are bundled into one optional param and more defaults are provided (#954) + * Instead of exporting signature util methods individually, they are now exported as `signatureUtils` (#924) + * Export types: `SignedOrder`, `Order`, `OrderRelevantState`, `OrderState`, `ECSignature`, `ERC20AssetData`, `ERC721AssetData`, `AssetProxyId`, `SignerType`, `SignatureType`, `OrderStateValid`, `OrderStateInvalid`, `ExchangeContractErrs`, `TradeSide`, `TransferType`, `FindFeeOrdersThatCoverFeesForTargetOrdersOpts`, `FindOrdersThatCoverMakerAssetFillAmountOpts`, `FeeOrdersAndRemainingFeeAmount`, `OrdersAndRemainingFillAmount`, `Provider`, `JSONRPCRequestPayload`, `JSONRPCErrorCallback` and `JSONRPCResponsePayload` (#924) + * Rename `resultOrders` to `resultFeeOrders` for object returned by `findFeeOrdersThatCoverFeesForTargetOrders` in `marketUtils` api (#997) + * Make `sortFeeOrdersByFeeAdjustedRate` in `sortingUtils` generic (#997) + * Update `findFeeOrdersThatCoverFeesForTargetOrders` to round the the nearest integer when calculating required fees (#997) + +## v1.0.1-rc.3 - _August 14, 2018_ * Update ecSignOrderHashAsync to return signature string with signature type byte. Removes messagePrefixOpts. (#914) * Added a synchronous `createOrder` method in `orderFactory`, updated public interfaces to support some optional parameters (#936) @@ -28,7 +39,7 @@ CHANGELOG * Upgrade ethereumjs-abi dep including a fix so that addresses starting with 0 are properly decoded by `decodeERC20AssetData` -## v1.0.0-rc.1 - _July 19, 2018_ +## v1.0.0-rc.1 - _July 20, 2018_ * Refactor to work with V2 of 0x protocol (#636) * Export parseECSignature method (#684) @@ -54,7 +65,7 @@ CHANGELOG * Add orderStateUtils, a module for computing order state needed to decide if an order is still valid -## v0.0.4 - _May 4, 2018_ +## v0.0.4 - _May 5, 2018_ * Dependencies updated diff --git a/packages/order-watcher/CHANGELOG.json b/packages/order-watcher/CHANGELOG.json index ee6d5540a0..fe38e21750 100644 --- a/packages/order-watcher/CHANGELOG.json +++ b/packages/order-watcher/CHANGELOG.json @@ -11,7 +11,8 @@ "note": "Remove exporting types: `BlockParamLiteral`, `BlockParam`, `Order`", "pr": 924 } - ] + ], + "timestamp": 1535133899 }, { "version": "1.0.1-rc.3", diff --git a/packages/order-watcher/CHANGELOG.md b/packages/order-watcher/CHANGELOG.md index bb92f28506..73bfd51142 100644 --- a/packages/order-watcher/CHANGELOG.md +++ b/packages/order-watcher/CHANGELOG.md @@ -5,7 +5,12 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.1-rc.3 - _August 13, 2018_ +## 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 @@ -21,7 +26,7 @@ CHANGELOG * Dependencies updated -## v1.0.0-rc.1 - _July 19, 2018_ +## v1.0.0-rc.1 - _July 20, 2018_ * Add support for ERC721 event watching and Exchange V2 events (#887) diff --git a/packages/react-docs/CHANGELOG.json b/packages/react-docs/CHANGELOG.json index 2b83b7fae1..5ca4f4d055 100644 --- a/packages/react-docs/CHANGELOG.json +++ b/packages/react-docs/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535133899, + "version": "1.0.6", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1534210131, "version": "1.0.5", diff --git a/packages/react-docs/CHANGELOG.md b/packages/react-docs/CHANGELOG.md index 38d2451dd4..09d666d75f 100644 --- a/packages/react-docs/CHANGELOG.md +++ b/packages/react-docs/CHANGELOG.md @@ -5,7 +5,11 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.5 - _August 13, 2018_ +## v1.0.6 - _August 24, 2018_ + + * Dependencies updated + +## v1.0.5 - _August 14, 2018_ * Dependencies updated @@ -25,7 +29,7 @@ CHANGELOG * Dependencies updated -## v1.0.0 - _July 19, 2018_ +## v1.0.0 - _July 20, 2018_ * Dependencies updated @@ -45,7 +49,7 @@ CHANGELOG * Dependencies updated -## v0.0.13 - _May 31, 2018_ +## v0.0.13 - _June 1, 2018_ * Incorrect publish that was unpublished @@ -53,7 +57,7 @@ CHANGELOG * Dependencies updated -## v0.0.11 - _May 4, 2018_ +## v0.0.11 - _May 5, 2018_ * Dependencies updated diff --git a/packages/react-shared/CHANGELOG.json b/packages/react-shared/CHANGELOG.json index 1268bcc7b0..01e97f9e75 100644 --- a/packages/react-shared/CHANGELOG.json +++ b/packages/react-shared/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535133899, + "version": "1.0.7", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1534210131, "version": "1.0.6", diff --git a/packages/react-shared/CHANGELOG.md b/packages/react-shared/CHANGELOG.md index cfbaf6c704..b70db245c8 100644 --- a/packages/react-shared/CHANGELOG.md +++ b/packages/react-shared/CHANGELOG.md @@ -5,7 +5,11 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.6 - _August 13, 2018_ +## v1.0.7 - _August 24, 2018_ + + * Dependencies updated + +## v1.0.6 - _August 14, 2018_ * Dependencies updated @@ -29,7 +33,7 @@ CHANGELOG * Dependencies updated -## v1.0.0 - _July 19, 2018_ +## v1.0.0 - _July 20, 2018_ * Dependencies updated @@ -45,11 +49,11 @@ CHANGELOG * Dependencies updated -## v0.2.0 - _May 4, 2018_ +## v0.2.0 - _May 5, 2018_ * Removed portal specific colors -## v0.1.6 - _May 4, 2018_ +## v0.1.6 - _May 5, 2018_ * Dependencies updated diff --git a/packages/sol-compiler/CHANGELOG.json b/packages/sol-compiler/CHANGELOG.json index a723ea12ec..b27253b012 100644 --- a/packages/sol-compiler/CHANGELOG.json +++ b/packages/sol-compiler/CHANGELOG.json @@ -15,7 +15,8 @@ "note": "Export types: `CompilerSettings`, `OutputField`", "pr": 924 } - ] + ], + "timestamp": 1535133899 }, { "timestamp": 1534210131, diff --git a/packages/sol-compiler/CHANGELOG.md b/packages/sol-compiler/CHANGELOG.md index ee9eadeaac..852015ff99 100644 --- a/packages/sol-compiler/CHANGELOG.md +++ b/packages/sol-compiler/CHANGELOG.md @@ -5,7 +5,13 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.5 - _August 13, 2018_ +## v1.1.0 - _August 24, 2018_ + + * Quicken compilation by sending multiple contracts to the same solcjs invocation, batching them together based on compiler version requirements. (#965) + * Stop exporting types: `ContractArtifact`, `ContractNetworks` (#924) + * Export types: `CompilerSettings`, `OutputField` (#924) + +## v1.0.5 - _August 14, 2018_ * Dependencies updated @@ -25,7 +31,7 @@ CHANGELOG * Dependencies updated -## v1.0.0 - _July 19, 2018_ +## v1.0.0 - _July 20, 2018_ * Dependencies updated @@ -51,7 +57,7 @@ CHANGELOG * Properly export the executable binary (#588) * Add the ability to define a specific solidity version (#589) -## v0.4.3 - _May 4, 2018_ +## v0.4.3 - _May 5, 2018_ * Dependencies updated diff --git a/packages/sol-cov/CHANGELOG.json b/packages/sol-cov/CHANGELOG.json index 166bd9255f..597ba4875b 100644 --- a/packages/sol-cov/CHANGELOG.json +++ b/packages/sol-cov/CHANGELOG.json @@ -7,7 +7,8 @@ "Export types: `JSONRPCRequestPayload`, `Provider`, `JSONRPCErrorCallback`, `JSONRPCResponsePayload`, `JSONRPCRequestPayloadWithMethod`, `NextCallback`, `ErrorCallback`, `OnNextCompleted` and `Callback`", "pr": 924 } - ] + ], + "timestamp": 1535133899 }, { "version": "2.0.0", diff --git a/packages/sol-cov/CHANGELOG.md b/packages/sol-cov/CHANGELOG.md index d7bdb96144..819b58c958 100644 --- a/packages/sol-cov/CHANGELOG.md +++ b/packages/sol-cov/CHANGELOG.md @@ -5,7 +5,11 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v2.0.0 - _August 13, 2018_ +## v2.1.0 - _August 24, 2018_ + + * Export types: `JSONRPCRequestPayload`, `Provider`, `JSONRPCErrorCallback`, `JSONRPCResponsePayload`, `JSONRPCRequestPayloadWithMethod`, `NextCallback`, `ErrorCallback`, `OnNextCompleted` and `Callback` (#924) + +## v2.0.0 - _August 14, 2018_ * Fix a bug when eth_call coverage was not computed because of silent schema validation failures (#938) * Make `TruffleArtifactAdapter` read the `truffle.js` config for `solc` settings (#938) @@ -24,7 +28,7 @@ CHANGELOG * Dependencies updated -## v1.0.0 - _July 19, 2018_ +## v1.0.0 - _July 20, 2018_ * Add artifact adapter as a parameter for `CoverageSubprovider`. Export `AbstractArtifactAdapter` (#589) * Implement `SolCompilerArtifactAdapter` and `TruffleArtifactAdapter` (#589) @@ -57,7 +61,7 @@ CHANGELOG * Dependencies updated -## v0.1.0 - _May 31, 2018_ +## v0.1.0 - _June 1, 2018_ * Incorrect publish that was unpublished @@ -65,7 +69,7 @@ CHANGELOG * Dependencies updated -## v0.0.10 - _May 4, 2018_ +## v0.0.10 - _May 5, 2018_ * Dependencies updated diff --git a/packages/sol-resolver/CHANGELOG.json b/packages/sol-resolver/CHANGELOG.json index 42d4c7ed1d..cd1dcbe018 100644 --- a/packages/sol-resolver/CHANGELOG.json +++ b/packages/sol-resolver/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535133899, + "version": "1.0.6", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "1.0.5", "changes": [ diff --git a/packages/sol-resolver/CHANGELOG.md b/packages/sol-resolver/CHANGELOG.md index 1427ec3fe5..64ae2d6735 100644 --- a/packages/sol-resolver/CHANGELOG.md +++ b/packages/sol-resolver/CHANGELOG.md @@ -5,7 +5,11 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.5 - _August 13, 2018_ +## v1.0.6 - _August 24, 2018_ + + * Dependencies updated + +## v1.0.5 - _August 14, 2018_ * Fix a bug where RelativeFSResolver would crash when trying to read a directory (#909) * Fix a bug where NpmResolver would crash when trying to read a directory (#961) @@ -26,7 +30,7 @@ CHANGELOG * Dependencies updated -## v1.0.0 - _July 19, 2018_ +## v1.0.0 - _July 20, 2018_ * Fix a bug in FsResolver where it tries to read directories as files (#589) * Fix a bug in NameResolver where it is not ignoring .sol files (#589) @@ -39,7 +43,7 @@ CHANGELOG * Dependencies updated -## v0.0.6 - _May 31, 2018_ +## v0.0.6 - _June 1, 2018_ * Incorrect publish that was unpublished @@ -47,7 +51,7 @@ CHANGELOG * Dependencies updated -## v0.0.4 - _May 4, 2018_ +## v0.0.4 - _May 5, 2018_ * Dependencies updated diff --git a/packages/sra-api/CHANGELOG.json b/packages/sra-api/CHANGELOG.json index d6797cc452..8467f3c681 100644 --- a/packages/sra-api/CHANGELOG.json +++ b/packages/sra-api/CHANGELOG.json @@ -6,7 +6,8 @@ "note": "Add takerAddress to /orders parameters", "pr": 974 } - ] + ], + "timestamp": 1535133899 }, { "version": "1.0.1-rc.4", diff --git a/packages/sra-api/CHANGELOG.md b/packages/sra-api/CHANGELOG.md index ed0d4891bb..1a88b0ce18 100644 --- a/packages/sra-api/CHANGELOG.md +++ b/packages/sra-api/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.1-rc.4 - _August 13, 2018_ +## v1.0.1-rc.5 - _August 24, 2018_ + + * Add takerAddress to /orders parameters (#974) + +## v1.0.1-rc.4 - _August 14, 2018_ * Add inital spec for SRA v2 (#916) diff --git a/packages/sra-report/CHANGELOG.json b/packages/sra-report/CHANGELOG.json index 9711d3935b..eecb81312c 100644 --- a/packages/sra-report/CHANGELOG.json +++ b/packages/sra-report/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535133899, + "version": "1.0.6", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1534210131, "version": "1.0.5", diff --git a/packages/sra-report/CHANGELOG.md b/packages/sra-report/CHANGELOG.md index 4102219510..3ff6a73aea 100644 --- a/packages/sra-report/CHANGELOG.md +++ b/packages/sra-report/CHANGELOG.md @@ -5,7 +5,11 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.5 - _August 13, 2018_ +## v1.0.6 - _August 24, 2018_ + + * Dependencies updated + +## v1.0.5 - _August 14, 2018_ * Dependencies updated @@ -25,7 +29,7 @@ CHANGELOG * Dependencies updated -## v1.0.0 - _July 19, 2018_ +## v1.0.0 - _July 20, 2018_ * Dependencies updated @@ -57,7 +61,7 @@ CHANGELOG * Properly export the executable binary (#588) -## v0.0.14 - _May 4, 2018_ +## v0.0.14 - _May 5, 2018_ * Dependencies updated diff --git a/packages/subproviders/CHANGELOG.json b/packages/subproviders/CHANGELOG.json index bdda74c279..e11f663e61 100644 --- a/packages/subproviders/CHANGELOG.json +++ b/packages/subproviders/CHANGELOG.json @@ -7,7 +7,8 @@ "Export types: `PartialTxParams`, `JSONRPCRequestPayloadWithMethod`, `ECSignatureString`, `AccountFetchingConfigs`, `LedgerEthereumClientFactoryAsync`, `OnNextCompleted`, `MnemonicWalletSubproviderConfigs`, LedgerGetAddressResult, `JSONRPCRequestPayload`, `Provider`, `JSONRPCResponsePayload` and `JSONRPCErrorCallback`", "pr": 924 } - ] + ], + "timestamp": 1535133899 }, { "timestamp": 1534210131, diff --git a/packages/subproviders/CHANGELOG.md b/packages/subproviders/CHANGELOG.md index 152c0027e6..444d1997a8 100644 --- a/packages/subproviders/CHANGELOG.md +++ b/packages/subproviders/CHANGELOG.md @@ -5,7 +5,11 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.5 - _August 13, 2018_ +## v2.0.0 - _August 24, 2018_ + + * Export types: `PartialTxParams`, `JSONRPCRequestPayloadWithMethod`, `ECSignatureString`, `AccountFetchingConfigs`, `LedgerEthereumClientFactoryAsync`, `OnNextCompleted`, `MnemonicWalletSubproviderConfigs`, LedgerGetAddressResult, `JSONRPCRequestPayload`, `Provider`, `JSONRPCResponsePayload` and `JSONRPCErrorCallback` (#924) + +## v1.0.5 - _August 14, 2018_ * Dependencies updated @@ -25,7 +29,7 @@ CHANGELOG * Dependencies updated -## v1.0.0 - _July 19, 2018_ +## v1.0.0 - _July 20, 2018_ * Add `RpcSubprovider` with timeout (#874) * Add `EthLightwalletSubprovider` (#775) @@ -46,7 +50,7 @@ CHANGELOG * Dependencies updated -## v0.10.1 - _May 4, 2018_ +## v0.10.1 - _May 5, 2018_ * Dependencies updated diff --git a/packages/tslint-config/CHANGELOG.json b/packages/tslint-config/CHANGELOG.json index 8bad8526a4..b70285f05e 100644 --- a/packages/tslint-config/CHANGELOG.json +++ b/packages/tslint-config/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535133899, + "version": "1.0.6", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1534210131, "version": "1.0.5", diff --git a/packages/tslint-config/CHANGELOG.md b/packages/tslint-config/CHANGELOG.md index 136441971e..5474a08bef 100644 --- a/packages/tslint-config/CHANGELOG.md +++ b/packages/tslint-config/CHANGELOG.md @@ -5,7 +5,11 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.5 - _August 13, 2018_ +## v1.0.6 - _August 24, 2018_ + + * Dependencies updated + +## v1.0.5 - _August 14, 2018_ * Dependencies updated @@ -25,7 +29,7 @@ CHANGELOG * Dependencies updated -## v1.0.0 - _July 19, 2018_ +## v1.0.0 - _July 20, 2018_ * Added a bunch of rules (#883) @@ -37,7 +41,7 @@ CHANGELOG * Dependencies updated -## v0.4.19 - _May 31, 2018_ +## v0.4.19 - _June 1, 2018_ * Incorrect publish that was unpublished diff --git a/packages/types/CHANGELOG.json b/packages/types/CHANGELOG.json index b99a8bc358..fabc80ecfc 100644 --- a/packages/types/CHANGELOG.json +++ b/packages/types/CHANGELOG.json @@ -6,7 +6,8 @@ "note": "Add revert reasons for ERC721Token", "pr": 933 } - ] + ], + "timestamp": 1535133899 }, { "version": "1.0.1-rc.4", diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index 9be0c8bca9..3bd1d375fe 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -5,7 +5,11 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.1-rc.4 - _August 13, 2018_ +## v1.0.1-rc.5 - _August 24, 2018_ + + * Add revert reasons for ERC721Token (#933) + +## v1.0.1-rc.4 - _August 14, 2018_ * Added SignerType to handle different signing prefix scenarios (#914) @@ -25,7 +29,7 @@ CHANGELOG * Dependencies updated -## v1.0.0-rc.1 - _July 19, 2018_ +## v1.0.0-rc.1 - _July 20, 2018_ * Updated types for V2 of 0x protocol * Add `ECSignatureBuffer` @@ -48,7 +52,7 @@ CHANGELOG * Make OpCode type an enum (#589) * Moved ExchangeContractErrs, DoneCallback, Token, OrderRelevantState, OrderStateValid, OrderStateInvalid, OrderState, OrderAddresses and OrderValues types from 0x.js (#579) -## v0.6.3 - _May 4, 2018_ +## v0.6.3 - _May 5, 2018_ * Dependencies updated diff --git a/packages/typescript-typings/CHANGELOG.json b/packages/typescript-typings/CHANGELOG.json index 566d9f24c6..8e6b2b3c80 100644 --- a/packages/typescript-typings/CHANGELOG.json +++ b/packages/typescript-typings/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535133899, + "version": "1.0.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1534210131, "version": "1.0.4", diff --git a/packages/typescript-typings/CHANGELOG.md b/packages/typescript-typings/CHANGELOG.md index 70e6574b28..b3a3f3e38b 100644 --- a/packages/typescript-typings/CHANGELOG.md +++ b/packages/typescript-typings/CHANGELOG.md @@ -5,7 +5,11 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.4 - _August 13, 2018_ +## v1.0.5 - _August 24, 2018_ + + * Dependencies updated + +## v1.0.4 - _August 14, 2018_ * Dependencies updated @@ -21,7 +25,7 @@ CHANGELOG * Dependencies updated -## v1.0.0 - _July 19, 2018_ +## v1.0.0 - _July 20, 2018_ * Add types for `eth-lightwallet` (#775) * Improve 'web3-provider-engine' typings (#768) @@ -46,7 +50,7 @@ CHANGELOG * Dependencies updated -## v0.3.1 - _May 4, 2018_ +## v0.3.1 - _May 5, 2018_ * Dependencies updated diff --git a/packages/utils/CHANGELOG.json b/packages/utils/CHANGELOG.json index 796a99a5a0..6edafb946f 100644 --- a/packages/utils/CHANGELOG.json +++ b/packages/utils/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535133899, + "version": "1.0.6", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "1.0.5", "changes": [ diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md index bdde2687d3..a2d4d115b2 100644 --- a/packages/utils/CHANGELOG.md +++ b/packages/utils/CHANGELOG.md @@ -5,9 +5,14 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.0.5 - _August 13, 2018_ +## v1.0.6 - _August 24, 2018_ + + * Dependencies updated + +## v1.0.5 - _August 14, 2018_ * Increased BigNumber decimal precision from 20 to 78 (#807) + * Store different ABIs for events with same function signature and different amount of indexed arguments (#933) ## v1.0.4 - _July 26, 2018_ @@ -25,7 +30,7 @@ CHANGELOG * Add `AbortController` polyfill to `fetchAsync` (#903) -## v1.0.0 - _July 19, 2018_ +## v1.0.0 - _July 20, 2018_ * Add `fetchAsync` which adds a default timeout to all requests (#874) @@ -43,7 +48,7 @@ CHANGELOG * Dependencies updated -## v0.7.0 - _May 31, 2018_ +## v0.7.0 - _June 1, 2018_ * Incorrect publish that was unpublished @@ -51,7 +56,7 @@ CHANGELOG * Dependencies updated -## v0.6.1 - _May 4, 2018_ +## v0.6.1 - _May 5, 2018_ * Dependencies updated diff --git a/packages/web3-wrapper/CHANGELOG.json b/packages/web3-wrapper/CHANGELOG.json index b9cde2f956..e2bbcaeb8e 100644 --- a/packages/web3-wrapper/CHANGELOG.json +++ b/packages/web3-wrapper/CHANGELOG.json @@ -15,7 +15,8 @@ "note": "Export `AbiDecoder` class", "pr": 924 } - ] + ], + "timestamp": 1535133899 }, { "version": "1.2.0", diff --git a/packages/web3-wrapper/CHANGELOG.md b/packages/web3-wrapper/CHANGELOG.md index 0955993f46..3bfe07d3bd 100644 --- a/packages/web3-wrapper/CHANGELOG.md +++ b/packages/web3-wrapper/CHANGELOG.md @@ -5,7 +5,13 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v1.2.0 - _August 13, 2018_ +## v2.0.0 - _August 24, 2018_ + + * Export types: `BlockParam`, `TxData`, `Provider`, `TransactionReceipt`, `Transaction`, `TraceParams`, `TransactionTrace``, BlockWithoutTransactionDat`a, `LogEntry`, `FilterObject`, `CallData`, `TransactionReceiptWithDecodedLogs`, `BlockWithTransactionData``, LogTopi`c, `JSONRPCRequestPayload`, `TransactionReceiptStatus`, `DecodedLogArgs`, `StructLog`, `JSONRPCErrorCallback``, BlockParamLitera`l, `ContractEventArg`, `DecodedLogEntry`, `LogEntryEvent`, `OpCode`, `TxDataPayable`, `JSONRPCResponsePayload``, RawLogEntr`y, `DecodedLogEntryEvent`, `LogWithDecodedArgs`, `AbiDefinition`, `RawLog`, `FunctionAbi`, `EventAbi`, `EventParameter``, MethodAb`i, `ConstructorAbi`, `FallbackAbi`, `DataItem`, `ConstructorStateMutability` and `StateMutability` (#924) + * Stop exporting types: `CallTxDataBaseRPC` and `AbstractBlockRPC` (#924) + * Export `AbiDecoder` class (#924) + +## v1.2.0 - _August 14, 2018_ * Export marshaller to convert between RPC and user-space data formats (#938) * Export RPC types (#938) @@ -26,7 +32,7 @@ CHANGELOG * Dependencies updated -## v1.0.0 - _July 19, 2018_ +## v1.0.0 - _July 20, 2018_ * Stop exporting `marshaller` utility file. (#902) * Export `marshaller` utility file. (#829) @@ -45,7 +51,7 @@ CHANGELOG * Dependencies updated -## v0.7.0 - _June 3, 2018_ +## v0.7.0 - _June 4, 2018_ * Add `web3Wrapper.getContractCodeAsync` (#675) * Add `web3Wrapper.getTransactionTraceAsync` (#675) @@ -60,7 +66,7 @@ CHANGELOG * Dependencies updated -## v0.6.3 - _May 4, 2018_ +## v0.6.3 - _May 5, 2018_ * Dependencies updated From 7f585a15f526e0a61fd822cdefb7087fc6bb8934 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Fri, 24 Aug 2018 19:11:27 +0100 Subject: [PATCH 013/120] Publish - 0x.js@1.0.1-rc.4 - @0xproject/abi-gen@1.0.6 - @0xproject/assert@1.0.6 - @0xproject/base-contract@2.0.0 - @0xproject/connect@2.0.0-rc.1 - @0xproject/contract-wrappers@1.0.1-rc.4 - contracts@2.1.41 - @0xproject/dev-utils@1.0.5 - ethereum-types@1.0.5 - @0xproject/fill-scenarios@1.0.1-rc.4 - @0xproject/forwarder-helper@1.0.1-rc.1 - @0xproject/json-schemas@1.0.1-rc.5 - @0xproject/metacoin@0.0.16 - @0xproject/migrations@1.0.5 - @0xproject/monorepo-scripts@1.0.6 - @0xproject/order-utils@1.0.1-rc.4 - @0xproject/order-watcher@1.0.1-rc.4 - @0xproject/react-docs@1.0.6 - @0xproject/react-shared@1.0.7 - @0xproject/sol-compiler@1.1.0 - @0xproject/sol-cov@2.1.0 - @0xproject/sol-resolver@1.0.6 - @0xproject/sra-api@1.0.1-rc.5 - @0xproject/sra-report@1.0.6 - @0xproject/subproviders@2.0.0 - @0xproject/testnet-faucets@1.0.42 - @0xproject/tslint-config@1.0.6 - @0xproject/types@1.0.1-rc.5 - @0xproject/typescript-typings@1.0.5 - @0xproject/utils@1.0.6 - @0xproject/web3-wrapper@2.0.0 - @0xproject/website@0.0.45 --- packages/0x.js/package.json | 34 ++++++++++---------- packages/abi-gen/package.json | 10 +++--- packages/assert/package.json | 10 +++--- packages/base-contract/package.json | 12 +++---- packages/connect/package.json | 14 ++++----- packages/contract-wrappers/package.json | 32 +++++++++---------- packages/contracts/package.json | 40 +++++++++++------------- packages/dev-utils/package.json | 16 +++++----- packages/ethereum-types/package.json | 4 +-- packages/fill-scenarios/package.json | 20 ++++++------ packages/forwarder-helper/package.json | 22 ++++++------- packages/json-schemas/package.json | 12 ++++--- packages/metacoin/package.json | 26 +++++++-------- packages/migrations/package.json | 26 +++++++-------- packages/monorepo-scripts/package.json | 2 +- packages/order-utils/package.json | 22 ++++++------- packages/order-watcher/package.json | 32 +++++++++---------- packages/react-docs/package.json | 10 +++--- packages/react-shared/package.json | 6 ++-- packages/sol-compiler/package.json | 22 ++++++------- packages/sol-cov/package.json | 23 ++++++++------ packages/sol-resolver/package.json | 8 ++--- packages/sra-api/package.json | 6 ++-- packages/sra-report/package.json | 10 +++--- packages/subproviders/package.json | 16 +++++----- packages/testnet-faucets/package.json | 14 ++++----- packages/tslint-config/package.json | 2 +- packages/types/package.json | 6 ++-- packages/typescript-typings/package.json | 4 +-- packages/utils/package.json | 10 +++--- packages/web3-wrapper/package.json | 14 ++++----- packages/website/package.json | 10 +++--- 32 files changed, 247 insertions(+), 248 deletions(-) diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json index bb0799f4b3..b5cb6c7e46 100644 --- a/packages/0x.js/package.json +++ b/packages/0x.js/package.json @@ -1,6 +1,6 @@ { "name": "0x.js", - "version": "1.0.1-rc.3", + "version": "1.0.1-rc.4", "engines": { "node": ">=6.12" }, @@ -42,11 +42,11 @@ }, "license": "Apache-2.0", "devDependencies": { - "@0xproject/abi-gen": "^1.0.5", - "@0xproject/dev-utils": "^1.0.4", - "@0xproject/migrations": "^1.0.4", - "@0xproject/monorepo-scripts": "^1.0.5", - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/abi-gen": "^1.0.6", + "@0xproject/dev-utils": "^1.0.5", + "@0xproject/migrations": "^1.0.5", + "@0xproject/monorepo-scripts": "^1.0.6", + "@0xproject/tslint-config": "^1.0.6", "@types/lodash": "4.14.104", "@types/mocha": "^2.2.42", "@types/node": "^8.0.53", @@ -73,17 +73,17 @@ "webpack": "^3.1.0" }, "dependencies": { - "@0xproject/assert": "^1.0.5", - "@0xproject/base-contract": "^2.0.0-rc.1", - "@0xproject/contract-wrappers": "^1.0.1-rc.3", - "@0xproject/order-utils": "^1.0.1-rc.3", - "@0xproject/order-watcher": "1.0.1-rc.3", - "@0xproject/subproviders": "^1.0.5", - "@0xproject/types": "^1.0.1-rc.4", - "@0xproject/typescript-typings": "^1.0.4", - "@0xproject/utils": "^1.0.5", - "@0xproject/web3-wrapper": "^1.2.0", - "ethereum-types": "^1.0.4", + "@0xproject/assert": "^1.0.6", + "@0xproject/base-contract": "^2.0.0", + "@0xproject/contract-wrappers": "^1.0.1-rc.4", + "@0xproject/order-utils": "^1.0.1-rc.4", + "@0xproject/order-watcher": "^1.0.1-rc.4", + "@0xproject/subproviders": "^2.0.0", + "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/typescript-typings": "^1.0.5", + "@0xproject/utils": "^1.0.6", + "@0xproject/web3-wrapper": "^2.0.0", + "ethereum-types": "^1.0.5", "ethers": "3.0.22", "lodash": "^4.17.5", "web3-provider-engine": "14.0.6" diff --git a/packages/abi-gen/package.json b/packages/abi-gen/package.json index 5d5fc146d0..61a35ef09f 100644 --- a/packages/abi-gen/package.json +++ b/packages/abi-gen/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/abi-gen", - "version": "1.0.5", + "version": "1.0.6", "engines": { "node": ">=6.12" }, @@ -31,10 +31,10 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen/README.md", "dependencies": { - "@0xproject/typescript-typings": "^1.0.4", - "@0xproject/utils": "^1.0.5", + "@0xproject/typescript-typings": "^1.0.5", + "@0xproject/utils": "^1.0.6", "chalk": "^2.3.0", - "ethereum-types": "^1.0.4", + "ethereum-types": "^1.0.5", "glob": "^7.1.2", "handlebars": "^4.0.11", "lodash": "^4.17.5", @@ -45,7 +45,7 @@ "yargs": "^10.0.3" }, "devDependencies": { - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", "@types/glob": "5.0.35", "@types/handlebars": "^4.0.36", "@types/mkdirp": "^0.5.1", diff --git a/packages/assert/package.json b/packages/assert/package.json index 43e9380ec1..c67a19013d 100644 --- a/packages/assert/package.json +++ b/packages/assert/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/assert", - "version": "1.0.5", + "version": "1.0.6", "engines": { "node": ">=6.12" }, @@ -29,7 +29,7 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/assert/README.md", "devDependencies": { - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", "@types/lodash": "4.14.104", "@types/mocha": "^2.2.42", "@types/valid-url": "^1.0.2", @@ -45,9 +45,9 @@ "typescript": "3.0.1" }, "dependencies": { - "@0xproject/json-schemas": "^1.0.1-rc.4", - "@0xproject/typescript-typings": "^1.0.4", - "@0xproject/utils": "^1.0.5", + "@0xproject/json-schemas": "^1.0.1-rc.5", + "@0xproject/typescript-typings": "^1.0.5", + "@0xproject/utils": "^1.0.6", "lodash": "^4.17.5", "valid-url": "^1.0.9" }, diff --git a/packages/base-contract/package.json b/packages/base-contract/package.json index df4b76e88f..221222928c 100644 --- a/packages/base-contract/package.json +++ b/packages/base-contract/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/base-contract", - "version": "2.0.0-rc.1", + "version": "2.0.0", "engines": { "node": ">=6.12" }, @@ -29,7 +29,7 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/base-contract/README.md", "devDependencies": { - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", "@types/lodash": "4.14.104", "chai": "^4.0.1", "copyfiles": "^2.0.0", @@ -41,10 +41,10 @@ "typescript": "3.0.1" }, "dependencies": { - "@0xproject/typescript-typings": "^1.0.4", - "@0xproject/utils": "^1.0.5", - "@0xproject/web3-wrapper": "^1.2.0", - "ethereum-types": "^1.0.4", + "@0xproject/typescript-typings": "^1.0.5", + "@0xproject/utils": "^1.0.6", + "@0xproject/web3-wrapper": "^2.0.0", + "ethereum-types": "^1.0.5", "ethers": "3.0.22", "lodash": "^4.17.5" }, diff --git a/packages/connect/package.json b/packages/connect/package.json index f5772cf4d2..116db04699 100644 --- a/packages/connect/package.json +++ b/packages/connect/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/connect", - "version": "1.0.5", + "version": "2.0.0-rc.1", "engines": { "node": ">=6.12" }, @@ -44,11 +44,11 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/connect/README.md", "dependencies": { - "@0xproject/assert": "^1.0.5", - "@0xproject/json-schemas": "^1.0.1-rc.4", - "@0xproject/types": "^1.0.1-rc.4", - "@0xproject/typescript-typings": "^1.0.4", - "@0xproject/utils": "^1.0.5", + "@0xproject/assert": "^1.0.6", + "@0xproject/json-schemas": "^1.0.1-rc.5", + "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/typescript-typings": "^1.0.5", + "@0xproject/utils": "^1.0.6", "lodash": "^4.17.5", "query-string": "^5.0.1", "sinon": "^4.0.0", @@ -56,7 +56,7 @@ "websocket": "^1.0.25" }, "devDependencies": { - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", "@types/fetch-mock": "^6.0.3", "@types/lodash": "4.14.104", "@types/mocha": "^2.2.42", diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json index 67cca9ec0b..63fe6a5e5c 100644 --- a/packages/contract-wrappers/package.json +++ b/packages/contract-wrappers/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/contract-wrappers", - "version": "1.0.1-rc.3", + "version": "1.0.1-rc.4", "description": "Smart TS wrappers for 0x smart contracts", "keywords": [ "0xproject", @@ -44,11 +44,11 @@ "node": ">=6.0.0" }, "devDependencies": { - "@0xproject/abi-gen": "^1.0.5", - "@0xproject/dev-utils": "^1.0.4", - "@0xproject/migrations": "^1.0.4", - "@0xproject/subproviders": "^1.0.5", - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/abi-gen": "^1.0.6", + "@0xproject/dev-utils": "^1.0.5", + "@0xproject/migrations": "^1.0.5", + "@0xproject/subproviders": "^2.0.0", + "@0xproject/tslint-config": "^1.0.6", "@types/lodash": "4.14.104", "@types/mocha": "^2.2.42", "@types/node": "^8.0.53", @@ -74,16 +74,16 @@ "web3-provider-engine": "14.0.6" }, "dependencies": { - "@0xproject/assert": "^1.0.5", - "@0xproject/base-contract": "^2.0.0-rc.1", - "@0xproject/fill-scenarios": "^1.0.1-rc.3", - "@0xproject/json-schemas": "^1.0.1-rc.4", - "@0xproject/order-utils": "^1.0.1-rc.3", - "@0xproject/types": "^1.0.1-rc.4", - "@0xproject/typescript-typings": "^1.0.4", - "@0xproject/utils": "^1.0.5", - "@0xproject/web3-wrapper": "^1.2.0", - "ethereum-types": "^1.0.4", + "@0xproject/assert": "^1.0.6", + "@0xproject/base-contract": "^2.0.0", + "@0xproject/fill-scenarios": "^1.0.1-rc.4", + "@0xproject/json-schemas": "^1.0.1-rc.5", + "@0xproject/order-utils": "^1.0.1-rc.4", + "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/typescript-typings": "^1.0.5", + "@0xproject/utils": "^1.0.6", + "@0xproject/web3-wrapper": "^2.0.0", + "ethereum-types": "^1.0.5", "ethereumjs-blockstream": "5.0.0", "ethereumjs-util": "^5.1.1", "ethers": "3.0.22", diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 8421c31045..10ab09767b 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "contracts", - "version": "2.1.40", + "version": "2.1.41", "engines": { "node": ">=6.12" }, @@ -20,14 +20,11 @@ "test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov", "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html", "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha", - "run_mocha": - "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit", + "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit", "compile": "sol-compiler --contracts-dir src", "clean": "shx rm -rf lib generated_contract_wrappers", - "generate_contract_wrappers": - "abi-gen --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output generated_contract_wrappers --backend ethers", - "lint": - "tslint --project . --exclude **/src/generated_contract_wrappers/**/* --exclude **/lib/**/* && yarn lint-contracts", + "generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output generated_contract_wrappers --backend ethers", + "lint": "tslint --project . --exclude **/src/generated_contract_wrappers/**/* --exclude **/lib/**/* && yarn lint-contracts", "coverage:report:text": "istanbul report text", "coverage:report:html": "istanbul report html && open coverage/index.html", "profiler:report:html": "istanbul report html && open coverage/index.html", @@ -36,8 +33,7 @@ "lint-contracts": "solhint src/2.0.0/**/**/**/**/*.sol" }, "config": { - "abis": - "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|DummyNoReturnERC20Token|ERC20Proxy|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|InvalidERC721Receiver|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|OrderValidator|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestExchangeInternals|TestLibBytes|TestLibs|TestSignatureValidator|Validator|Wallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json" + "abis": "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|DummyNoReturnERC20Token|ERC20Proxy|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|InvalidERC721Receiver|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|OrderValidator|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestExchangeInternals|TestLibBytes|TestLibs|TestSignatureValidator|Validator|Wallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json" }, "repository": { "type": "git", @@ -50,12 +46,12 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/contracts/README.md", "devDependencies": { - "@0xproject/abi-gen": "^1.0.5", - "@0xproject/dev-utils": "^1.0.4", - "@0xproject/sol-cov": "^2.0.0", - "@0xproject/subproviders": "^1.0.5", - "@0xproject/tslint-config": "^1.0.5", - "@0xproject/sol-compiler": "^1.0.5", + "@0xproject/abi-gen": "^1.0.6", + "@0xproject/dev-utils": "^1.0.5", + "@0xproject/sol-compiler": "^1.1.0", + "@0xproject/sol-cov": "^2.1.0", + "@0xproject/subproviders": "^2.0.0", + "@0xproject/tslint-config": "^1.0.6", "@types/bn.js": "^4.11.0", "@types/ethereumjs-abi": "^0.6.0", "@types/lodash": "4.14.104", @@ -77,15 +73,15 @@ "yargs": "^10.0.3" }, "dependencies": { - "@0xproject/base-contract": "^2.0.0-rc.1", - "@0xproject/order-utils": "^1.0.1-rc.3", - "@0xproject/types": "^1.0.1-rc.4", - "@0xproject/typescript-typings": "^1.0.4", - "@0xproject/utils": "^1.0.5", - "@0xproject/web3-wrapper": "^1.2.0", + "@0xproject/base-contract": "^2.0.0", + "@0xproject/order-utils": "^1.0.1-rc.4", + "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/typescript-typings": "^1.0.5", + "@0xproject/utils": "^1.0.6", + "@0xproject/web3-wrapper": "^2.0.0", "@types/js-combinatorics": "^0.5.29", "bn.js": "^4.11.8", - "ethereum-types": "^1.0.4", + "ethereum-types": "^1.0.5", "ethereumjs-abi": "0.6.5", "ethereumjs-util": "^5.1.1", "ethers": "3.0.22", diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 6bdf3a37d9..a131613207 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/dev-utils", - "version": "1.0.4", + "version": "1.0.5", "engines": { "node": ">=6.12" }, @@ -29,7 +29,7 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/dev-utils/README.md", "devDependencies": { - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", "@types/lodash": "4.14.104", "@types/mocha": "^2.2.42", "chai": "^4.0.1", @@ -43,12 +43,12 @@ "typescript": "3.0.1" }, "dependencies": { - "@0xproject/subproviders": "^1.0.5", - "@0xproject/types": "^1.0.1-rc.4", - "@0xproject/typescript-typings": "^1.0.4", - "@0xproject/utils": "^1.0.5", - "@0xproject/web3-wrapper": "^1.2.0", - "ethereum-types": "^1.0.4", + "@0xproject/subproviders": "^2.0.0", + "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/typescript-typings": "^1.0.5", + "@0xproject/utils": "^1.0.6", + "@0xproject/web3-wrapper": "^2.0.0", + "ethereum-types": "^1.0.5", "lodash": "^4.17.5" }, "publishConfig": { diff --git a/packages/ethereum-types/package.json b/packages/ethereum-types/package.json index 73325da4b5..9e4d287a40 100644 --- a/packages/ethereum-types/package.json +++ b/packages/ethereum-types/package.json @@ -1,6 +1,6 @@ { "name": "ethereum-types", - "version": "1.0.4", + "version": "1.0.5", "engines": { "node": ">=6.12" }, @@ -29,7 +29,7 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/ethereum-types/README.md", "devDependencies": { - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", "copyfiles": "^2.0.0", "make-promises-safe": "^1.1.0", "shx": "^0.2.2", diff --git a/packages/fill-scenarios/package.json b/packages/fill-scenarios/package.json index d156829116..74a95fa43d 100644 --- a/packages/fill-scenarios/package.json +++ b/packages/fill-scenarios/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/fill-scenarios", - "version": "1.0.1-rc.3", + "version": "1.0.1-rc.4", "description": "0x order fill scenario generator", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -27,8 +27,8 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/fill-scenarios/README.md", "devDependencies": { - "@0xproject/abi-gen": "^1.0.5", - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/abi-gen": "^1.0.6", + "@0xproject/tslint-config": "^1.0.6", "@types/lodash": "4.14.104", "copyfiles": "^2.0.0", "make-promises-safe": "^1.1.0", @@ -38,13 +38,13 @@ "typescript": "3.0.1" }, "dependencies": { - "@0xproject/base-contract": "^2.0.0-rc.1", - "@0xproject/order-utils": "^1.0.1-rc.3", - "@0xproject/types": "^1.0.1-rc.4", - "@0xproject/typescript-typings": "^1.0.4", - "@0xproject/utils": "^1.0.5", - "@0xproject/web3-wrapper": "^1.2.0", - "ethereum-types": "^1.0.4", + "@0xproject/base-contract": "^2.0.0", + "@0xproject/order-utils": "^1.0.1-rc.4", + "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/typescript-typings": "^1.0.5", + "@0xproject/utils": "^1.0.6", + "@0xproject/web3-wrapper": "^2.0.0", + "ethereum-types": "^1.0.5", "ethers": "3.0.22", "lodash": "^4.17.5" }, diff --git a/packages/forwarder-helper/package.json b/packages/forwarder-helper/package.json index fcb4838858..b030413044 100644 --- a/packages/forwarder-helper/package.json +++ b/packages/forwarder-helper/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/forwarder-helper", - "version": "1.0.0-rc.1", + "version": "1.0.1-rc.1", "engines": { "node": ">=6.12" }, @@ -15,15 +15,13 @@ "test:coverage": "nyc npm run test --all && yarn coverage:report:lcov", "coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info", "test:circleci": "yarn test:coverage", - "run_mocha": - "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js --exit", + "run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js --exit", "clean": "shx rm -rf lib test_temp scripts", "build": "tsc && copyfiles -u 3 './lib/src/monorepo_scripts/**/*' ./scripts", "manual:postpublish": "yarn build; node ./scripts/postpublish.js", "docs:stage": "node scripts/stage_docs.js", "docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --json $JSON_FILE_PATH $PROJECT_FILES", - "upload_docs_json": - "aws s3 cp generated_docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type application/json" + "upload_docs_json": "aws s3 cp generated_docs/index.json $S3_URL --profile 0xproject --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --content-type application/json" }, "config": { "postpublish": { @@ -41,17 +39,17 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/forwarder-helper/README.md", "dependencies": { - "@0xproject/assert": "^1.0.5", - "@0xproject/json-schemas": "^1.0.1-rc.4", - "@0xproject/order-utils": "^1.0.1-rc.3", - "@0xproject/types": "^1.0.1-rc.4", - "@0xproject/typescript-typings": "^1.0.4", - "@0xproject/utils": "^1.0.5", + "@0xproject/assert": "^1.0.6", + "@0xproject/json-schemas": "^1.0.1-rc.5", + "@0xproject/order-utils": "^1.0.1-rc.4", + "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/typescript-typings": "^1.0.5", + "@0xproject/utils": "^1.0.6", "@types/node": "^8.0.53", "lodash": "^4.17.10" }, "devDependencies": { - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", "@types/lodash": "^4.14.116", "@types/mocha": "^2.2.42", "chai": "^4.0.1", diff --git a/packages/json-schemas/package.json b/packages/json-schemas/package.json index c67d15d6c9..af4c086728 100644 --- a/packages/json-schemas/package.json +++ b/packages/json-schemas/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/json-schemas", - "version": "1.0.1-rc.4", + "version": "1.0.1-rc.5", "engines": { "node": ">=6.12" }, @@ -23,7 +23,9 @@ "config": { "postpublish": { "assets": [], - "docOmitExports": ["schemas"] + "docOmitExports": [ + "schemas" + ] } }, "repository": { @@ -37,14 +39,14 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/json-schemas/README.md", "dependencies": { - "@0xproject/typescript-typings": "^1.0.4", + "@0xproject/typescript-typings": "^1.0.5", "@types/node": "^8.0.53", "jsonschema": "^1.2.0", "lodash.values": "^4.3.0" }, "devDependencies": { - "@0xproject/tslint-config": "^1.0.5", - "@0xproject/utils": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", + "@0xproject/utils": "^1.0.6", "@types/lodash.foreach": "^4.5.3", "@types/lodash.values": "^4.3.3", "@types/mocha": "^2.2.42", diff --git a/packages/metacoin/package.json b/packages/metacoin/package.json index 3337570b6b..7731c1ca31 100644 --- a/packages/metacoin/package.json +++ b/packages/metacoin/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/metacoin", - "version": "0.0.15", + "version": "0.0.16", "engines": { "node": ">=6.12" }, @@ -29,25 +29,25 @@ "author": "", "license": "Apache-2.0", "dependencies": { - "@0xproject/abi-gen": "^1.0.5", - "@0xproject/base-contract": "^2.0.0-rc.1", - "@0xproject/sol-cov": "^2.0.0", - "@0xproject/subproviders": "^1.0.5", - "@0xproject/tslint-config": "^1.0.5", - "@0xproject/types": "^1.0.1-rc.4", - "@0xproject/typescript-typings": "^1.0.4", - "@0xproject/utils": "^1.0.5", - "@0xproject/web3-wrapper": "^1.2.0", + "@0xproject/abi-gen": "^1.0.6", + "@0xproject/base-contract": "^2.0.0", + "@0xproject/sol-cov": "^2.1.0", + "@0xproject/subproviders": "^2.0.0", + "@0xproject/tslint-config": "^1.0.6", + "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/typescript-typings": "^1.0.5", + "@0xproject/utils": "^1.0.6", + "@0xproject/web3-wrapper": "^2.0.0", "@types/mocha": "^5.2.2", "copyfiles": "^2.0.0", - "ethereum-types": "^1.0.4", + "ethereum-types": "^1.0.5", "ethers": "3.0.22", "lodash": "^4.17.5", "run-s": "^0.0.0" }, "devDependencies": { - "@0xproject/dev-utils": "^1.0.4", - "@0xproject/sol-compiler": "^1.0.5", + "@0xproject/dev-utils": "^1.0.5", + "@0xproject/sol-compiler": "^1.1.0", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^2.0.1", diff --git a/packages/migrations/package.json b/packages/migrations/package.json index f48b13adbf..57f856ce59 100644 --- a/packages/migrations/package.json +++ b/packages/migrations/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/migrations", - "version": "1.0.4", + "version": "1.0.5", "engines": { "node": ">=6.12" }, @@ -35,10 +35,10 @@ }, "license": "Apache-2.0", "devDependencies": { - "@0xproject/abi-gen": "^1.0.5", - "@0xproject/dev-utils": "^1.0.4", - "@0xproject/tslint-config": "^1.0.5", - "@0xproject/types": "^1.0.1-rc.4", + "@0xproject/abi-gen": "^1.0.6", + "@0xproject/dev-utils": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", + "@0xproject/types": "^1.0.1-rc.5", "@types/yargs": "^10.0.0", "copyfiles": "^2.0.0", "make-promises-safe": "^1.1.0", @@ -49,15 +49,15 @@ "yargs": "^10.0.3" }, "dependencies": { - "@0xproject/base-contract": "^2.0.0-rc.1", - "@0xproject/order-utils": "^1.0.1-rc.3", - "@0xproject/sol-compiler": "^1.0.5", - "@0xproject/subproviders": "^1.0.5", - "@0xproject/typescript-typings": "^1.0.4", - "@0xproject/utils": "^1.0.5", - "@0xproject/web3-wrapper": "^1.2.0", + "@0xproject/base-contract": "^2.0.0", + "@0xproject/order-utils": "^1.0.1-rc.4", + "@0xproject/sol-compiler": "^1.1.0", + "@0xproject/subproviders": "^2.0.0", + "@0xproject/typescript-typings": "^1.0.5", + "@0xproject/utils": "^1.0.6", + "@0xproject/web3-wrapper": "^2.0.0", "@ledgerhq/hw-app-eth": "^4.3.0", - "ethereum-types": "^1.0.4", + "ethereum-types": "^1.0.5", "ethers": "3.0.22", "lodash": "^4.17.5" }, diff --git a/packages/monorepo-scripts/package.json b/packages/monorepo-scripts/package.json index 5516951293..6a4d0bb45e 100644 --- a/packages/monorepo-scripts/package.json +++ b/packages/monorepo-scripts/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@0xproject/monorepo-scripts", - "version": "1.0.5", + "version": "1.0.6", "engines": { "node": ">=6.12" }, diff --git a/packages/order-utils/package.json b/packages/order-utils/package.json index 0d82affef3..0a35251d72 100644 --- a/packages/order-utils/package.json +++ b/packages/order-utils/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/order-utils", - "version": "1.0.1-rc.3", + "version": "1.0.1-rc.4", "engines": { "node": ">=6.12" }, @@ -40,8 +40,8 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/order-utils/README.md", "devDependencies": { - "@0xproject/dev-utils": "^1.0.4", - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/dev-utils": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", "@types/bn.js": "^4.11.0", "@types/lodash": "4.14.104", "chai": "^4.0.1", @@ -59,16 +59,16 @@ "typescript": "3.0.1" }, "dependencies": { - "@0xproject/assert": "^1.0.5", - "@0xproject/base-contract": "^2.0.0-rc.1", - "@0xproject/json-schemas": "^1.0.1-rc.4", - "@0xproject/types": "^1.0.1-rc.4", - "@0xproject/typescript-typings": "^1.0.4", - "@0xproject/utils": "^1.0.5", - "@0xproject/web3-wrapper": "^1.2.0", + "@0xproject/assert": "^1.0.6", + "@0xproject/base-contract": "^2.0.0", + "@0xproject/json-schemas": "^1.0.1-rc.5", + "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/typescript-typings": "^1.0.5", + "@0xproject/utils": "^1.0.6", + "@0xproject/web3-wrapper": "^2.0.0", "@types/node": "^8.0.53", "bn.js": "^4.11.8", - "ethereum-types": "^1.0.4", + "ethereum-types": "^1.0.5", "ethereumjs-abi": "0.6.5", "ethereumjs-util": "^5.1.1", "ethers": "3.0.22", diff --git a/packages/order-watcher/package.json b/packages/order-watcher/package.json index 121f3f3f4e..70db15783c 100644 --- a/packages/order-watcher/package.json +++ b/packages/order-watcher/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/order-watcher", - "version": "1.0.1-rc.3", + "version": "1.0.1-rc.4", "description": "An order watcher daemon that watches for order validity", "keywords": [ "0x", @@ -43,10 +43,10 @@ "node": ">=6.0.0" }, "devDependencies": { - "@0xproject/abi-gen": "^1.0.5", - "@0xproject/dev-utils": "^1.0.4", - "@0xproject/migrations": "^1.0.4", - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/abi-gen": "^1.0.6", + "@0xproject/dev-utils": "^1.0.5", + "@0xproject/migrations": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", "@types/bintrees": "^1.0.2", "@types/lodash": "4.14.104", "@types/mocha": "^2.2.42", @@ -71,18 +71,18 @@ "typescript": "3.0.1" }, "dependencies": { - "@0xproject/assert": "^1.0.5", - "@0xproject/base-contract": "^2.0.0-rc.1", - "@0xproject/contract-wrappers": "^1.0.1-rc.3", - "@0xproject/fill-scenarios": "^1.0.1-rc.3", - "@0xproject/json-schemas": "^1.0.1-rc.4", - "@0xproject/order-utils": "^1.0.1-rc.3", - "@0xproject/types": "^1.0.1-rc.4", - "@0xproject/typescript-typings": "^1.0.4", - "@0xproject/utils": "^1.0.5", - "@0xproject/web3-wrapper": "^1.2.0", + "@0xproject/assert": "^1.0.6", + "@0xproject/base-contract": "^2.0.0", + "@0xproject/contract-wrappers": "^1.0.1-rc.4", + "@0xproject/fill-scenarios": "^1.0.1-rc.4", + "@0xproject/json-schemas": "^1.0.1-rc.5", + "@0xproject/order-utils": "^1.0.1-rc.4", + "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/typescript-typings": "^1.0.5", + "@0xproject/utils": "^1.0.6", + "@0xproject/web3-wrapper": "^2.0.0", "bintrees": "^1.0.2", - "ethereum-types": "^1.0.4", + "ethereum-types": "^1.0.5", "ethereumjs-blockstream": "5.0.0", "ethers": "3.0.22", "lodash": "^4.17.5" diff --git a/packages/react-docs/package.json b/packages/react-docs/package.json index aeface8d74..47b266e8e8 100644 --- a/packages/react-docs/package.json +++ b/packages/react-docs/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/react-docs", - "version": "1.0.5", + "version": "1.0.6", "engines": { "node": ">=6.12" }, @@ -24,8 +24,8 @@ "url": "https://github.com/0xProject/0x-monorepo.git" }, "devDependencies": { - "@0xproject/dev-utils": "^1.0.4", - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/dev-utils": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", "@types/compare-versions": "^3.0.0", "copyfiles": "^2.0.0", "make-promises-safe": "^1.1.0", @@ -34,8 +34,8 @@ "typescript": "3.0.1" }, "dependencies": { - "@0xproject/react-shared": "^1.0.6", - "@0xproject/utils": "^1.0.5", + "@0xproject/react-shared": "^1.0.7", + "@0xproject/utils": "^1.0.6", "@types/lodash": "4.14.104", "@types/material-ui": "0.18.0", "@types/node": "^8.0.53", diff --git a/packages/react-shared/package.json b/packages/react-shared/package.json index d73d6c162d..27927bbc86 100644 --- a/packages/react-shared/package.json +++ b/packages/react-shared/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/react-shared", - "version": "1.0.6", + "version": "1.0.7", "engines": { "node": ">=6.12" }, @@ -24,8 +24,8 @@ "url": "https://github.com/0xProject/0x-monorepo.git" }, "devDependencies": { - "@0xproject/dev-utils": "^1.0.4", - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/dev-utils": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", "copyfiles": "^2.0.0", "make-promises-safe": "^1.1.0", "shx": "^0.2.2", diff --git a/packages/sol-compiler/package.json b/packages/sol-compiler/package.json index ee7dffe30c..f7e901819a 100644 --- a/packages/sol-compiler/package.json +++ b/packages/sol-compiler/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/sol-compiler", - "version": "1.0.5", + "version": "1.1.0", "engines": { "node": ">=6.12" }, @@ -42,8 +42,8 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/sol-compiler/README.md", "devDependencies": { - "@0xproject/dev-utils": "^1.0.4", - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/dev-utils": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", "@types/mkdirp": "^0.5.2", "@types/require-from-string": "^1.2.0", "@types/semver": "^5.5.0", @@ -65,16 +65,16 @@ "zeppelin-solidity": "1.8.0" }, "dependencies": { - "@0xproject/assert": "^1.0.5", - "@0xproject/json-schemas": "^1.0.1-rc.4", - "@0xproject/sol-resolver": "^1.0.5", - "@0xproject/types": "^1.0.1-rc.4", - "@0xproject/typescript-typings": "^1.0.4", - "@0xproject/utils": "^1.0.5", - "@0xproject/web3-wrapper": "^1.2.0", + "@0xproject/assert": "^1.0.6", + "@0xproject/json-schemas": "^1.0.1-rc.5", + "@0xproject/sol-resolver": "^1.0.6", + "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/typescript-typings": "^1.0.5", + "@0xproject/utils": "^1.0.6", + "@0xproject/web3-wrapper": "^2.0.0", "@types/yargs": "^11.0.0", "chalk": "^2.3.0", - "ethereum-types": "^1.0.4", + "ethereum-types": "^1.0.5", "ethereumjs-util": "^5.1.1", "lodash": "^4.17.5", "mkdirp": "^0.5.1", diff --git a/packages/sol-cov/package.json b/packages/sol-cov/package.json index 2bf09e63a2..00bb300ad6 100644 --- a/packages/sol-cov/package.json +++ b/packages/sol-cov/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/sol-cov", - "version": "2.0.0", + "version": "2.1.0", "engines": { "node": ">=6.12" }, @@ -26,7 +26,10 @@ "config": { "postpublish": { "assets": [], - "docOmitExports": ["ProfilerSubprovider", "RevertTraceSubprovider"] + "docOmitExports": [ + "ProfilerSubprovider", + "RevertTraceSubprovider" + ] } }, "repository": { @@ -39,14 +42,14 @@ }, "homepage": "https://github.com/0xProject/0x.js/packages/sol-cov/README.md", "dependencies": { - "@0xproject/dev-utils": "^1.0.4", - "@0xproject/sol-compiler": "^1.0.5", - "@0xproject/subproviders": "^1.0.5", - "@0xproject/typescript-typings": "^1.0.4", - "@0xproject/utils": "^1.0.5", - "@0xproject/web3-wrapper": "^1.2.0", + "@0xproject/dev-utils": "^1.0.5", + "@0xproject/sol-compiler": "^1.1.0", + "@0xproject/subproviders": "^2.0.0", + "@0xproject/typescript-typings": "^1.0.5", + "@0xproject/utils": "^1.0.6", + "@0xproject/web3-wrapper": "^2.0.0", "@types/solidity-parser-antlr": "^0.2.1", - "ethereum-types": "^1.0.4", + "ethereum-types": "^1.0.5", "ethereumjs-util": "^5.1.1", "glob": "^7.1.2", "istanbul": "^0.4.5", @@ -58,7 +61,7 @@ "solidity-parser-antlr": "^0.2.12" }, "devDependencies": { - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", "@types/istanbul": "^0.4.30", "@types/loglevel": "^1.5.3", "@types/mkdirp": "^0.5.1", diff --git a/packages/sol-resolver/package.json b/packages/sol-resolver/package.json index c1b037942d..031e9dbdd7 100644 --- a/packages/sol-resolver/package.json +++ b/packages/sol-resolver/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/sol-resolver", - "version": "1.0.5", + "version": "1.0.6", "engines": { "node": ">=6.12" }, @@ -23,7 +23,7 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/resolver/README.md", "devDependencies": { - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", "copyfiles": "^2.0.0", "make-promises-safe": "^1.1.0", "shx": "^0.2.2", @@ -31,8 +31,8 @@ "typescript": "3.0.1" }, "dependencies": { - "@0xproject/types": "^1.0.1-rc.4", - "@0xproject/typescript-typings": "^1.0.4", + "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/typescript-typings": "^1.0.5", "lodash": "^4.17.5" }, "publishConfig": { diff --git a/packages/sra-api/package.json b/packages/sra-api/package.json index a4a0a7b0b0..1f06f8219b 100644 --- a/packages/sra-api/package.json +++ b/packages/sra-api/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/sra-api", - "version": "1.0.1-rc.4", + "version": "1.0.1-rc.5", "engines": { "node": ">=6.12" }, @@ -33,10 +33,10 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/sra-api/README.md", "dependencies": { - "@0xproject/json-schemas": "^1.0.1-rc.4" + "@0xproject/json-schemas": "^1.0.1-rc.5" }, "devDependencies": { - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", "@loopback/openapi-v3-types": "^0.8.2", "@types/mocha": "^2.2.42", "@types/node": "^10.5.3", diff --git a/packages/sra-report/package.json b/packages/sra-report/package.json index 682508a6ff..4311d77fe9 100644 --- a/packages/sra-report/package.json +++ b/packages/sra-report/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/sra-report", - "version": "1.0.5", + "version": "1.0.6", "engines": { "node": ">=6.12" }, @@ -34,20 +34,20 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/sra-report/README.md", "dependencies": { - "@0xproject/assert": "^1.0.5", + "@0xproject/assert": "^1.0.6", "@0xproject/connect": "1.0.4", "@0xproject/json-schemas": "^0.8.3", "@0xproject/order-utils": "^0.0.9", "@0xproject/types": "^0.8.2", - "@0xproject/typescript-typings": "^1.0.4", - "@0xproject/utils": "^1.0.5", + "@0xproject/typescript-typings": "^1.0.5", + "@0xproject/utils": "^1.0.6", "chalk": "^2.3.0", "lodash": "^4.17.5", "newman": "^3.9.3", "yargs": "^10.0.3" }, "devDependencies": { - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", "@types/lodash": "4.14.104", "@types/mocha": "^2.2.48", "@types/nock": "^9.1.2", diff --git a/packages/subproviders/package.json b/packages/subproviders/package.json index 521785998a..cf30cc4168 100644 --- a/packages/subproviders/package.json +++ b/packages/subproviders/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/subproviders", - "version": "1.0.5", + "version": "2.0.0", "engines": { "node": ">=6.12" }, @@ -29,18 +29,18 @@ } }, "dependencies": { - "@0xproject/assert": "^1.0.5", - "@0xproject/types": "^1.0.1-rc.4", - "@0xproject/typescript-typings": "^1.0.4", - "@0xproject/utils": "^1.0.5", - "@0xproject/web3-wrapper": "^1.2.0", + "@0xproject/assert": "^1.0.6", + "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/typescript-typings": "^1.0.5", + "@0xproject/utils": "^1.0.6", + "@0xproject/web3-wrapper": "^2.0.0", "@ledgerhq/hw-app-eth": "^4.3.0", "@ledgerhq/hw-transport-u2f": "^4.3.0", "@types/hdkey": "^0.7.0", "bip39": "^2.5.0", "bn.js": "^4.11.8", "eth-lightwallet": "^3.0.1", - "ethereum-types": "^1.0.4", + "ethereum-types": "^1.0.5", "ethereumjs-tx": "^1.3.5", "ethereumjs-util": "^5.1.1", "ganache-core": "0xProject/ganache-core#monorepo-dep", @@ -51,7 +51,7 @@ "web3-provider-engine": "14.0.6" }, "devDependencies": { - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", "@types/bip39": "^2.4.0", "@types/bn.js": "^4.11.0", "@types/ethereumjs-tx": "^1.0.0", diff --git a/packages/testnet-faucets/package.json b/packages/testnet-faucets/package.json index 769fdf3711..6dc351c29e 100644 --- a/packages/testnet-faucets/package.json +++ b/packages/testnet-faucets/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@0xproject/testnet-faucets", - "version": "1.0.41", + "version": "1.0.42", "engines": { "node": ">=6.12" }, @@ -19,12 +19,12 @@ "license": "Apache-2.0", "dependencies": { "0x.js": "0.38.5", - "@0xproject/subproviders": "^1.0.5", - "@0xproject/typescript-typings": "^1.0.4", - "@0xproject/utils": "^1.0.5", - "@0xproject/web3-wrapper": "^1.2.0", + "@0xproject/subproviders": "^2.0.0", + "@0xproject/typescript-typings": "^1.0.5", + "@0xproject/utils": "^1.0.6", + "@0xproject/web3-wrapper": "^2.0.0", "body-parser": "^1.17.1", - "ethereum-types": "^1.0.4", + "ethereum-types": "^1.0.5", "ethereumjs-tx": "^1.3.5", "ethereumjs-util": "^5.1.1", "express": "^4.15.2", @@ -32,7 +32,7 @@ "rollbar": "^0.6.5" }, "devDependencies": { - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", "@types/body-parser": "^1.16.1", "@types/express": "^4.0.35", "@types/lodash": "4.14.104", diff --git a/packages/tslint-config/package.json b/packages/tslint-config/package.json index f6b18cde39..3303149746 100644 --- a/packages/tslint-config/package.json +++ b/packages/tslint-config/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/tslint-config", - "version": "1.0.5", + "version": "1.0.6", "engines": { "node": ">=6.12" }, diff --git a/packages/types/package.json b/packages/types/package.json index 8d5eb11237..6078f422a5 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/types", - "version": "1.0.1-rc.4", + "version": "1.0.1-rc.5", "engines": { "node": ">=6.12" }, @@ -23,7 +23,7 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/types/README.md", "devDependencies": { - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", "copyfiles": "^2.0.0", "make-promises-safe": "^1.1.0", "shx": "^0.2.2", @@ -33,7 +33,7 @@ "dependencies": { "@types/node": "^8.0.53", "bignumber.js": "~4.1.0", - "ethereum-types": "^1.0.4" + "ethereum-types": "^1.0.5" }, "publishConfig": { "access": "public" diff --git a/packages/typescript-typings/package.json b/packages/typescript-typings/package.json index 0070df4fb8..c047a53289 100644 --- a/packages/typescript-typings/package.json +++ b/packages/typescript-typings/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/typescript-typings", - "version": "1.0.4", + "version": "1.0.5", "engines": { "node": ">=6.12" }, @@ -27,7 +27,7 @@ "@types/bn.js": "^4.11.0", "@types/react": "*", "bignumber.js": "~4.1.0", - "ethereum-types": "^1.0.4", + "ethereum-types": "^1.0.5", "popper.js": "1.14.3" }, "devDependencies": { diff --git a/packages/utils/package.json b/packages/utils/package.json index 4568352e18..b4795cefd3 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/utils", - "version": "1.0.5", + "version": "1.0.6", "engines": { "node": ">=6.12" }, @@ -28,7 +28,7 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/utils/README.md", "devDependencies": { - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", "@types/lodash": "4.14.104", "@types/mocha": "^2.2.42", "chai": "^4.0.1", @@ -41,13 +41,13 @@ "typescript": "3.0.1" }, "dependencies": { - "@0xproject/types": "^1.0.1-rc.4", - "@0xproject/typescript-typings": "^1.0.4", + "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/typescript-typings": "^1.0.5", "@types/node": "^8.0.53", "abortcontroller-polyfill": "^1.1.9", "bignumber.js": "~4.1.0", "detect-node": "2.0.3", - "ethereum-types": "^1.0.4", + "ethereum-types": "^1.0.5", "ethereumjs-util": "^5.1.1", "ethers": "3.0.22", "isomorphic-fetch": "^2.2.1", diff --git a/packages/web3-wrapper/package.json b/packages/web3-wrapper/package.json index 3b347ac6f2..fe8e82d15e 100644 --- a/packages/web3-wrapper/package.json +++ b/packages/web3-wrapper/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/web3-wrapper", - "version": "1.2.0", + "version": "2.0.0", "engines": { "node": ">=6.12" }, @@ -35,7 +35,7 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/web3-wrapper/README.md", "devDependencies": { - "@0xproject/tslint-config": "^1.0.5", + "@0xproject/tslint-config": "^1.0.6", "@types/lodash": "4.14.104", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", @@ -53,11 +53,11 @@ "typescript": "3.0.1" }, "dependencies": { - "@0xproject/assert": "^1.0.5", - "@0xproject/json-schemas": "^1.0.1-rc.4", - "@0xproject/typescript-typings": "^1.0.4", - "@0xproject/utils": "^1.0.5", - "ethereum-types": "^1.0.4", + "@0xproject/assert": "^1.0.6", + "@0xproject/json-schemas": "^1.0.1-rc.5", + "@0xproject/typescript-typings": "^1.0.5", + "@0xproject/utils": "^1.0.6", + "ethereum-types": "^1.0.5", "ethereumjs-util": "^5.1.1", "ethers": "3.0.22", "lodash": "^4.17.5" diff --git a/packages/website/package.json b/packages/website/package.json index 57cc4ce4ba..bd6b18866b 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/website", - "version": "0.0.44", + "version": "0.0.45", "engines": { "node": ">=6.12" }, @@ -20,13 +20,13 @@ "dependencies": { "@0xproject/contract-wrappers": "^0.0.5", "@0xproject/order-utils": "^0.0.9", - "@0xproject/react-docs": "^1.0.5", + "@0xproject/react-docs": "^1.0.6", "@0xproject/react-shared": "^0.2.3", - "@0xproject/subproviders": "^1.0.5", + "@0xproject/subproviders": "^2.0.0", "@0xproject/types": "^0.8.1", "@0xproject/typescript-typings": "^0.4.3", - "@0xproject/utils": "^1.0.5", - "@0xproject/web3-wrapper": "^1.2.0", + "@0xproject/utils": "^1.0.6", + "@0xproject/web3-wrapper": "^2.0.0", "accounting": "^0.4.1", "basscss": "^8.0.3", "blockies": "^0.0.2", From 7bcaac4e1080ae6c5d1b482992c7878b4be3174f Mon Sep 17 00:00:00 2001 From: fragosti Date: Fri, 24 Aug 2018 11:11:56 -0700 Subject: [PATCH 014/120] Ignore api.json in public --- packages/sra-spec/.gitignore | 1 + packages/sra-spec/public/api.json | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 packages/sra-spec/.gitignore delete mode 100644 packages/sra-spec/public/api.json diff --git a/packages/sra-spec/.gitignore b/packages/sra-spec/.gitignore new file mode 100644 index 0000000000..f029c576c1 --- /dev/null +++ b/packages/sra-spec/.gitignore @@ -0,0 +1 @@ +public/api.json diff --git a/packages/sra-spec/public/api.json b/packages/sra-spec/public/api.json deleted file mode 100644 index fc2409abbe..0000000000 --- a/packages/sra-spec/public/api.json +++ /dev/null @@ -1 +0,0 @@ -{"openapi":"3.0.0","info":{"version":"2.0.0","title":"Standard Relayer REST API","description":"# Testing\n\nUse the [sra-report](https://github.com/0xProject/0x-monorepo/tree/development/packages/sra-report) command line tool to test your API for SRA compliance.\n\n# Schemas\n\nThe [JSON schemas](http://json-schema.org/) for the API payloads and responses can be found in [@0xproject/json-schemas](https://github.com/0xProject/0x.js/tree/development/packages/json-schemas). Examples of each payload and response can be found in the library's [test suite](https://github.com/0xProject/0x.js/blob/development/packages/json-schemas/test/schema_test.ts#L1).\n\n```bash\nnpm install @0xproject/json-schemas --save\n```\n\nYou can easily validate your API's payloads and responses using the [@0xproject/json-schemas](https://github.com/0xProject/0x.js/tree/development/packages/json-schemas) package:\n\n```js\nimport {SchemaValidator, ValidatorResult, schemas} from '@0xproject/json-schemas';\n\nconst {relayerApiTokenPairsResponseSchema} = schemas;\nconst validator = new SchemaValidator();\n\nconst tokenPairsResponse = {\n ...\n};\nconst validatorResult: ValidatorResult = validator.validate(tokenPairsResponse, relayerApiTokenPairsResponseSchema);\n```\n\n# Pagination\n\nRequests that return potentially large collections should respond to the **?page** and **?perPage** parameters. For example:\n\n```bash\n$ curl https://api.example-relayer.com/v2/asset_pairs?page=3&perPage=20\n```\n\nPage numbering should be 1-indexed, not 0-indexed. If a query provides an unreasonable (ie. too high) `perPage` value, the response can return a validation error as specified in the [errors section](#section/Errors). If the query specifies a `page` that does not exist (ie. there are not enough `records`), the response should just return an empty `records` array.\n\nAll endpoints that are paginated should return a `total`, `page`, `perPage` and a `records` value in the top level of the collection. The value of `total` should be the total number of records for a given query, whereas `records` should be an array representing the response to the query for that page. `page` and `perPage`, are the same values that were specified in the request. See the note in [miscellaneous](#section/Misc.) about formatting `snake_case` vs. `lowerCamelCase`.\n\nThese requests include the [`/v2/asset_pairs`](#operation/getAssetPairs), [`/v2/orders`](#operation/getOrders), [`/v2/fee_recipients`](#operation/getFeeRecipients) and [`/v2/orderbook`](#operation/getOrderbook) endpoints.\n\n# Network Id\n\nAll requests should be able to specify a **?networkId** query param for all supported networks. For example:\n\n```bash\n$ curl https://api.example-relayer.com/v2/asset_pairs?networkId=1\n```\n\nIf the query param is not provided, it should default to **1** (mainnet).\n\nNetworks and their Ids:\n\n| Network Id | Network Name |\n| ---------- | ------------ |\n| 1 | Mainnet |\n| 42 | Kovan |\n| 3 | Ropsten |\n| 4 | Rinkeby |\n\nIf a certain network is not supported, the response should **400** as specified in the [error response](#section/Errors) section. For example:\n\n```json\n{\n \"code\": 100,\n \"reason\": \"Validation failed\",\n \"validationErrors\": [\n {\n \"field\": \"networkId\",\n \"code\": 1006,\n \"reason\": \"Network id 42 is not supported\"\n }\n ]\n}\n```\n\n# Link Header\n\nA [Link Header](https://tools.ietf.org/html/rfc5988) can be included in a response to provide clients with more context about paging\nFor example:\n\n```bash\nLink: ; rel=\"next\",\n; rel=\"last\"\n```\n\nThis `Link` response header contains one or more Hypermedia link relations.\n\nThe possible `rel` values are:\n\n| Name | Description |\n| ----- | ------------------------------------------------------------- |\n| next | The link relation for the immediate next page of results. |\n| last | The link relation for the last page of results. |\n| first | The link relation for the first page of results. |\n| prev | The link relation for the immediate previous page of results. |\n\n# Rate Limits\n\nRate limit guidance for clients can be optionally returned in the response headers:\n\n| Header Name | Description |\n| --------------------- | ---------------------------------------------------------------------------- |\n| X-RateLimit-Limit | The maximum number of requests you're permitted to make per hour. |\n| X-RateLimit-Remaining | The number of requests remaining in the current rate limit window. |\n| X-RateLimit-Reset | The time at which the current rate limit window resets in UTC epoch seconds. |\n\nFor example:\n\n```bash\n$ curl -i https://api.example-relayer.com/v2/asset_pairs\nHTTP/1.1 200 OK\nDate: Mon, 20 Oct 2017 12:30:06 GMT\nStatus: 200 OK\nX-RateLimit-Limit: 60\nX-RateLimit-Remaining: 56\nX-RateLimit-Reset: 1372700873\n```\n\nWhen a rate limit is exceeded, a status of **429 Too Many Requests** should be returned.\n\n# Errors\n\nUnless the spec defines otherwise, errors to bad requests should respond with HTTP 4xx or status codes.\n\n## Common error codes\n\n| Code | Reason |\n| ---- | --------------------------------------- |\n| 400 | Bad Request – Invalid request format |\n| 404 | Not found |\n| 429 | Too many requests - Rate limit exceeded |\n| 500 | Internal Server Error |\n| 501 | Not Implemented |\n\n## Error reporting format\n\nFor all **400** responses, see the [error response schema](https://github.com/0xProject/0x-monorepo/blob/development/packages/json-schemas/schemas/relayer_api_error_response_schema.ts#L1).\n\n```json\n{\n \"code\": 101,\n \"reason\": \"Validation failed\",\n \"validationErrors\": [\n {\n \"field\": \"maker\",\n \"code\": 1002,\n \"reason\": \"Invalid address\"\n }\n ]\n}\n```\n\nGeneral error codes:\n\n```bash\n100 - Validation Failed\n101 - Malformed JSON\n102 - Order submission disabled\n103 - Throttled\n```\n\nValidation error codes:\n\n```bash\n1000 - Required field\n1001 - Incorrect format\n1002 - Invalid address\n1003 - Address not supported\n1004 - Value out of range\n1005 - Invalid signature or hash\n1006 - Unsupported option\n```\n\n# Asset Data Encoding\n\nAs we now support multiple [token transfer proxies](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxy), the identifier of which proxy to use for the token transfer must be encoded, along with the token information. Each proxy in 0x v2 has a unique identifier. If you're using 0x.js there will be helper methods for this [encoding](https://0xproject.com/docs/0x.js#zeroEx-encodeERC20AssetData) and [decoding](https://0xproject.com/docs/0x.js#zeroEx-decodeAssetProxyId).\n\nThe identifier for the Proxy uses a similar scheme to [ABI function selectors](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI#function-selector).\n\n```js\n// ERC20 Proxy ID 0xf47261b0\nbytes4(keccak256('ERC20Token(address)'));\n// ERC721 Proxy ID 0x08e937fa\nbytes4(keccak256('ERC721Token(address,uint256)'));\n```\n\nAsset data is encoded using [ABI encoding](https://solidity.readthedocs.io/en/develop/abi-spec.html).\n\nFor example, encoding the ERC20 token contract (address: 0x1dc4c1cefef38a777b15aa20260a54e584b16c48) using the ERC20 Transfer Proxy (id: 0xf47261b0) would be:\n\n```bash\n0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48\n```\n\nEncoding the ERC721 token contract (address: `0x371b13d97f4bf77d724e78c16b7dc74099f40e84`), token id (id: `99`, which hex encoded is `0x63`) and the ERC721 Transfer Proxy (id: 0x08e937fa) would be:\n\n```bash\n0x08e937fa000000000000000000000000371b13d97f4bf77d724e78c16b7dc74099f40e840000000000000000000000000000000000000000000000000000000000000063\n```\n\nFor more information see [the Asset Proxy](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#erc20proxy) section of the v2 spec and the [Ethereum ABI Spec](https://solidity.readthedocs.io/en/develop/abi-spec.html).\n\n# Meta Data in Order Responses\n\nIn 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.\n\nA 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).\n\n# Misc.\n\n* All requests and responses should be of **application/json** content type\n* All token amounts are sent in amounts of the smallest level of precision (base units). (e.g if a token has 18 decimal places, selling 1 token would show up as selling `'1000000000000000000'` units by this API).\n* All addresses are sent as lower-case (non-checksummed) Ethereum addresses with the `0x` prefix.\n* All parameters are to be written in `lowerCamelCase`.\n","license":{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0.html"}},"paths":{"/v2/asset_pairs":{"get":{"description":"Retrieves a list of available asset pairs and the information required to trade them (in any order). Setting only `assetDataA` or `assetDataB` returns pairs filtered by that asset only.","operationId":"getAssetPairs","parameters":[{"name":"assetDataA","in":"query","description":"The assetData value for the first asset in the pair.","example":"0xf47261b04c32345ced77393b3530b1eed0f346429d","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"assetDataB","in":"query","description":"The assetData value for the second asset in the pair.","example":"0x0257179264389b814a946f3e92105513705ca6b990","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}},{"name":"page","in":"query","description":"The number of the page to request in the collection.","example":3,"schema":{"type":"number","default":1}},{"name":"perPage","in":"query","description":"The number of records to return per page.","example":10,"schema":{"type":"number","default":100}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"Returns a collection of available asset pairs with some meta info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiAssetDataPairsResponseSchema"},"example":{"total":43,"page":1,"perPage":100,"records":[{"assetDataA":{"minAmount":"0","maxAmount":"10000000000000000000","precision":5,"assetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d"},"assetDataB":{"minAmount":"0","maxAmount":"50000000000000000000","precision":5,"assetData":"0x0257179264389b814a946f3e92105513705ca6b990"}}]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/orders":{"get":{"description":"Retrieves a list of orders given query parameters. This endpoint should be [paginated](#section/Pagination). For querying an entire orderbook snapshot, the [orderbook endpoint](#operation/getOrderbook) is recommended. If both makerAssetData and takerAssetData are specified, returned orders will be sorted by price determined by (takerTokenAmount/makerTokenAmount) in ascending order. By default, orders returned by this endpoint are unsorted.","operationId":"getOrders","parameters":[{"name":"makerAssetProxyId","in":"query","description":"The maker [asset proxy id](https://0xproject.com/docs/0x.js#types-AssetProxyId) (example: \"0xf47261b0\" for ERC20, \"0x02571792\" for ERC721).","example":"0xf47261b0","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"takerAssetProxyId","in":"query","description":"The taker asset [asset proxy id](https://0xproject.com/docs/0x.js#types-AssetProxyId) (example: \"0xf47261b0\" for ERC20, \"0x02571792\" for ERC721).","example":"0x02571792","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"makerAssetAddress","in":"query","description":"The contract address for the maker asset.","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"takerAssetAddress","in":"query","description":"The contract address for the taker asset.","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"exchangeAddress","in":"query","description":"Same as exchangeAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"senderAddress","in":"query","description":"Same as senderAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"makerAssetData","in":"query","description":"Same as makerAssetData in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"takerAssetData","in":"query","description":"Same as takerAssetData in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"traderAssetData","in":"query","description":"Same as traderAssetData in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"makerAddress","in":"query","description":"Same as makerAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"takerAddress","in":"query","description":"Same as takerAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"traderAddress","in":"query","description":"Same as traderAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"feeRecipientAddress","in":"query","description":"Same as feeRecipientAddress in the [0x Protocol v2 Specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#order-message-format)","example":"0xe41d2489571d322189246dafa5ebde1f4699f498","schema":{"$ref":"#/components/schemas/addressSchema"}},{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}},{"name":"page","in":"query","description":"The number of the page to request in the collection.","example":3,"schema":{"type":"number","default":1}},{"name":"perPage","in":"query","description":"The number of records to return per page.","example":10,"schema":{"type":"number","default":100}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"A collection of 0x orders with meta-data as specified by query params","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrdersResponseSchema"},"example":{"total":984,"page":1,"perPage":100,"records":[{"order":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerFee":"100000000000000","takerFee":"200000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33"},"metaData":{}}]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/order/{orderHash}":{"get":{"description":"Retrieves the 0x order with meta info that is associated with the hash.","operationId":"getOrder","parameters":[{"name":"orderHash","in":"path","description":"The hash of the desired 0x order.","example":"0xd4b103c42d2512eef3fee775e097f044291615d25f5d71e0ac70dbd49d223591","schema":{"$ref":"#/components/schemas/orderHashSchema"}},{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"The order and meta info associated with the orderHash","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrderSchema"},"example":{"order":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerFee":"100000000000000","takerFee":"200000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33"},"metaData":{}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/orderbook":{"get":{"description":"Retrieves the orderbook for a given asset pair. This endpoint should be [paginated](#section/Pagination). Bids will be sorted in descending order by price, and asks will be sorted in ascending order by price. Within the price sorted orders, the orders are further sorted by _taker fee price_ which is defined as the **takerFee** divided by **takerTokenAmount**. After _taker fee price_, orders are to be sorted by expiration in ascending order. The way pagination works for this endpoint is that the **page** and **perPage** query params apply to both `bids` and `asks` collections, and if `page` * `perPage` > `total` for a certain collection, the `records` for that collection should just be empty. ","operationId":"getOrderbook","parameters":[{"name":"baseAssetData","in":"query","description":"assetData (makerAssetData or takerAssetData) designated as the base currency in the [currency pair calculation](https://en.wikipedia.org/wiki/Currency_pair) of price.","required":true,"example":"0xf47261b04c32345ced77393b3530b1eed0f346429d","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"quoteAssetData","in":"query","description":"assetData (makerAssetData or takerAssetData) designated as the quote currency in the currency pair calculation of price (required).","required":true,"example":"0xf47261b04c32345ced77393b3530b1eed0f346429d","schema":{"$ref":"#/components/schemas/hexSchema"}},{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}},{"name":"page","in":"query","description":"The number of the page to request in the collection.","example":3,"schema":{"type":"number","default":1}},{"name":"perPage","in":"query","description":"The number of records to return per page.","example":10,"schema":{"type":"number","default":100}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"The sorted order book for the specified asset pair.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrderbookResponseSchema"},"example":{"bids":{"total":325,"page":2,"perPage":100,"records":[{"order":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerFee":"100000000000000","takerFee":"200000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33"},"metaData":{}}]},"asks":{"total":500,"page":2,"perPage":100,"records":[{"order":{"makerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","takerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"20000000000000000","takerAssetAmount":"10000000000000000","makerFee":"200000000000000","takerFee":"100000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","takerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x013842a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b3518891"},"metaData":{}}]}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/order_config":{"get":{"description":"Relayers have full discretion over the orders that they are willing to host on their orderbooks (e.g what fees they charge, etc...). In order for traders to discover their requirements programmatically, they can send an incomplete order to this endpoint and receive the missing fields, specifc to that order. This gives relayers a large amount of flexibility to tailor fees to unique traders, trading pairs and volume amounts. Submit a partial order and receive information required to complete the order: `senderAddress`, `feeRecipientAddress`, `makerFee`, `takerFee`. ","operationId":"getOrderConfig","parameters":[{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}}],"requestBody":{"description":"The fields of a 0x order the relayer may want to decide what configuration to send back.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrderConfigPayloadSchema"},"example":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","expirationTimeSeconds":"1532560590"}}}},"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"The additional fields necessary in order to submit an order to the relayer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiOrderConfigResponseSchema"},"example":{"senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","makerFee":"100000000000000","takerFee":"200000000000000"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/fee_recipients":{"get":{"description":"Retrieves a collection of all fee recipient addresses for a relayer. This endpoint should be [paginated](#section/Pagination).","operationId":"getFeeRecipients","parameters":[{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}},{"name":"page","in":"query","description":"The number of the page to request in the collection.","example":3,"schema":{"type":"number","default":1}},{"name":"perPage","in":"query","description":"The number of records to return per page.","example":10,"schema":{"type":"number","default":100}}],"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"A collection of all used fee recipient addresses.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiFeeRecipientsResponseSchema"},"example":{"total":3,"page":1,"perPage":10,"records":["0x6eC92694ea172ebC430C30fa31De87620967A082","0x9e56625509c2f60af937f23b7b532600390e8c8b","0xa2b31dacf30a9c50ca473337c01d8a201ae33e32"]}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}},"/v2/order":{"post":{"description":"Submit a signed order to the relayer.","operationId":"postOrder","parameters":[{"name":"networkId","in":"query","description":"The id of the Ethereum network","example":42,"schema":{"type":"number","default":1}}],"requestBody":{"description":"A valid signed 0x order based on the schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/signedOrderSchema"},"example":{"makerAddress":"0x9e56625509c2f60af937f23b7b532600390e8c8b","takerAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","feeRecipientAddress":"0xb046140686d052fff581f63f8136cce132e857da","senderAddress":"0xa2b31dacf30a9c50ca473337c01d8a201ae33e32","makerAssetAmount":"10000000000000000","takerAssetAmount":"20000000000000000","makerFee":"100000000000000","takerFee":"200000000000000","expirationTimeSeconds":"1532560590","salt":"1532559225","makerAssetData":"0xf47261b04c32345ced77393b3530b1eed0f346429d","takerAssetData":"0x0257179264389b814a946f3e92105513705ca6b990","exchangeAddress":"0x12459c951127e0c374ff9105dda097662a027093","signature":"0x012761a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc33"}}}},"responses":{"200":{"headers":{"X-Rate-Limit-Limit":{"description":"The maximum number of requests you're permitted to make per hour.","schema":{"type":"integer"}},"X-Rate-Limit-Remaining":{"description":"The number of requests remaining in the current rate limit window.","schema":{"type":"integer"}},"X-Rate-Limit-Reset":{"description":"The time at which the current rate limit window resets in UTC epoch seconds.","schema":{"type":"integer"}}},"description":"OK","content":{}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/relayerApiErrorResponseSchema"},"example":{"code":100,"reason":"Validation failed","validationErrors":[{"field":"networkId","code":1006,"reason":"Network id 42 is not supported"}]}}}},"404":{"description":"Not found"},"429":{"description":"Too many requests - Rate limit exceeded"},"500":{"description":"Internal Server Error"},"501":{"description":"Not implemented."}}}}},"components":{"schemas":{"numberSchema":{"type":"string","pattern":"^\\d+(\\.\\d+)?$"},"addressSchema":{"type":"string","pattern":"^0x[0-9a-f]{40}$"},"hexSchema":{"type":"string","pattern":"^0x(([0-9a-f][0-9a-f])+)?$"},"orderHashSchema":{"type":"string","pattern":"^0x[0-9a-fA-F]{64}$"},"orderSchema":{"properties":{"makerAddress":{"$ref":"#/components/schemas/addressSchema"},"takerAddress":{"$ref":"#/components/schemas/addressSchema"},"makerFee":{"$ref":"#/components/schemas/numberSchema"},"takerFee":{"$ref":"#/components/schemas/numberSchema"},"senderAddress":{"$ref":"#/components/schemas/addressSchema"},"makerAssetAmount":{"$ref":"#/components/schemas/numberSchema"},"takerAssetAmount":{"$ref":"#/components/schemas/numberSchema"},"makerAssetData":{"$ref":"#/components/schemas/hexSchema"},"takerAssetData":{"$ref":"#/components/schemas/hexSchema"},"salt":{"$ref":"#/components/schemas/numberSchema"},"exchangeAddress":{"$ref":"#/components/schemas/addressSchema"},"feeRecipientAddress":{"$ref":"#/components/schemas/addressSchema"},"expirationTimeSeconds":{"$ref":"#/components/schemas/numberSchema"}},"required":["makerAddress","takerAddress","makerFee","takerFee","senderAddress","makerAssetAmount","takerAssetAmount","makerAssetData","takerAssetData","salt","exchangeAddress","feeRecipientAddress","expirationTimeSeconds"],"type":"object"},"signedOrderSchema":{"allOf":[{"$ref":"#/components/schemas/orderSchema"},{"properties":{"signature":{"$ref":"#/components/schemas/hexSchema"}},"required":["signature"]}]},"signedOrdersSchema":{"type":"array","items":{"$ref":"#/components/schemas/signedOrderSchema"}},"ordersSchema":{"type":"array","items":{"$ref":"#/components/schemas/orderSchema"}},"paginatedCollectionSchema":{"type":"object","properties":{"total":{"type":"number"},"perPage":{"type":"number"},"page":{"type":"number"}},"required":["total","perPage","page"]},"relayerApiErrorResponseSchema":{"type":"object","properties":{"code":{"type":"integer","minimum":100,"maximum":103},"reason":{"type":"string"},"validationErrors":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"code":{"type":"integer","minimum":1000,"maximum":1006},"reason":{"type":"string"}},"required":["field","code","reason"]}}},"required":["code","reason"]},"relayerApiFeeRecipientsResponseSchema":{"type":"object","allOf":[{"$ref":"#/components/schemas/paginatedCollectionSchema"},{"properties":{"records":{"id":"#/components/schemas/relayerApiFeeRecipientsSchema","type":"array","items":{"$ref":"#/components/schemas/addressSchema"}}},"required":["records"]}]},"relayerApiOrderSchema":{"type":"object","properties":{"order":{"$ref":"#/components/schemas/orderSchema"},"metaData":{"type":"object"}},"required":["order","metaData"]},"relayerApiOrdersSchema":{"type":"array","items":{"$ref":"#/components/schemas/relayerApiOrderSchema"}},"relayerApiOrderConfigPayloadSchema":{"type":"object","properties":{"makerAddress":{"$ref":"#/components/schemas/addressSchema"},"takerAddress":{"$ref":"#/components/schemas/addressSchema"},"makerAssetAmount":{"$ref":"#/components/schemas/numberSchema"},"takerAssetAmount":{"$ref":"#/components/schemas/numberSchema"},"makerAssetData":{"$ref":"#/components/schemas/hexSchema"},"takerAssetData":{"$ref":"#/components/schemas/hexSchema"},"exchangeAddress":{"$ref":"#/components/schemas/addressSchema"},"expirationTimeSeconds":{"$ref":"#/components/schemas/numberSchema"}},"required":["makerAddress","takerAddress","makerAssetAmount","takerAssetAmount","makerAssetData","takerAssetData","exchangeAddress","expirationTimeSeconds"]},"relayerApiOrderConfigResponseSchema":{"type":"object","properties":{"makerFee":{"$ref":"#/components/schemas/numberSchema"},"takerFee":{"$ref":"#/components/schemas/numberSchema"},"feeRecipientAddress":{"$ref":"#/components/schemas/addressSchema"},"senderAddress":{"$ref":"#/components/schemas/addressSchema"}},"required":["makerFee","takerFee","feeRecipientAddress","senderAddress"]},"relayerApiOrderbookResponseSchema":{"type":"object","properties":{"bids":{"$ref":"#/components/schemas/relayerApiOrdersResponseSchema"},"asks":{"$ref":"#/components/schemas/relayerApiOrdersResponseSchema"}},"required":["bids","asks"]},"relayerApiAssetDataPairsResponseSchema":{"type":"object","allOf":[{"$ref":"#/components/schemas/paginatedCollectionSchema"},{"properties":{"records":{"$ref":"#/components/schemas/relayerApiAssetDataPairsSchema"}},"required":["records"]}]},"relayerApiAssetDataTradeInfoSchema":{"type":"object","properties":{"assetData":{"$ref":"#/components/schemas/hexSchema"},"minAmount":{"$ref":"#/components/schemas/numberSchema"},"maxAmount":{"$ref":"#/components/schemas/numberSchema"},"precision":{"type":"number"}},"required":["assetData"]},"relayerApiOrdersChannelSubscribeSchema":{"type":"object","properties":{"type":{"enum":["subscribe"]},"channel":{"enum":["orders"]},"requestId":{"type":"string"},"payload":{"$ref":"#/components/schemas/relayerApiOrdersChannelSubscribePayload"}},"required":["type","channel","requestId"]},"relayerApiOrdersChannelSubscribePayload":{"type":"object","properties":{"makerAssetProxyId":{"$ref":"#/components/schemas/hexSchema"},"takerAssetProxyId":{"$ref":"#/components/schemas/hexSchema"},"networkId":{"type":"number"},"makerAssetAddress":{"$ref":"#/components/schemas/addressSchema"},"takerAssetAddress":{"$ref":"#/components/schemas/addressSchema"},"makerAssetData":{"$ref":"#/components/schemas/hexSchema"},"takerAssetData":{"$ref":"#/components/schemas/hexSchema"},"traderAssetData":{"$ref":"#/components/schemas/hexSchema"}}},"relayerApiOrdersChannelUpdateSchema":{"type":"object","properties":{"type":{"enum":["update"]},"channel":{"enum":["orders"]},"requestId":{"type":"string"},"payload":{"$ref":"#/components/schemas/relayerApiOrdersSchema"}},"required":["type","channel","requestId"]},"relayerApiOrdersResponseSchema":{"type":"object","allOf":[{"$ref":"#/components/schemas/paginatedCollectionSchema"},{"properties":{"records":{"$ref":"#/components/schemas/relayerApiOrdersSchema"}},"required":["records"]}]},"relayerApiAssetDataPairsSchema":{"type":"array","items":{"properties":{"assetDataA":{"$ref":"#/components/schemas/relayerApiAssetDataTradeInfoSchema"},"assetDataB":{"$ref":"#/components/schemas/relayerApiAssetDataTradeInfoSchema"}},"required":["assetDataA","assetDataB"],"type":"object"}}}}} \ No newline at end of file From c5f8b9c2d2b1eed5789b40c4df07e98afe0431ab Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Thu, 23 Aug 2018 17:25:22 -0700 Subject: [PATCH 015/120] Add pragma experimental v0.5.0 to SignatureValidator and add tests --- packages/contracts/compiler.json | 1 + packages/contracts/package.json | 3 +- .../Exchange/MixinSignatureValidator.sol | 1 + .../TestSignatureValidator.sol | 1 + .../test/TestStaticCall/TestStaticCall.sol | 64 +++++++++++++++++++ .../test/exchange/signature_validator.ts | 53 ++++++++++++++- packages/contracts/test/utils/artifacts.ts | 2 + 7 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 packages/contracts/src/2.0.0/test/TestStaticCall/TestStaticCall.sol diff --git a/packages/contracts/compiler.json b/packages/contracts/compiler.json index 16524231c3..741614f2c3 100644 --- a/packages/contracts/compiler.json +++ b/packages/contracts/compiler.json @@ -47,6 +47,7 @@ "TestLibs", "TestExchangeInternals", "TestSignatureValidator", + "TestStaticCall", "TokenRegistry", "Validator", "Wallet", diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 10ab09767b..6fd5a864bc 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -33,7 +33,8 @@ "lint-contracts": "solhint src/2.0.0/**/**/**/**/*.sol" }, "config": { - "abis": "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|DummyNoReturnERC20Token|ERC20Proxy|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|InvalidERC721Receiver|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|OrderValidator|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestExchangeInternals|TestLibBytes|TestLibs|TestSignatureValidator|Validator|Wallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json" + "abis": + "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|DummyNoReturnERC20Token|ERC20Proxy|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|InvalidERC721Receiver|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|OrderValidator|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestExchangeInternals|TestLibBytes|TestLibs|TestSignatureValidator|TestStaticCall|Validator|Wallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json" }, "repository": { "type": "git", diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol index 44de548177..fd655e7571 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol @@ -17,6 +17,7 @@ */ pragma solidity 0.4.24; +pragma experimental "v0.5.0"; import "../../utils/LibBytes/LibBytes.sol"; import "./mixins/MSignatureValidator.sol"; diff --git a/packages/contracts/src/2.0.0/test/TestSignatureValidator/TestSignatureValidator.sol b/packages/contracts/src/2.0.0/test/TestSignatureValidator/TestSignatureValidator.sol index e1a610469c..3845b7b9ed 100644 --- a/packages/contracts/src/2.0.0/test/TestSignatureValidator/TestSignatureValidator.sol +++ b/packages/contracts/src/2.0.0/test/TestSignatureValidator/TestSignatureValidator.sol @@ -17,6 +17,7 @@ */ pragma solidity 0.4.24; +pragma experimental "v0.5.0"; import "../../protocol/Exchange/MixinSignatureValidator.sol"; import "../../protocol/Exchange/MixinTransactions.sol"; diff --git a/packages/contracts/src/2.0.0/test/TestStaticCall/TestStaticCall.sol b/packages/contracts/src/2.0.0/test/TestStaticCall/TestStaticCall.sol new file mode 100644 index 0000000000..be24e2f37e --- /dev/null +++ b/packages/contracts/src/2.0.0/test/TestStaticCall/TestStaticCall.sol @@ -0,0 +1,64 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity 0.4.24; + + +contract TestStaticCall { + + uint256 internal state = 1; + + /// @dev Updates state and returns true. Intended to be used with `Validator` signature type. + /// @param hash Message hash that is signed. + /// @param signerAddress Address that should have signed the given hash. + /// @param signature Proof of signing. + /// @return Validity of order signature. + function isValidSignature( + bytes32 hash, + address signerAddress, + bytes signature + ) + external + returns (bool isValid) + { + updateState(); + return true; + } + + /// @dev Updates state and returns true. Intended to be used with `Wallet` signature type. + /// @param hash Message hash that is signed. + /// @param signature Proof of signing. + /// @return Validity of order signature. + function isValidSignature( + bytes32 hash, + bytes signature + ) + external + returns (bool isValid) + { + updateState(); + return true; + } + + /// @dev Increments state variable. + function updateState() + internal + { + state++; + } +} diff --git a/packages/contracts/test/exchange/signature_validator.ts b/packages/contracts/test/exchange/signature_validator.ts index cd4f3d6f38..0e2967bc7e 100644 --- a/packages/contracts/test/exchange/signature_validator.ts +++ b/packages/contracts/test/exchange/signature_validator.ts @@ -9,11 +9,12 @@ import { TestSignatureValidatorContract, TestSignatureValidatorSignatureValidatorApprovalEventArgs, } from '../../generated_contract_wrappers/test_signature_validator'; +import { TestStaticCallContract } from '../../generated_contract_wrappers/test_static_call'; import { ValidatorContract } from '../../generated_contract_wrappers/validator'; import { WalletContract } from '../../generated_contract_wrappers/wallet'; import { addressUtils } from '../utils/address_utils'; import { artifacts } from '../utils/artifacts'; -import { expectContractCallFailed } from '../utils/assertions'; +import { expectContractCallFailed, expectContractCallFailedWithoutReasonAsync } from '../utils/assertions'; import { chaiSetup } from '../utils/chai_setup'; import { constants } from '../utils/constants'; import { LogDecoder } from '../utils/log_decoder'; @@ -31,6 +32,8 @@ describe('MixinSignatureValidator', () => { let signatureValidator: TestSignatureValidatorContract; let testWallet: WalletContract; let testValidator: ValidatorContract; + let maliciousWallet: TestStaticCallContract; + let maliciousValidator: TestStaticCallContract; let signerAddress: string; let signerPrivateKey: Buffer; let notSignerAddress: string; @@ -65,6 +68,11 @@ describe('MixinSignatureValidator', () => { txDefaults, signerAddress, ); + maliciousWallet = maliciousValidator = await TestStaticCallContract.deployFrom0xArtifactAsync( + artifacts.TestStaticCall, + provider, + txDefaults, + ); signatureValidatorLogDecoder = new LogDecoder(web3Wrapper); await web3Wrapper.awaitTransactionSuccessAsync( await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync(testValidator.address, true, { @@ -72,6 +80,16 @@ describe('MixinSignatureValidator', () => { }), constants.AWAIT_TRANSACTION_MINED_MS, ); + await web3Wrapper.awaitTransactionSuccessAsync( + await signatureValidator.setSignatureValidatorApproval.sendTransactionAsync( + maliciousValidator.address, + true, + { + from: signerAddress, + }, + ), + constants.AWAIT_TRANSACTION_MINED_MS, + ); const defaultOrderParams = { ...constants.STATIC_ORDER_PARAMS, @@ -334,6 +352,29 @@ describe('MixinSignatureValidator', () => { expect(isValidSignature).to.be.false(); }); + it('should not allow `isValidSignature` to update state when SignatureType=Wallet', async () => { + // Create EIP712 signature + const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); + const orderHashBuffer = ethUtil.toBuffer(orderHashHex); + const ecSignature = ethUtil.ecsign(orderHashBuffer, signerPrivateKey); + // Create 0x signature from EIP712 signature + const signature = Buffer.concat([ + ethUtil.toBuffer(ecSignature.v), + ecSignature.r, + ecSignature.s, + ethUtil.toBuffer(`0x${SignatureType.Wallet}`), + ]); + const signatureHex = ethUtil.bufferToHex(signature); + // Validate signature + await expectContractCallFailedWithoutReasonAsync( + signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + maliciousWallet.address, + signatureHex, + ), + ); + }); + it('should return true when SignatureType=Validator, signature is valid and validator is approved', async () => { const validatorAddress = ethUtil.toBuffer(`${testValidator.address}`); const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`); @@ -364,6 +405,16 @@ describe('MixinSignatureValidator', () => { expect(isValidSignature).to.be.false(); }); + it('should not allow `isValidSignature` to update state when SignatureType=Validator', async () => { + const validatorAddress = ethUtil.toBuffer(`${maliciousValidator.address}`); + const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`); + const signature = Buffer.concat([validatorAddress, signatureType]); + const signatureHex = ethUtil.bufferToHex(signature); + const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); + await expectContractCallFailedWithoutReasonAsync( + signatureValidator.publicIsValidSignature.callAsync(orderHashHex, signerAddress, signatureHex), + ); + }); it('should return false when SignatureType=Validator, signature is valid and validator is not approved', async () => { // Set approval of signature validator to false await web3Wrapper.awaitTransactionSuccessAsync( diff --git a/packages/contracts/test/utils/artifacts.ts b/packages/contracts/test/utils/artifacts.ts index e8a7585ac3..1c922a3e48 100644 --- a/packages/contracts/test/utils/artifacts.ts +++ b/packages/contracts/test/utils/artifacts.ts @@ -23,6 +23,7 @@ import * as TestExchangeInternals from '../../artifacts/TestExchangeInternals.js import * as TestLibBytes from '../../artifacts/TestLibBytes.json'; import * as TestLibs from '../../artifacts/TestLibs.json'; import * as TestSignatureValidator from '../../artifacts/TestSignatureValidator.json'; +import * as TestStaticCall from '../../artifacts/TestStaticCall.json'; import * as TokenRegistry from '../../artifacts/TokenRegistry.json'; import * as Validator from '../../artifacts/Validator.json'; import * as Wallet from '../../artifacts/Wallet.json'; @@ -55,6 +56,7 @@ export const artifacts = { TestLibs: (TestLibs as any) as ContractArtifact, TestExchangeInternals: (TestExchangeInternals as any) as ContractArtifact, TestSignatureValidator: (TestSignatureValidator as any) as ContractArtifact, + TestStaticCall: (TestStaticCall as any) as ContractArtifact, Validator: (Validator as any) as ContractArtifact, Wallet: (Wallet as any) as ContractArtifact, TokenRegistry: (TokenRegistry as any) as ContractArtifact, From 0a1ae2c31139e446b2fb3b7f03caf371c6668ae2 Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Fri, 24 Aug 2018 00:19:06 -0700 Subject: [PATCH 016/120] Remove pragma experimental v0.5.0 and use staticcall is assembly --- .../Exchange/MixinSignatureValidator.sol | 84 ++++++++++++++++++- .../Exchange/mixins/MSignatureValidator.sol | 31 +++++++ .../TestSignatureValidator.sol | 1 - .../test/TestStaticCall/TestStaticCall.sol | 16 ++++ packages/contracts/test/exchange/core.ts | 59 ++++++++++++- .../test/exchange/signature_validator.ts | 22 ++--- 6 files changed, 198 insertions(+), 15 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol index fd655e7571..6bfbb51076 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol @@ -17,7 +17,6 @@ */ pragma solidity 0.4.24; -pragma experimental "v0.5.0"; import "../../utils/LibBytes/LibBytes.sol"; import "./mixins/MSignatureValidator.sol"; @@ -192,7 +191,11 @@ contract MixinSignatureValidator is // Signature verified by wallet contract. // If used with an order, the maker of the order is the wallet contract. } else if (signatureType == SignatureType.Wallet) { - isValid = IWallet(signerAddress).isValidSignature(hash, signature); + isValid = isValidWalletSignature( + hash, + signerAddress, + signature + ); return isValid; // Signature verified by validator contract. @@ -210,7 +213,8 @@ contract MixinSignatureValidator is if (!allowedValidators[signerAddress][validatorAddress]) { return false; } - isValid = IValidator(validatorAddress).isValidSignature( + isValid = isValidValidatorSignature( + validatorAddress, hash, signerAddress, signature @@ -258,4 +262,78 @@ contract MixinSignatureValidator is // signature was invalid.) revert("SIGNATURE_UNSUPPORTED"); } + + /// @dev Verifies signature using logic defined by Wallet contract. + /// @param hash Any 32 byte hash. + /// @param walletAddress Address that should have signed the given hash + /// and defines its own signature verification method. + /// @param signature Proof that the hash has been signed by signer. + /// @return True if signature is valid for given wallet.. + function isValidWalletSignature( + bytes32 hash, + address walletAddress, + bytes signature + ) + internal + view + returns (bool isValid) + { + bytes memory calldata = abi.encodeWithSelector( + IWallet(walletAddress).isValidSignature.selector, + hash, + signature + ); + assembly { + let cdStart := add(calldata, 32) + let success := staticcall( + gas, // forward all gas + walletAddress, // address of Wallet contract + cdStart, // pointer to start of input + mload(calldata), // length of input + cdStart, // write input over output + 32 // output size is 32 bytes + ) + // Signature is valid if call did not revert and returned true + isValid := and(success, mload(cdStart)) + } + return isValid; + } + + /// @dev Verifies signature using logic defined by Validator contract. + /// @param validatorAddress Address of validator contract. + /// @param hash Any 32 byte hash. + /// @param signerAddress Address that should have signed the given hash. + /// @param signature Proof that the hash has been signed by signer. + /// @return True if the address recovered from the provided signature matches the input signer address. + function isValidValidatorSignature( + address validatorAddress, + bytes32 hash, + address signerAddress, + bytes signature + ) + internal + view + returns (bool isValid) + { + bytes memory calldata = abi.encodeWithSelector( + IValidator(signerAddress).isValidSignature.selector, + hash, + signerAddress, + signature + ); + assembly { + let cdStart := add(calldata, 32) + let success := staticcall( + gas, // forward all gas + validatorAddress, // address of Validator contract + cdStart, // pointer to start of input + mload(calldata), // length of input + cdStart, // write input over output + 32 // output size is 32 bytes + ) + // Signature is valid if call did not revert and returned true + isValid := and(success, mload(cdStart)) + } + return isValid; + } } diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MSignatureValidator.sol b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MSignatureValidator.sol index f14f2ba004..75fe9ec46e 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MSignatureValidator.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MSignatureValidator.sol @@ -43,4 +43,35 @@ contract MSignatureValidator is Trezor, // 0x08 NSignatureTypes // 0x09, number of signature types. Always leave at end. } + + /// @dev Verifies signature using logic defined by Wallet contract. + /// @param hash Any 32 byte hash. + /// @param walletAddress Address that should have signed the given hash + /// and defines its own signature verification method. + /// @param signature Proof that the hash has been signed by signer. + /// @return True if the address recovered from the provided signature matches the input signer address. + function isValidWalletSignature( + bytes32 hash, + address walletAddress, + bytes signature + ) + internal + view + returns (bool isValid); + + /// @dev Verifies signature using logic defined by Validator contract. + /// @param validatorAddress Address of validator contract. + /// @param hash Any 32 byte hash. + /// @param signerAddress Address that should have signed the given hash. + /// @param signature Proof that the hash has been signed by signer. + /// @return True if the address recovered from the provided signature matches the input signer address. + function isValidValidatorSignature( + address validatorAddress, + bytes32 hash, + address signerAddress, + bytes signature + ) + internal + view + returns (bool isValid); } diff --git a/packages/contracts/src/2.0.0/test/TestSignatureValidator/TestSignatureValidator.sol b/packages/contracts/src/2.0.0/test/TestSignatureValidator/TestSignatureValidator.sol index 3845b7b9ed..e1a610469c 100644 --- a/packages/contracts/src/2.0.0/test/TestSignatureValidator/TestSignatureValidator.sol +++ b/packages/contracts/src/2.0.0/test/TestSignatureValidator/TestSignatureValidator.sol @@ -17,7 +17,6 @@ */ pragma solidity 0.4.24; -pragma experimental "v0.5.0"; import "../../protocol/Exchange/MixinSignatureValidator.sol"; import "../../protocol/Exchange/MixinTransactions.sol"; diff --git a/packages/contracts/src/2.0.0/test/TestStaticCall/TestStaticCall.sol b/packages/contracts/src/2.0.0/test/TestStaticCall/TestStaticCall.sol index be24e2f37e..5a9581f513 100644 --- a/packages/contracts/src/2.0.0/test/TestStaticCall/TestStaticCall.sol +++ b/packages/contracts/src/2.0.0/test/TestStaticCall/TestStaticCall.sol @@ -18,6 +18,8 @@ pragma solidity 0.4.24; +import "../../tokens/ERC20Token/IERC20Token.sol"; + contract TestStaticCall { @@ -55,6 +57,20 @@ contract TestStaticCall { return true; } + /// @dev Approves an ERC20 token to spend tokens from this address. + /// @param token Address of ERC20 token. + /// @param spender Address that will spend tokens. + /// @param value Amount of tokens spender is approved to spend. + function approveERC20( + address token, + address spender, + uint256 value + ) + external + { + IERC20Token(token).approve(spender, value); + } + /// @dev Increments state variable. function updateState() internal diff --git a/packages/contracts/test/exchange/core.ts b/packages/contracts/test/exchange/core.ts index bc2bad7495..d3f9b95aff 100644 --- a/packages/contracts/test/exchange/core.ts +++ b/packages/contracts/test/exchange/core.ts @@ -1,6 +1,6 @@ import { BlockchainLifecycle } from '@0xproject/dev-utils'; import { assetDataUtils, orderHashUtils } from '@0xproject/order-utils'; -import { RevertReason, SignedOrder } from '@0xproject/types'; +import { RevertReason, SignatureType, SignedOrder } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as chai from 'chai'; @@ -14,6 +14,7 @@ import { DummyNoReturnERC20TokenContract } from '../../generated_contract_wrappe import { ERC20ProxyContract } from '../../generated_contract_wrappers/erc20_proxy'; import { ERC721ProxyContract } from '../../generated_contract_wrappers/erc721_proxy'; import { ExchangeCancelEventArgs, ExchangeContract } from '../../generated_contract_wrappers/exchange'; +import { TestStaticCallContract } from '../../generated_contract_wrappers/test_static_call'; import { artifacts } from '../utils/artifacts'; import { expectTransactionFailedAsync } from '../utils/assertions'; import { getLatestBlockTimestampAsync, increaseTimeAndMineBlockAsync } from '../utils/block_timestamp'; @@ -44,6 +45,8 @@ describe('Exchange core', () => { let exchange: ExchangeContract; let erc20Proxy: ERC20ProxyContract; let erc721Proxy: ERC721ProxyContract; + let maliciousWallet: TestStaticCallContract; + let maliciousValidator: TestStaticCallContract; let signedOrder: SignedOrder; let erc20Balances: ERC20BalancesByOwner; @@ -109,6 +112,12 @@ describe('Exchange core', () => { constants.AWAIT_TRANSACTION_MINED_MS, ); + maliciousWallet = maliciousValidator = await TestStaticCallContract.deployFrom0xArtifactAsync( + artifacts.TestStaticCall, + provider, + txDefaults, + ); + defaultMakerAssetAddress = erc20TokenA.address; defaultTakerAssetAddress = erc20TokenB.address; @@ -161,6 +170,54 @@ describe('Exchange core', () => { RevertReason.OrderUnfillable, ); }); + + it('should revert if `isValidSignature` tries to update state when SignatureType=Wallet', async () => { + const maliciousMakerAddress = maliciousWallet.address; + await web3Wrapper.awaitTransactionSuccessAsync( + await erc20TokenA.setBalance.sendTransactionAsync( + maliciousMakerAddress, + constants.INITIAL_ERC20_BALANCE, + ), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await maliciousWallet.approveERC20.sendTransactionAsync( + erc20TokenA.address, + erc20Proxy.address, + constants.INITIAL_ERC20_ALLOWANCE, + ), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + signedOrder = await orderFactory.newSignedOrderAsync({ + makerAddress: maliciousMakerAddress, + makerFee: constants.ZERO_AMOUNT, + }); + signedOrder.signature = `0x0${SignatureType.Wallet}`; + await expectTransactionFailedAsync( + exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), + RevertReason.InvalidOrderSignature, + ); + }); + + it('should revert if `isValidSignature` tries to update state when SignatureType=Validator', async () => { + const isApproved = true; + await web3Wrapper.awaitTransactionSuccessAsync( + await exchange.setSignatureValidatorApproval.sendTransactionAsync( + maliciousValidator.address, + isApproved, + { from: makerAddress }, + ), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + signedOrder = await orderFactory.newSignedOrderAsync({ + makerAddress: maliciousValidator.address, + }); + signedOrder.signature = `${maliciousValidator.address}0${SignatureType.Validator}`; + await expectTransactionFailedAsync( + exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), + RevertReason.InvalidOrderSignature, + ); + }); }); describe('Testing exchange of ERC20 tokens with no return values', () => { diff --git a/packages/contracts/test/exchange/signature_validator.ts b/packages/contracts/test/exchange/signature_validator.ts index 0e2967bc7e..75656d992d 100644 --- a/packages/contracts/test/exchange/signature_validator.ts +++ b/packages/contracts/test/exchange/signature_validator.ts @@ -352,7 +352,7 @@ describe('MixinSignatureValidator', () => { expect(isValidSignature).to.be.false(); }); - it('should not allow `isValidSignature` to update state when SignatureType=Wallet', async () => { + it('should return false when `isValidSignature` attempts to update state and not allow state to be updated when SignatureType=Wallet', async () => { // Create EIP712 signature const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); const orderHashBuffer = ethUtil.toBuffer(orderHashHex); @@ -366,13 +366,12 @@ describe('MixinSignatureValidator', () => { ]); const signatureHex = ethUtil.bufferToHex(signature); // Validate signature - await expectContractCallFailedWithoutReasonAsync( - signatureValidator.publicIsValidSignature.callAsync( - orderHashHex, - maliciousWallet.address, - signatureHex, - ), + const isValid = await signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + maliciousWallet.address, + signatureHex, ); + expect(isValid).to.be.equal(false); }); it('should return true when SignatureType=Validator, signature is valid and validator is approved', async () => { @@ -405,15 +404,18 @@ describe('MixinSignatureValidator', () => { expect(isValidSignature).to.be.false(); }); - it('should not allow `isValidSignature` to update state when SignatureType=Validator', async () => { + it('should return false when `isValidSignature` attempts to update state and not allow state to be updated when SignatureType=Validator', async () => { const validatorAddress = ethUtil.toBuffer(`${maliciousValidator.address}`); const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`); const signature = Buffer.concat([validatorAddress, signatureType]); const signatureHex = ethUtil.bufferToHex(signature); const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - await expectContractCallFailedWithoutReasonAsync( - signatureValidator.publicIsValidSignature.callAsync(orderHashHex, signerAddress, signatureHex), + const isValid = await signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + maliciousValidator.address, + signatureHex, ); + expect(isValid).to.be.equal(false); }); it('should return false when SignatureType=Validator, signature is valid and validator is not approved', async () => { // Set approval of signature validator to false From 681ed822eca91085300e85e136ddcf4abd90495c Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Fri, 24 Aug 2018 09:24:33 -0700 Subject: [PATCH 017/120] Revert if undefined function called in AssetProxies --- .../2.0.0/protocol/AssetProxy/ERC20Proxy.sol | 3 +++ .../2.0.0/protocol/AssetProxy/ERC721Proxy.sol | 3 +++ .../contracts/test/asset_proxy/proxies.ts | 24 ++++++++++++++++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/contracts/src/2.0.0/protocol/AssetProxy/ERC20Proxy.sol b/packages/contracts/src/2.0.0/protocol/AssetProxy/ERC20Proxy.sol index b5cec6b641..004c3892d8 100644 --- a/packages/contracts/src/2.0.0/protocol/AssetProxy/ERC20Proxy.sol +++ b/packages/contracts/src/2.0.0/protocol/AssetProxy/ERC20Proxy.sol @@ -118,6 +118,9 @@ contract ERC20Proxy is mstore(96, 0) revert(0, 100) } + + // Revert if undefined function is called + revert(0, 0) } } diff --git a/packages/contracts/src/2.0.0/protocol/AssetProxy/ERC721Proxy.sol b/packages/contracts/src/2.0.0/protocol/AssetProxy/ERC721Proxy.sol index 6a70c9f607..9d0bc0f74d 100644 --- a/packages/contracts/src/2.0.0/protocol/AssetProxy/ERC721Proxy.sol +++ b/packages/contracts/src/2.0.0/protocol/AssetProxy/ERC721Proxy.sol @@ -152,6 +152,9 @@ contract ERC721Proxy is mstore(96, 0) revert(0, 100) } + + // Revert if undefined function is called + revert(0, 0) } } diff --git a/packages/contracts/test/asset_proxy/proxies.ts b/packages/contracts/test/asset_proxy/proxies.ts index 76a0202228..6031e554d6 100644 --- a/packages/contracts/test/asset_proxy/proxies.ts +++ b/packages/contracts/test/asset_proxy/proxies.ts @@ -12,7 +12,7 @@ import { ERC20ProxyContract } from '../../generated_contract_wrappers/erc20_prox import { ERC721ProxyContract } from '../../generated_contract_wrappers/erc721_proxy'; import { IAssetProxyContract } from '../../generated_contract_wrappers/i_asset_proxy'; import { artifacts } from '../utils/artifacts'; -import { expectTransactionFailedAsync } from '../utils/assertions'; +import { expectTransactionFailedAsync, expectTransactionFailedWithoutReasonAsync } from '../utils/assertions'; import { chaiSetup } from '../utils/chai_setup'; import { constants } from '../utils/constants'; import { ERC20Wrapper } from '../utils/erc20_wrapper'; @@ -99,6 +99,17 @@ describe('Asset Transfer Proxies', () => { await blockchainLifecycle.revertAsync(); }); describe('Transfer Proxy - ERC20', () => { + it('should revert if undefined function is called', async () => { + const undefinedSelector = '0x01020304'; + await expectTransactionFailedWithoutReasonAsync( + web3Wrapper.sendTransactionAsync({ + from: owner, + to: erc20Proxy.address, + value: constants.ZERO_AMOUNT, + data: undefinedSelector, + }), + ); + }); describe('transferFrom', () => { it('should successfully transfer tokens', async () => { // Construct ERC20 asset data @@ -219,6 +230,17 @@ describe('Asset Transfer Proxies', () => { }); describe('Transfer Proxy - ERC721', () => { + it('should revert if undefined function is called', async () => { + const undefinedSelector = '0x01020304'; + await expectTransactionFailedWithoutReasonAsync( + web3Wrapper.sendTransactionAsync({ + from: owner, + to: erc721Proxy.address, + value: constants.ZERO_AMOUNT, + data: undefinedSelector, + }), + ); + }); describe('transferFrom', () => { it('should successfully transfer tokens', async () => { // Construct ERC721 asset data From 070eff6f3a2f3775ef72248c3f345c05cd833798 Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Fri, 24 Aug 2018 09:27:29 -0700 Subject: [PATCH 018/120] Rename TestStaticCall => TestStaticCallReceiver --- packages/contracts/compiler.json | 2 +- packages/contracts/package.json | 2 +- .../TestStaticCallReceiver.sol} | 3 ++- packages/contracts/test/exchange/core.ts | 10 +++++----- .../contracts/test/exchange/signature_validator.ts | 10 +++++----- packages/contracts/test/utils/artifacts.ts | 4 ++-- 6 files changed, 16 insertions(+), 15 deletions(-) rename packages/contracts/src/2.0.0/test/{TestStaticCall/TestStaticCall.sol => TestStaticCallReceiver/TestStaticCallReceiver.sol} (96%) diff --git a/packages/contracts/compiler.json b/packages/contracts/compiler.json index 741614f2c3..27bb69a36d 100644 --- a/packages/contracts/compiler.json +++ b/packages/contracts/compiler.json @@ -47,7 +47,7 @@ "TestLibs", "TestExchangeInternals", "TestSignatureValidator", - "TestStaticCall", + "TestStaticCallReceiver", "TokenRegistry", "Validator", "Wallet", diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 6fd5a864bc..0ead2f43f8 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -34,7 +34,7 @@ }, "config": { "abis": - "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|DummyNoReturnERC20Token|ERC20Proxy|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|InvalidERC721Receiver|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|OrderValidator|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestExchangeInternals|TestLibBytes|TestLibs|TestSignatureValidator|TestStaticCall|Validator|Wallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json" + "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|DummyNoReturnERC20Token|ERC20Proxy|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|InvalidERC721Receiver|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|OrderValidator|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestExchangeInternals|TestLibBytes|TestLibs|TestSignatureValidator|TestStaticCallReceiver|Validator|Wallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json" }, "repository": { "type": "git", diff --git a/packages/contracts/src/2.0.0/test/TestStaticCall/TestStaticCall.sol b/packages/contracts/src/2.0.0/test/TestStaticCallReceiver/TestStaticCallReceiver.sol similarity index 96% rename from packages/contracts/src/2.0.0/test/TestStaticCall/TestStaticCall.sol rename to packages/contracts/src/2.0.0/test/TestStaticCallReceiver/TestStaticCallReceiver.sol index 5a9581f513..41aab01c8b 100644 --- a/packages/contracts/src/2.0.0/test/TestStaticCall/TestStaticCall.sol +++ b/packages/contracts/src/2.0.0/test/TestStaticCallReceiver/TestStaticCallReceiver.sol @@ -21,7 +21,8 @@ pragma solidity 0.4.24; import "../../tokens/ERC20Token/IERC20Token.sol"; -contract TestStaticCall { +// solhint-disable no-unused-vars +contract TestStaticCallReceiver { uint256 internal state = 1; diff --git a/packages/contracts/test/exchange/core.ts b/packages/contracts/test/exchange/core.ts index d3f9b95aff..fdfb401559 100644 --- a/packages/contracts/test/exchange/core.ts +++ b/packages/contracts/test/exchange/core.ts @@ -14,7 +14,7 @@ import { DummyNoReturnERC20TokenContract } from '../../generated_contract_wrappe import { ERC20ProxyContract } from '../../generated_contract_wrappers/erc20_proxy'; import { ERC721ProxyContract } from '../../generated_contract_wrappers/erc721_proxy'; import { ExchangeCancelEventArgs, ExchangeContract } from '../../generated_contract_wrappers/exchange'; -import { TestStaticCallContract } from '../../generated_contract_wrappers/test_static_call'; +import { TestStaticCallReceiverContract } from '../../generated_contract_wrappers/test_static_call_receiver'; import { artifacts } from '../utils/artifacts'; import { expectTransactionFailedAsync } from '../utils/assertions'; import { getLatestBlockTimestampAsync, increaseTimeAndMineBlockAsync } from '../utils/block_timestamp'; @@ -45,8 +45,8 @@ describe('Exchange core', () => { let exchange: ExchangeContract; let erc20Proxy: ERC20ProxyContract; let erc721Proxy: ERC721ProxyContract; - let maliciousWallet: TestStaticCallContract; - let maliciousValidator: TestStaticCallContract; + let maliciousWallet: TestStaticCallReceiverContract; + let maliciousValidator: TestStaticCallReceiverContract; let signedOrder: SignedOrder; let erc20Balances: ERC20BalancesByOwner; @@ -112,8 +112,8 @@ describe('Exchange core', () => { constants.AWAIT_TRANSACTION_MINED_MS, ); - maliciousWallet = maliciousValidator = await TestStaticCallContract.deployFrom0xArtifactAsync( - artifacts.TestStaticCall, + maliciousWallet = maliciousValidator = await TestStaticCallReceiverContract.deployFrom0xArtifactAsync( + artifacts.TestStaticCallReceiver, provider, txDefaults, ); diff --git a/packages/contracts/test/exchange/signature_validator.ts b/packages/contracts/test/exchange/signature_validator.ts index 75656d992d..947ebffccb 100644 --- a/packages/contracts/test/exchange/signature_validator.ts +++ b/packages/contracts/test/exchange/signature_validator.ts @@ -9,7 +9,7 @@ import { TestSignatureValidatorContract, TestSignatureValidatorSignatureValidatorApprovalEventArgs, } from '../../generated_contract_wrappers/test_signature_validator'; -import { TestStaticCallContract } from '../../generated_contract_wrappers/test_static_call'; +import { TestStaticCallReceiverContract } from '../../generated_contract_wrappers/test_static_call_receiver'; import { ValidatorContract } from '../../generated_contract_wrappers/validator'; import { WalletContract } from '../../generated_contract_wrappers/wallet'; import { addressUtils } from '../utils/address_utils'; @@ -32,8 +32,8 @@ describe('MixinSignatureValidator', () => { let signatureValidator: TestSignatureValidatorContract; let testWallet: WalletContract; let testValidator: ValidatorContract; - let maliciousWallet: TestStaticCallContract; - let maliciousValidator: TestStaticCallContract; + let maliciousWallet: TestStaticCallReceiverContract; + let maliciousValidator: TestStaticCallReceiverContract; let signerAddress: string; let signerPrivateKey: Buffer; let notSignerAddress: string; @@ -68,8 +68,8 @@ describe('MixinSignatureValidator', () => { txDefaults, signerAddress, ); - maliciousWallet = maliciousValidator = await TestStaticCallContract.deployFrom0xArtifactAsync( - artifacts.TestStaticCall, + maliciousWallet = maliciousValidator = await TestStaticCallReceiverContract.deployFrom0xArtifactAsync( + artifacts.TestStaticCallReceiver, provider, txDefaults, ); diff --git a/packages/contracts/test/utils/artifacts.ts b/packages/contracts/test/utils/artifacts.ts index 1c922a3e48..2f6fcef719 100644 --- a/packages/contracts/test/utils/artifacts.ts +++ b/packages/contracts/test/utils/artifacts.ts @@ -23,7 +23,7 @@ import * as TestExchangeInternals from '../../artifacts/TestExchangeInternals.js import * as TestLibBytes from '../../artifacts/TestLibBytes.json'; import * as TestLibs from '../../artifacts/TestLibs.json'; import * as TestSignatureValidator from '../../artifacts/TestSignatureValidator.json'; -import * as TestStaticCall from '../../artifacts/TestStaticCall.json'; +import * as TestStaticCallReceiver from '../../artifacts/TestStaticCallReceiver.json'; import * as TokenRegistry from '../../artifacts/TokenRegistry.json'; import * as Validator from '../../artifacts/Validator.json'; import * as Wallet from '../../artifacts/Wallet.json'; @@ -56,7 +56,7 @@ export const artifacts = { TestLibs: (TestLibs as any) as ContractArtifact, TestExchangeInternals: (TestExchangeInternals as any) as ContractArtifact, TestSignatureValidator: (TestSignatureValidator as any) as ContractArtifact, - TestStaticCall: (TestStaticCall as any) as ContractArtifact, + TestStaticCallReceiver: (TestStaticCallReceiver as any) as ContractArtifact, Validator: (Validator as any) as ContractArtifact, Wallet: (Wallet as any) as ContractArtifact, TokenRegistry: (TokenRegistry as any) as ContractArtifact, From 92497d7df4b61ee62acfdd58bfb98569ff67214e Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Thu, 23 Aug 2018 11:01:52 -0700 Subject: [PATCH 019/120] Fix isRoundingError --- .../2.0.0/protocol/Exchange/libs/LibMath.sol | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol index fa09da6ac1..146bb99432 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol @@ -46,7 +46,7 @@ contract LibMath is return partialAmount; } - /// @dev Checks if rounding error > 0.1%. + /// @dev Checks if rounding error >= 0.1%. /// @param numerator Numerator. /// @param denominator Denominator. /// @param target Value to multiply with numerator/denominator. @@ -60,16 +60,23 @@ contract LibMath is pure returns (bool isError) { + // The absolute rounding error is the difference between the rounded + // value and the ideal value. The relative rounding error is the + // absolute rounding error divided by the absolute value of the + // ideal value. We want the relative rounding error to be strictly less + // than 0.1%. + // Let's call `numerator * target % denominator` the remainder. + // The ideal value is `numerator * target / denominator`. + // The absolute error is `remainder / denominator`. + // The relative error is `remainder / numerator * target`. + // We want the relative error less than 1 / 1000: + // remainder / numerator * denominator < 1 / 1000 + // or equivalently: + // 1000 * remainder < numerator * target + // so we have a rounding error iff: + // 1000 * remainder >= numerator * target uint256 remainder = mulmod(target, numerator, denominator); - if (remainder == 0) { - return false; // No rounding error. - } - - uint256 errPercentageTimes1000000 = safeDiv( - safeMul(remainder, 1000000), - safeMul(numerator, target) - ); - isError = errPercentageTimes1000000 > 1000; + isError = safeMul(1000, remainder) >= safeMul(numerator, target); return isError; } } From 4159e45aff14c04f2d799ec8a7b6e7f1a4894064 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Thu, 23 Aug 2018 12:54:13 -0700 Subject: [PATCH 020/120] Update tests --- packages/contracts/test/exchange/internal.ts | 26 +++++++++++--------- packages/contracts/test/exchange/libs.ts | 4 +-- packages/types/src/index.ts | 1 + 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/packages/contracts/test/exchange/internal.ts b/packages/contracts/test/exchange/internal.ts index 67d1d2d2cb..0231cc3f12 100644 --- a/packages/contracts/test/exchange/internal.ts +++ b/packages/contracts/test/exchange/internal.ts @@ -63,6 +63,7 @@ describe('Exchange core internal functions', () => { let testExchange: TestExchangeInternalsContract; let invalidOpcodeErrorForCall: Error | undefined; let overflowErrorForSendTransaction: Error | undefined; + let divisionByZeroErrorForCall: Error | undefined; before(async () => { await blockchainLifecycle.startAsync(); @@ -79,6 +80,9 @@ describe('Exchange core internal functions', () => { overflowErrorForSendTransaction = new Error( await getRevertReasonOrErrorMessageForSendTransactionAsync(RevertReason.Uint256Overflow), ); + divisionByZeroErrorForCall = new Error( + await getRevertReasonOrErrorMessageForSendTransactionAsync(RevertReason.DivisionByZero), + ); invalidOpcodeErrorForCall = new Error(await getInvalidOpcodeErrorMessageForCallAsync()); }); // Note(albrow): Don't forget to add beforeEach and afterEach calls to reset @@ -215,26 +219,26 @@ describe('Exchange core internal functions', () => { denominator: BigNumber, target: BigNumber, ): Promise { - const product = numerator.mul(target); if (denominator.eq(0)) { - throw invalidOpcodeErrorForCall; + throw divisionByZeroErrorForCall; } - const remainder = product.mod(denominator); - if (remainder.eq(0)) { + if (numerator.eq(0)) { return false; } + if (target.eq(0)) { + return false; + } + const product = numerator.mul(target); + const remainder = product.mod(denominator); + const remainderTimes1000 = remainder.mul('1000'); + const isError = remainderTimes1000.gt(product); if (product.greaterThan(MAX_UINT256)) { throw overflowErrorForCall; } - if (product.eq(0)) { - throw invalidOpcodeErrorForCall; - } - const remainderTimes1000000 = remainder.mul('1000000'); - if (remainderTimes1000000.greaterThan(MAX_UINT256)) { + if (remainderTimes1000.greaterThan(MAX_UINT256)) { throw overflowErrorForCall; } - const errPercentageTimes1000000 = remainderTimes1000000.dividedToIntegerBy(product); - return errPercentageTimes1000000.greaterThan('1000'); + return isError; } async function testIsRoundingErrorAsync( numerator: BigNumber, diff --git a/packages/contracts/test/exchange/libs.ts b/packages/contracts/test/exchange/libs.ts index 6c3305d1d5..c08d62758f 100644 --- a/packages/contracts/test/exchange/libs.ts +++ b/packages/contracts/test/exchange/libs.ts @@ -71,13 +71,13 @@ describe('Exchange libs', () => { // combinatorial tests in test/exchange/internal. They test specific edge // cases that are not covered by the combinatorial tests. describe('LibMath', () => { - it('should return false if there is a rounding error of 0.1%', async () => { + it('should return true if there is a rounding error of 0.1%', async () => { const numerator = new BigNumber(20); const denominator = new BigNumber(999); const target = new BigNumber(50); // rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1% const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target); - expect(isRoundingError).to.be.false(); + expect(isRoundingError).to.be.true(); }); it('should return false if there is a rounding of 0.09%', async () => { const numerator = new BigNumber(20); diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 298fa77d41..2353c0807f 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -175,6 +175,7 @@ export enum RevertReason { InvalidSender = 'INVALID_SENDER', InvalidOrderSignature = 'INVALID_ORDER_SIGNATURE', InvalidTakerAmount = 'INVALID_TAKER_AMOUNT', + DivisionByZero = 'DIVISION_BY_ZERO', RoundingError = 'ROUNDING_ERROR', InvalidSignature = 'INVALID_SIGNATURE', SignatureIllegal = 'SIGNATURE_ILLEGAL', From e68942ee78eb19c27a96fb0b6b8b05c83b647bcc Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Thu, 23 Aug 2018 12:54:39 -0700 Subject: [PATCH 021/120] Handle zero case --- .../2.0.0/protocol/Exchange/libs/LibMath.sol | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol index 146bb99432..758b7ec908 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol @@ -60,14 +60,26 @@ contract LibMath is pure returns (bool isError) { + require(denominator > 0, "DIVISION_BY_ZERO"); + // The absolute rounding error is the difference between the rounded // value and the ideal value. The relative rounding error is the // absolute rounding error divided by the absolute value of the - // ideal value. We want the relative rounding error to be strictly less - // than 0.1%. - // Let's call `numerator * target % denominator` the remainder. + // ideal value. This is undefined when the ideal value is zero. + // // The ideal value is `numerator * target / denominator`. + // Let's call `numerator * target % denominator` the remainder. // The absolute error is `remainder / denominator`. + // + // When the ideal value is zero, we require the absolute error to + // be zero. Fortunately, this is always the case. The ideal value is + // zero iff `numerator == 0` and/or `target == 0`. In this case the + // remainder and absolute error are also zero. + if (target == 0 || numerator == 0) { + return false; + } + // Otherwise, we want the relative rounding error to be strictly + // less than 0.1%. // The relative error is `remainder / numerator * target`. // We want the relative error less than 1 / 1000: // remainder / numerator * denominator < 1 / 1000 From 6a9669a409a61c4645af43f39a4e4a0761354e32 Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Fri, 24 Aug 2018 14:06:46 -0700 Subject: [PATCH 022/120] Rethrow Wallet and Validator errors --- .../Exchange/MixinSignatureValidator.sol | 32 ++++++++++++++++--- packages/contracts/test/exchange/core.ts | 7 ++-- .../test/exchange/signature_validator.ts | 25 +++++++-------- packages/types/CHANGELOG.json | 9 ++++++ packages/types/src/index.ts | 2 ++ 5 files changed, 53 insertions(+), 22 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol index 6bfbb51076..017da742ee 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol @@ -293,8 +293,20 @@ contract MixinSignatureValidator is cdStart, // write input over output 32 // output size is 32 bytes ) - // Signature is valid if call did not revert and returned true - isValid := and(success, mload(cdStart)) + + switch success + case 0 { + // Revert with `Error("WALLET_ERROR")` + mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) + mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) + mstore(64, 0x0000000c57414c4c45545f4552524f5200000000000000000000000000000000) + mstore(96, 0) + revert(0, 100) + } + case 1 { + // Signature is valid if call did not revert and returned true + isValid := mload(cdStart) + } } return isValid; } @@ -331,8 +343,20 @@ contract MixinSignatureValidator is cdStart, // write input over output 32 // output size is 32 bytes ) - // Signature is valid if call did not revert and returned true - isValid := and(success, mload(cdStart)) + + switch success + case 0 { + // Revert with `Error("VALIDATOR_ERROR")` + mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000) + mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000) + mstore(64, 0x0000000f56414c494441544f525f4552524f5200000000000000000000000000) + mstore(96, 0) + revert(0, 100) + } + case 1 { + // Signature is valid if call did not revert and returned true + isValid := mload(cdStart) + } } return isValid; } diff --git a/packages/contracts/test/exchange/core.ts b/packages/contracts/test/exchange/core.ts index fdfb401559..f9d8b77830 100644 --- a/packages/contracts/test/exchange/core.ts +++ b/packages/contracts/test/exchange/core.ts @@ -195,7 +195,7 @@ describe('Exchange core', () => { signedOrder.signature = `0x0${SignatureType.Wallet}`; await expectTransactionFailedAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), - RevertReason.InvalidOrderSignature, + RevertReason.WalletError, ); }); @@ -209,13 +209,10 @@ describe('Exchange core', () => { ), constants.AWAIT_TRANSACTION_MINED_MS, ); - signedOrder = await orderFactory.newSignedOrderAsync({ - makerAddress: maliciousValidator.address, - }); signedOrder.signature = `${maliciousValidator.address}0${SignatureType.Validator}`; await expectTransactionFailedAsync( exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), - RevertReason.InvalidOrderSignature, + RevertReason.ValidatorError, ); }); }); diff --git a/packages/contracts/test/exchange/signature_validator.ts b/packages/contracts/test/exchange/signature_validator.ts index 947ebffccb..5b64d853c4 100644 --- a/packages/contracts/test/exchange/signature_validator.ts +++ b/packages/contracts/test/exchange/signature_validator.ts @@ -352,7 +352,7 @@ describe('MixinSignatureValidator', () => { expect(isValidSignature).to.be.false(); }); - it('should return false when `isValidSignature` attempts to update state and not allow state to be updated when SignatureType=Wallet', async () => { + it('should revert when `isValidSignature` attempts to update state and SignatureType=Wallet', async () => { // Create EIP712 signature const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); const orderHashBuffer = ethUtil.toBuffer(orderHashHex); @@ -365,13 +365,14 @@ describe('MixinSignatureValidator', () => { ethUtil.toBuffer(`0x${SignatureType.Wallet}`), ]); const signatureHex = ethUtil.bufferToHex(signature); - // Validate signature - const isValid = await signatureValidator.publicIsValidSignature.callAsync( - orderHashHex, - maliciousWallet.address, - signatureHex, + await expectContractCallFailed( + signatureValidator.publicIsValidSignature.callAsync( + orderHashHex, + maliciousWallet.address, + signatureHex, + ), + RevertReason.WalletError, ); - expect(isValid).to.be.equal(false); }); it('should return true when SignatureType=Validator, signature is valid and validator is approved', async () => { @@ -404,18 +405,16 @@ describe('MixinSignatureValidator', () => { expect(isValidSignature).to.be.false(); }); - it('should return false when `isValidSignature` attempts to update state and not allow state to be updated when SignatureType=Validator', async () => { + it('should revert when `isValidSignature` attempts to update state and SignatureType=Validator', async () => { const validatorAddress = ethUtil.toBuffer(`${maliciousValidator.address}`); const signatureType = ethUtil.toBuffer(`0x${SignatureType.Validator}`); const signature = Buffer.concat([validatorAddress, signatureType]); const signatureHex = ethUtil.bufferToHex(signature); const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - const isValid = await signatureValidator.publicIsValidSignature.callAsync( - orderHashHex, - maliciousValidator.address, - signatureHex, + await expectContractCallFailed( + signatureValidator.publicIsValidSignature.callAsync(orderHashHex, signerAddress, signatureHex), + RevertReason.ValidatorError, ); - expect(isValid).to.be.equal(false); }); it('should return false when SignatureType=Validator, signature is valid and validator is not approved', async () => { // Set approval of signature validator to false diff --git a/packages/types/CHANGELOG.json b/packages/types/CHANGELOG.json index fabc80ecfc..980a12ad33 100644 --- a/packages/types/CHANGELOG.json +++ b/packages/types/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "1.0.1-rc.6", + "changes": [ + { + "note": "Add WalletError and ValidatorError revert reasons", + "pr": 1012 + } + ] + }, { "version": "1.0.1-rc.5", "changes": [ diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 298fa77d41..2831d816df 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -220,6 +220,8 @@ export enum RevertReason { Erc721InvalidSpender = 'ERC721_INVALID_SPENDER', Erc721ZeroOwner = 'ERC721_ZERO_OWNER', Erc721InvalidSelector = 'ERC721_INVALID_SELECTOR', + WalletError = 'WALLET_ERROR', + ValidatorError = 'VALIDATOR_ERROR', } export enum StatusCodes { From ab5df342e1dc4add20223fab7128f9323a114b8e Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Wed, 22 Aug 2018 12:22:49 -0700 Subject: [PATCH 023/120] Add getPartialAmountCeil --- .../2.0.0/protocol/Exchange/libs/LibMath.sol | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol index 758b7ec908..3e70d1b60e 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol @@ -29,7 +29,7 @@ contract LibMath is /// @param numerator Numerator. /// @param denominator Denominator. /// @param target Value to calculate partial of. - /// @return Partial value of target. + /// @return Partial value of target rounded down. function getPartialAmount( uint256 numerator, uint256 denominator, @@ -45,8 +45,37 @@ contract LibMath is ); return partialAmount; } - - /// @dev Checks if rounding error >= 0.1%. + + /// @dev Calculates partial value given a numerator and denominator. + /// @param numerator Numerator. + /// @param denominator Denominator. + /// @param target Value to calculate partial of. + /// @return Partial value of target rounded up. + function getPartialAmountCeil( + uint256 numerator, + uint256 denominator, + uint256 target + ) + internal + pure + returns (uint256 partialAmount) + { + require( + denominator > 0, + "DIVISION_BY_ZERO" + ); + + // SafeDiv rounds down. To use it to round up we need to add + // denominator - 1. This causes anything less than an exact multiple + // of denominator to be rounded up. + partialAmount = safeDiv( + safeAdd(safeMul(numerator, target), safeSub(denominator, 1)), + denominator + ); + return partialAmount; + } + + /// @dev Checks if rounding error > 0.1%. /// @param numerator Numerator. /// @param denominator Denominator. /// @param target Value to multiply with numerator/denominator. From 5d70df771b151800b8a04b5569529843701c9fbd Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Wed, 22 Aug 2018 12:22:58 -0700 Subject: [PATCH 024/120] Add isRoundingErrorCeil --- .../2.0.0/protocol/Exchange/libs/LibMath.sol | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol index 3e70d1b60e..c4aa2abb54 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol @@ -107,6 +107,7 @@ contract LibMath is if (target == 0 || numerator == 0) { return false; } + // Otherwise, we want the relative rounding error to be strictly // less than 0.1%. // The relative error is `remainder / numerator * target`. @@ -120,4 +121,32 @@ contract LibMath is isError = safeMul(1000, remainder) >= safeMul(numerator, target); return isError; } + + /// @dev Checks if rounding error > 0.1%. + /// @param numerator Numerator. + /// @param denominator Denominator. + /// @param target Value to multiply with numerator/denominator. + /// @return Rounding error is present. + function isRoundingErrorCeil( + uint256 numerator, + uint256 denominator, + uint256 target + ) + internal + pure + returns (bool isError) + { + require(denominator > 0, "DIVISION_BY_ZERO"); + + if (target == 0 || numerator == 0) { + return false; + } + uint256 remainder = mulmod(target, numerator, denominator); + if (remainder == 0) { + return false; + } + remainder = safeSub(denominator, remainder); + isError = safeMul(1000, remainder) >= safeMul(numerator, target); + return isError; + } } From 3dad6ee55e9f51daa66cfe3c83dd17abc31f23f5 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Wed, 22 Aug 2018 12:23:32 -0700 Subject: [PATCH 025/120] Add tests for getPartialAmountCeil --- .../TestExchangeInternals.sol | 17 ++++++++ packages/contracts/test/exchange/internal.ts | 40 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/packages/contracts/src/2.0.0/test/TestExchangeInternals/TestExchangeInternals.sol b/packages/contracts/src/2.0.0/test/TestExchangeInternals/TestExchangeInternals.sol index d9cec9edcf..239dd10a87 100644 --- a/packages/contracts/src/2.0.0/test/TestExchangeInternals/TestExchangeInternals.sol +++ b/packages/contracts/src/2.0.0/test/TestExchangeInternals/TestExchangeInternals.sol @@ -79,6 +79,23 @@ contract TestExchangeInternals is return getPartialAmount(numerator, denominator, target); } + /// @dev Calculates partial value given a numerator and denominator. + /// @param numerator Numerator. + /// @param denominator Denominator. + /// @param target Value to calculate partial of. + /// @return Partial value of target. + function publicGetPartialAmountCeil( + uint256 numerator, + uint256 denominator, + uint256 target + ) + public + pure + returns (uint256 partialAmount) + { + return getPartialAmountCeil(numerator, denominator, target); + } + /// @dev Checks if rounding error > 0.1%. /// @param numerator Numerator. /// @param denominator Denominator. diff --git a/packages/contracts/test/exchange/internal.ts b/packages/contracts/test/exchange/internal.ts index 0231cc3f12..69625ee1d3 100644 --- a/packages/contracts/test/exchange/internal.ts +++ b/packages/contracts/test/exchange/internal.ts @@ -1,6 +1,7 @@ import { BlockchainLifecycle } from '@0xproject/dev-utils'; import { Order, RevertReason, SignedOrder } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; +import * as chai from 'chai'; import * as _ from 'lodash'; import { TestExchangeInternalsContract } from '../../generated_contract_wrappers/test_exchange_internals'; @@ -16,6 +17,8 @@ import { FillResults } from '../utils/types'; import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; chaiSetup.configure(); +const expect = chai.expect; + const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); const MAX_UINT256 = new BigNumber(2).pow(256).minus(1); @@ -213,6 +216,43 @@ describe('Exchange core internal functions', () => { ); }); + describe.only('getPartialAmountCeil', async () => { + async function referenceGetPartialAmountCeilAsync( + numerator: BigNumber, + denominator: BigNumber, + target: BigNumber, + ) { + if (denominator.eq(0)) { + throw new Error('revert DIVISION_BY_ZERO'); + } + const product = numerator.mul(target); + const offset = product.add(denominator.sub(1)); + if (offset.greaterThan(MAX_UINT256)) { + throw overflowErrorForCall; + } + const result = offset.dividedToIntegerBy(denominator); + if (product.mod(denominator).eq(0)) { + expect(result.mul(denominator)).to.be.bignumber.eq(product); + } else { + expect(result.mul(denominator)).to.be.bignumber.gt(product); + } + return result; + } + async function testGetPartialAmountCeilAsync( + numerator: BigNumber, + denominator: BigNumber, + target: BigNumber, + ): Promise { + return testExchange.publicGetPartialAmountCeil.callAsync(numerator, denominator, target); + } + await testCombinatoriallyWithReferenceFuncAsync( + 'getPartialAmountCeil', + referenceGetPartialAmountCeilAsync, + testGetPartialAmountCeilAsync, + [uint256Values, uint256Values, uint256Values], + ); + }); + describe('isRoundingError', async () => { async function referenceIsRoundingErrorAsync( numerator: BigNumber, From 50fab9feb3b80b7d5ac1e94df9af68cad4aaabe0 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Wed, 22 Aug 2018 12:22:58 -0700 Subject: [PATCH 026/120] Improve getPartialAmountCeil docs --- .../contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol index c4aa2abb54..d123c55a13 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol @@ -65,9 +65,9 @@ contract LibMath is "DIVISION_BY_ZERO" ); - // SafeDiv rounds down. To use it to round up we need to add - // denominator - 1. This causes anything less than an exact multiple - // of denominator to be rounded up. + // safeDiv computes `floor(a / b)`. We use the identity (a, b integer): + // ceil(a / b) = floor((a + b - 1) / b) + // To implement `ceil(a / b)` using safeDiv. partialAmount = safeDiv( safeAdd(safeMul(numerator, target), safeSub(denominator, 1)), denominator From c109d1f5451c43afd92dd0fb4bebb48cba65c661 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Thu, 23 Aug 2018 13:33:05 -0700 Subject: [PATCH 027/120] Remove .only --- packages/contracts/test/exchange/internal.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contracts/test/exchange/internal.ts b/packages/contracts/test/exchange/internal.ts index 69625ee1d3..2f25b17084 100644 --- a/packages/contracts/test/exchange/internal.ts +++ b/packages/contracts/test/exchange/internal.ts @@ -216,7 +216,7 @@ describe('Exchange core internal functions', () => { ); }); - describe.only('getPartialAmountCeil', async () => { + describe('getPartialAmountCeil', async () => { async function referenceGetPartialAmountCeilAsync( numerator: BigNumber, denominator: BigNumber, From 4219af1430f1cfc105d3521616941b7947fde4e3 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Thu, 23 Aug 2018 14:22:59 -0700 Subject: [PATCH 028/120] Add DIVISION_BY_ZERO to getPartialAmount for consistency --- .../2.0.0/protocol/Exchange/libs/LibMath.sol | 7 ++--- packages/contracts/test/exchange/internal.ts | 31 +++++++++---------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol index d123c55a13..f4e2f19582 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol @@ -39,6 +39,8 @@ contract LibMath is pure returns (uint256 partialAmount) { + require(denominator > 0, "DIVISION_BY_ZERO"); + partialAmount = safeDiv( safeMul(numerator, target), denominator @@ -60,10 +62,7 @@ contract LibMath is pure returns (uint256 partialAmount) { - require( - denominator > 0, - "DIVISION_BY_ZERO" - ); + require(denominator > 0, "DIVISION_BY_ZERO"); // safeDiv computes `floor(a / b)`. We use the identity (a, b integer): // ceil(a / b) = floor((a + b - 1) / b) diff --git a/packages/contracts/test/exchange/internal.ts b/packages/contracts/test/exchange/internal.ts index 2f25b17084..48e1e620c9 100644 --- a/packages/contracts/test/exchange/internal.ts +++ b/packages/contracts/test/exchange/internal.ts @@ -46,22 +46,6 @@ const emptySignedOrder: SignedOrder = { const overflowErrorForCall = new Error(RevertReason.Uint256Overflow); -async function referenceGetPartialAmountAsync( - numerator: BigNumber, - denominator: BigNumber, - target: BigNumber, -): Promise { - const invalidOpcodeErrorForCall = new Error(await getInvalidOpcodeErrorMessageForCallAsync()); - const product = numerator.mul(target); - if (product.greaterThan(MAX_UINT256)) { - throw overflowErrorForCall; - } - if (denominator.eq(0)) { - throw invalidOpcodeErrorForCall; - } - return product.dividedToIntegerBy(denominator); -} - describe('Exchange core internal functions', () => { let testExchange: TestExchangeInternalsContract; let invalidOpcodeErrorForCall: Error | undefined; @@ -91,6 +75,21 @@ describe('Exchange core internal functions', () => { // Note(albrow): Don't forget to add beforeEach and afterEach calls to reset // the blockchain state for any tests which modify it! + async function referenceGetPartialAmountAsync( + numerator: BigNumber, + denominator: BigNumber, + target: BigNumber, + ): Promise { + if (denominator.eq(0)) { + throw divisionByZeroErrorForCall; + } + const product = numerator.mul(target); + if (product.greaterThan(MAX_UINT256)) { + throw overflowErrorForCall; + } + return product.dividedToIntegerBy(denominator); + } + describe('addFillResults', async () => { function makeFillResults(value: BigNumber): FillResults { return { From 0fb7617a785b765415cb7f43448c9b8ea905963f Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Thu, 23 Aug 2018 15:18:45 -0700 Subject: [PATCH 029/120] Fix incorect modulus --- .../contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol index f4e2f19582..1c14dbcaef 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol @@ -141,10 +141,8 @@ contract LibMath is return false; } uint256 remainder = mulmod(target, numerator, denominator); - if (remainder == 0) { - return false; - } - remainder = safeSub(denominator, remainder); + // TODO: safeMod + remainder = safeSub(denominator, remainder) % denominator; isError = safeMul(1000, remainder) >= safeMul(numerator, target); return isError; } From 6734f2f1bcdab8f0d50524a26195707da00bd8ed Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Thu, 23 Aug 2018 15:18:55 -0700 Subject: [PATCH 030/120] Add docs --- .../src/2.0.0/protocol/Exchange/libs/LibMath.sol | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol index 1c14dbcaef..8a1444af13 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol @@ -74,7 +74,7 @@ contract LibMath is return partialAmount; } - /// @dev Checks if rounding error > 0.1%. + /// @dev Checks if rounding error >= 0.1% when rounding down. /// @param numerator Numerator. /// @param denominator Denominator. /// @param target Value to multiply with numerator/denominator. @@ -121,7 +121,7 @@ contract LibMath is return isError; } - /// @dev Checks if rounding error > 0.1%. + /// @dev Checks if rounding error >= 0.1% when rounding up. /// @param numerator Numerator. /// @param denominator Denominator. /// @param target Value to multiply with numerator/denominator. @@ -137,9 +137,14 @@ contract LibMath is { require(denominator > 0, "DIVISION_BY_ZERO"); + // See the comments in `isRoundingError`. if (target == 0 || numerator == 0) { + // When either is zero, the ideal value and rounded value are zero + // and there is no rounding error. (Although the relative error + // is undefined.) return false; } + // Compute remainder as before uint256 remainder = mulmod(target, numerator, denominator); // TODO: safeMod remainder = safeSub(denominator, remainder) % denominator; From 7f78d7da9dd13d1f0068a292bcd1ee3c5439d5a8 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Thu, 23 Aug 2018 15:19:29 -0700 Subject: [PATCH 031/120] Add tests --- .../TestExchangeInternals.sol | 19 ++++- .../src/2.0.0/test/TestLibs/TestLibs.sol | 34 +++++++++ packages/contracts/test/exchange/internal.ts | 43 +++++++++++ packages/contracts/test/exchange/libs.ts | 72 +++++++++++++------ 4 files changed, 145 insertions(+), 23 deletions(-) diff --git a/packages/contracts/src/2.0.0/test/TestExchangeInternals/TestExchangeInternals.sol b/packages/contracts/src/2.0.0/test/TestExchangeInternals/TestExchangeInternals.sol index 239dd10a87..5e2ae2f0ed 100644 --- a/packages/contracts/src/2.0.0/test/TestExchangeInternals/TestExchangeInternals.sol +++ b/packages/contracts/src/2.0.0/test/TestExchangeInternals/TestExchangeInternals.sol @@ -96,7 +96,7 @@ contract TestExchangeInternals is return getPartialAmountCeil(numerator, denominator, target); } - /// @dev Checks if rounding error > 0.1%. + /// @dev Checks if rounding error >= 0.1%. /// @param numerator Numerator. /// @param denominator Denominator. /// @param target Value to multiply with numerator/denominator. @@ -112,6 +112,23 @@ contract TestExchangeInternals is { return isRoundingError(numerator, denominator, target); } + + /// @dev Checks if rounding error >= 0.1%. + /// @param numerator Numerator. + /// @param denominator Denominator. + /// @param target Value to multiply with numerator/denominator. + /// @return Rounding error is present. + function publicIsRoundingErrorCeil( + uint256 numerator, + uint256 denominator, + uint256 target + ) + public + pure + returns (bool isError) + { + return isRoundingErrorCeil(numerator, denominator, target); + } /// @dev Updates state with results of a fill order. /// @param order that was filled. diff --git a/packages/contracts/src/2.0.0/test/TestLibs/TestLibs.sol b/packages/contracts/src/2.0.0/test/TestLibs/TestLibs.sol index 4a99dd9c18..8c3d122266 100644 --- a/packages/contracts/src/2.0.0/test/TestLibs/TestLibs.sol +++ b/packages/contracts/src/2.0.0/test/TestLibs/TestLibs.sol @@ -66,6 +66,23 @@ contract TestLibs is return partialAmount; } + function publicGetPartialAmountCeil( + uint256 numerator, + uint256 denominator, + uint256 target + ) + public + pure + returns (uint256 partialAmount) + { + partialAmount = getPartialAmountCeil( + numerator, + denominator, + target + ); + return partialAmount; + } + function publicIsRoundingError( uint256 numerator, uint256 denominator, @@ -83,6 +100,23 @@ contract TestLibs is return isError; } + function publicIsRoundingErrorCeil( + uint256 numerator, + uint256 denominator, + uint256 target + ) + public + pure + returns (bool isError) + { + isError = isRoundingErrorCeil( + numerator, + denominator, + target + ); + return isError; + } + function publicGetOrderHash(Order memory order) public view diff --git a/packages/contracts/test/exchange/internal.ts b/packages/contracts/test/exchange/internal.ts index 48e1e620c9..0c6ab3707c 100644 --- a/packages/contracts/test/exchange/internal.ts +++ b/packages/contracts/test/exchange/internal.ts @@ -294,6 +294,49 @@ describe('Exchange core internal functions', () => { ); }); + describe('isRoundingErrorCeil', async () => { + async function referenceIsRoundingErrorAsync( + numerator: BigNumber, + denominator: BigNumber, + target: BigNumber, + ): Promise { + if (denominator.eq(0)) { + throw divisionByZeroErrorForCall; + } + if (numerator.eq(0)) { + return false; + } + if (target.eq(0)) { + return false; + } + const product = numerator.mul(target); + const remainder = product.mod(denominator); + const error = denominator.sub(remainder).mod(denominator); + const errorTimes1000 = error.mul('1000'); + const isError = errorTimes1000.gt(product); + if (product.greaterThan(MAX_UINT256)) { + throw overflowErrorForCall; + } + if (errorTimes1000.greaterThan(MAX_UINT256)) { + throw overflowErrorForCall; + } + return isError; + } + async function testIsRoundingErrorCeilAsync( + numerator: BigNumber, + denominator: BigNumber, + target: BigNumber, + ): Promise { + return testExchange.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target); + } + await testCombinatoriallyWithReferenceFuncAsync( + 'isRoundingErrorCeil', + referenceIsRoundingErrorAsync, + testIsRoundingErrorCeilAsync, + [uint256Values, uint256Values, uint256Values], + ); + }); + describe('updateFilledState', async () => { // Note(albrow): Since updateFilledState modifies the state by calling // sendTransaction, we must reset the state after each test. diff --git a/packages/contracts/test/exchange/libs.ts b/packages/contracts/test/exchange/libs.ts index c08d62758f..a5f31a498e 100644 --- a/packages/contracts/test/exchange/libs.ts +++ b/packages/contracts/test/exchange/libs.ts @@ -71,29 +71,57 @@ describe('Exchange libs', () => { // combinatorial tests in test/exchange/internal. They test specific edge // cases that are not covered by the combinatorial tests. describe('LibMath', () => { - it('should return true if there is a rounding error of 0.1%', async () => { - const numerator = new BigNumber(20); - const denominator = new BigNumber(999); - const target = new BigNumber(50); - // rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1% - const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target); - expect(isRoundingError).to.be.true(); + describe('isRoundingError', () => { + it('should return true if there is a rounding error of 0.1%', async () => { + const numerator = new BigNumber(20); + const denominator = new BigNumber(999); + const target = new BigNumber(50); + // rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1% + const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target); + expect(isRoundingError).to.be.true(); + }); + it('should return false if there is a rounding of 0.09%', async () => { + const numerator = new BigNumber(20); + const denominator = new BigNumber(9991); + const target = new BigNumber(500); + // rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09% + const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target); + expect(isRoundingError).to.be.false(); + }); + it('should return true if there is a rounding error of 0.11%', async () => { + const numerator = new BigNumber(20); + const denominator = new BigNumber(9989); + const target = new BigNumber(500); + // rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011% + const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target); + expect(isRoundingError).to.be.true(); + }); }); - it('should return false if there is a rounding of 0.09%', async () => { - const numerator = new BigNumber(20); - const denominator = new BigNumber(9991); - const target = new BigNumber(500); - // rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09% - const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target); - expect(isRoundingError).to.be.false(); - }); - it('should return true if there is a rounding error of 0.11%', async () => { - const numerator = new BigNumber(20); - const denominator = new BigNumber(9989); - const target = new BigNumber(500); - // rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011% - const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target); - expect(isRoundingError).to.be.true(); + describe('isRoundingErrorCeil', () => { + it('should return true if there is a rounding error of 0.1%', async () => { + const numerator = new BigNumber(20); + const denominator = new BigNumber(1001); + const target = new BigNumber(50); + // rounding error = (ceil(20*50/1001) - (20*50/1001)) / (20*50/1001) = 0.1% + const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target); + expect(isRoundingError).to.be.true(); + }); + it('should return false if there is a rounding of 0.09%', async () => { + const numerator = new BigNumber(20); + const denominator = new BigNumber(10009); + const target = new BigNumber(500); + // rounding error = (ceil(20*500/10009) - (20*500/10009)) / (20*500/10009) = 0.09% + const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target); + expect(isRoundingError).to.be.false(); + }); + it('should return true if there is a rounding error of 0.11%', async () => { + const numerator = new BigNumber(20); + const denominator = new BigNumber(10011); + const target = new BigNumber(500); + // rounding error = (ceil(20*500/10011) - (20*500/10011)) / (20*500/10011) = 0.11% + const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target); + expect(isRoundingError).to.be.true(); + }); }); }); From f6080367fe3a90762afea76a653c5df1315c45fa Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 24 Aug 2018 14:11:45 -0700 Subject: [PATCH 032/120] Disambiguate the operator precedence --- .../contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol index 8a1444af13..90ec9e2b69 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol @@ -109,9 +109,9 @@ contract LibMath is // Otherwise, we want the relative rounding error to be strictly // less than 0.1%. - // The relative error is `remainder / numerator * target`. + // The relative error is `remainder / (numerator * target)`. // We want the relative error less than 1 / 1000: - // remainder / numerator * denominator < 1 / 1000 + // remainder / (numerator * denominator) < 1 / 1000 // or equivalently: // 1000 * remainder < numerator * target // so we have a rounding error iff: From 8ce4f9c784556e93bde2c58b670bf6efd5d3b7fd Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Fri, 24 Aug 2018 10:01:24 -0700 Subject: [PATCH 033/120] Remove SignatureType.Caller --- .../2.0.0/examples/Whitelist/Whitelist.sol | 2 +- .../Exchange/MixinSignatureValidator.sol | 34 ++++++------------- .../Exchange/mixins/MSignatureValidator.sol | 11 +++--- .../test/exchange/signature_validator.ts | 26 -------------- packages/types/src/index.ts | 1 - 5 files changed, 16 insertions(+), 58 deletions(-) diff --git a/packages/contracts/src/2.0.0/examples/Whitelist/Whitelist.sol b/packages/contracts/src/2.0.0/examples/Whitelist/Whitelist.sol index 60cac26ea5..e4e25038c2 100644 --- a/packages/contracts/src/2.0.0/examples/Whitelist/Whitelist.sol +++ b/packages/contracts/src/2.0.0/examples/Whitelist/Whitelist.sol @@ -37,7 +37,7 @@ contract Whitelist is bytes internal TX_ORIGIN_SIGNATURE; // solhint-enable var-name-mixedcase - byte constant internal VALIDATOR_SIGNATURE_BYTE = "\x06"; + byte constant internal VALIDATOR_SIGNATURE_BYTE = "\x05"; constructor (address _exchange) public diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol index 017da742ee..401fdd3772 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol @@ -48,14 +48,16 @@ contract MixinSignatureValidator is ) external { - require( - isValidSignature( - hash, - signerAddress, - signature - ), - "INVALID_SIGNATURE" - ); + if (signerAddress != msg.sender) { + require( + isValidSignature( + hash, + signerAddress, + signature + ), + "INVALID_SIGNATURE" + ); + } preSigned[hash][signerAddress] = true; } @@ -172,22 +174,6 @@ contract MixinSignatureValidator is isValid = signerAddress == recovered; return isValid; - // Implicitly signed by caller. - // The signer has initiated the call. In the case of non-contract - // accounts it means the transaction itself was signed. - // Example: let's say for a particular operation three signatures - // A, B and C are required. To submit the transaction, A and B can - // give a signature to C, who can then submit the transaction using - // `Caller` for his own signature. Or A and C can sign and B can - // submit using `Caller`. Having `Caller` allows this flexibility. - } else if (signatureType == SignatureType.Caller) { - require( - signature.length == 0, - "LENGTH_0_REQUIRED" - ); - isValid = signerAddress == msg.sender; - return isValid; - // Signature verified by wallet contract. // If used with an order, the maker of the order is the wallet contract. } else if (signatureType == SignatureType.Wallet) { diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MSignatureValidator.sol b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MSignatureValidator.sol index 75fe9ec46e..b00c5e8da4 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MSignatureValidator.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MSignatureValidator.sol @@ -36,12 +36,11 @@ contract MSignatureValidator is Invalid, // 0x01 EIP712, // 0x02 EthSign, // 0x03 - Caller, // 0x04 - Wallet, // 0x05 - Validator, // 0x06 - PreSigned, // 0x07 - Trezor, // 0x08 - NSignatureTypes // 0x09, number of signature types. Always leave at end. + Wallet, // 0x04 + Validator, // 0x05 + PreSigned, // 0x06 + Trezor, // 0x07 + NSignatureTypes // 0x08, number of signature types. Always leave at end. } /// @dev Verifies signature using logic defined by Wallet contract. diff --git a/packages/contracts/test/exchange/signature_validator.ts b/packages/contracts/test/exchange/signature_validator.ts index 5b64d853c4..ac07b06361 100644 --- a/packages/contracts/test/exchange/signature_validator.ts +++ b/packages/contracts/test/exchange/signature_validator.ts @@ -281,32 +281,6 @@ describe('MixinSignatureValidator', () => { expect(isValidSignature).to.be.false(); }); - it('should return true when SignatureType=Caller and signer is caller', async () => { - const signature = ethUtil.toBuffer(`0x${SignatureType.Caller}`); - const signatureHex = ethUtil.bufferToHex(signature); - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( - orderHashHex, - signerAddress, - signatureHex, - { from: signerAddress }, - ); - expect(isValidSignature).to.be.true(); - }); - - it('should return false when SignatureType=Caller and signer is not caller', async () => { - const signature = ethUtil.toBuffer(`0x${SignatureType.Caller}`); - const signatureHex = ethUtil.bufferToHex(signature); - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( - orderHashHex, - signerAddress, - signatureHex, - { from: notSignerAddress }, - ); - expect(isValidSignature).to.be.false(); - }); - it('should return true when SignatureType=Wallet and signature is valid', async () => { // Create EIP712 signature const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 2831d816df..beedc24a3d 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -133,7 +133,6 @@ export enum SignatureType { Invalid, EIP712, EthSign, - Caller, Wallet, Validator, PreSigned, From 4f27991959ba6e4e15839e6195a40b0fd8a2122c Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Fri, 24 Aug 2018 11:22:17 -0700 Subject: [PATCH 034/120] Remove SigntureType.Caller from signingUtils --- packages/order-utils/src/signature_utils.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/order-utils/src/signature_utils.ts b/packages/order-utils/src/signature_utils.ts index 40bbcef985..f8ed9cf9cd 100644 --- a/packages/order-utils/src/signature_utils.ts +++ b/packages/order-utils/src/signature_utils.ts @@ -53,11 +53,6 @@ export const signatureUtils = { return signatureUtils.isValidECSignature(prefixedMessageHex, ecSignature, signerAddress); } - case SignatureType.Caller: - // HACK: We currently do not "validate" the caller signature type. - // It can only be validated during Exchange contract execution. - throw new Error('Caller signature type cannot be validated off-chain'); - case SignatureType.Wallet: { const isValid = await signatureUtils.isValidWalletSignatureAsync( provider, From 1932aff35c6b07093534cde66dec63c5f919fcf0 Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Fri, 24 Aug 2018 13:11:17 -0700 Subject: [PATCH 035/120] Remove Trezor SignatureType --- .../Exchange/MixinSignatureValidator.sol | 28 ----------- .../Exchange/mixins/MSignatureValidator.sol | 3 +- .../test/exchange/signature_validator.ts | 47 ------------------- packages/order-utils/CHANGELOG.json | 9 ++++ packages/order-utils/src/signature_utils.ts | 12 +---- .../order-utils/test/signature_utils_test.ts | 14 ------ packages/types/CHANGELOG.json | 4 ++ packages/types/src/index.ts | 1 - 8 files changed, 15 insertions(+), 103 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol index 401fdd3772..f30adcdb81 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol @@ -211,34 +211,6 @@ contract MixinSignatureValidator is } else if (signatureType == SignatureType.PreSigned) { isValid = preSigned[hash][signerAddress]; return isValid; - - // Signature from Trezor hardware wallet. - // It differs from web3.eth_sign in the encoding of message length - // (Bitcoin varint encoding vs ascii-decimal, the latter is not - // self-terminating which leads to ambiguities). - // See also: - // https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer - // https://github.com/trezor/trezor-mcu/blob/master/firmware/ethereum.c#L602 - // https://github.com/trezor/trezor-mcu/blob/master/firmware/crypto.c#L36 - } else if (signatureType == SignatureType.Trezor) { - require( - signature.length == 65, - "LENGTH_65_REQUIRED" - ); - v = uint8(signature[0]); - r = signature.readBytes32(1); - s = signature.readBytes32(33); - recovered = ecrecover( - keccak256(abi.encodePacked( - "\x19Ethereum Signed Message:\n\x20", - hash - )), - v, - r, - s - ); - isValid = signerAddress == recovered; - return isValid; } // Anything else is illegal (We do not return false because diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MSignatureValidator.sol b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MSignatureValidator.sol index b00c5e8da4..1fe88b908e 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MSignatureValidator.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MSignatureValidator.sol @@ -39,8 +39,7 @@ contract MSignatureValidator is Wallet, // 0x04 Validator, // 0x05 PreSigned, // 0x06 - Trezor, // 0x07 - NSignatureTypes // 0x08, number of signature types. Always leave at end. + NSignatureTypes // 0x07, number of signature types. Always leave at end. } /// @dev Verifies signature using logic defined by Wallet contract. diff --git a/packages/contracts/test/exchange/signature_validator.ts b/packages/contracts/test/exchange/signature_validator.ts index ac07b06361..9113e52480 100644 --- a/packages/contracts/test/exchange/signature_validator.ts +++ b/packages/contracts/test/exchange/signature_validator.ts @@ -414,53 +414,6 @@ describe('MixinSignatureValidator', () => { expect(isValidSignature).to.be.false(); }); - it('should return true when SignatureType=Trezor and signature is valid', async () => { - // Create Trezor signature - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - const orderHashWithTrezorPrefixHex = signatureUtils.addSignedMessagePrefix(orderHashHex, SignerType.Trezor); - const orderHashWithTrezorPrefixBuffer = ethUtil.toBuffer(orderHashWithTrezorPrefixHex); - const ecSignature = ethUtil.ecsign(orderHashWithTrezorPrefixBuffer, signerPrivateKey); - // Create 0x signature from Trezor signature - const signature = Buffer.concat([ - ethUtil.toBuffer(ecSignature.v), - ecSignature.r, - ecSignature.s, - ethUtil.toBuffer(`0x${SignatureType.Trezor}`), - ]); - const signatureHex = ethUtil.bufferToHex(signature); - // Validate signature - const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( - orderHashHex, - signerAddress, - signatureHex, - ); - expect(isValidSignature).to.be.true(); - }); - - it('should return false when SignatureType=Trezor and signature is invalid', async () => { - // Create Trezor signature - const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); - const orderHashWithTrezorPrefixHex = signatureUtils.addSignedMessagePrefix(orderHashHex, SignerType.Trezor); - const orderHashWithTrezorPrefixBuffer = ethUtil.toBuffer(orderHashWithTrezorPrefixHex); - const ecSignature = ethUtil.ecsign(orderHashWithTrezorPrefixBuffer, signerPrivateKey); - // Create 0x signature from Trezor signature - const signature = Buffer.concat([ - ethUtil.toBuffer(ecSignature.v), - ecSignature.r, - ecSignature.s, - ethUtil.toBuffer(`0x${SignatureType.Trezor}`), - ]); - const signatureHex = ethUtil.bufferToHex(signature); - // Validate signature. - // This will fail because `signerAddress` signed the message, but we're passing in `notSignerAddress` - const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( - orderHashHex, - notSignerAddress, - signatureHex, - ); - expect(isValidSignature).to.be.false(); - }); - it('should return true when SignatureType=Presigned and signer has presigned hash', async () => { // Presign hash const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json index 81782b5015..d18bf51edb 100644 --- a/packages/order-utils/CHANGELOG.json +++ b/packages/order-utils/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "1.0.1-rc.5", + "changes": [ + { + "note": "Remove Caller and Trezor SignatureTypes", + "pr": 1015 + } + ] + }, { "version": "1.0.1-rc.4", "changes": [ diff --git a/packages/order-utils/src/signature_utils.ts b/packages/order-utils/src/signature_utils.ts index f8ed9cf9cd..23577efdc1 100644 --- a/packages/order-utils/src/signature_utils.ts +++ b/packages/order-utils/src/signature_utils.ts @@ -77,12 +77,6 @@ export const signatureUtils = { return signatureUtils.isValidPresignedSignatureAsync(provider, data, signerAddress); } - case SignatureType.Trezor: { - const prefixedMessageHex = signatureUtils.addSignedMessagePrefix(data, SignerType.Trezor); - const ecSignature = signatureUtils.parseECSignature(signature); - return signatureUtils.isValidECSignature(prefixedMessageHex, ecSignature, signerAddress); - } - default: throw new Error(`Unhandled SignatureType: ${signatureTypeIndexIfExists}`); } @@ -288,10 +282,6 @@ export const signatureUtils = { signatureType = SignatureType.EthSign; break; } - case SignerType.Trezor: { - signatureType = SignatureType.Trezor; - break; - } default: throw new Error(`Unrecognized SignerType: ${signerType}`); } @@ -345,7 +335,7 @@ export const signatureUtils = { */ parseECSignature(signature: string): ECSignature { assert.isHexString('signature', signature); - const ecSignatureTypes = [SignatureType.EthSign, SignatureType.EIP712, SignatureType.Trezor]; + const ecSignatureTypes = [SignatureType.EthSign, SignatureType.EIP712]; assert.isOneOfExpectedSignatureTypes(signature, ecSignatureTypes); // tslint:disable-next-line:custom-no-magic-numbers diff --git a/packages/order-utils/test/signature_utils_test.ts b/packages/order-utils/test/signature_utils_test.ts index 4ce99a1c77..0e7831b41a 100644 --- a/packages/order-utils/test/signature_utils_test.ts +++ b/packages/order-utils/test/signature_utils_test.ts @@ -76,20 +76,6 @@ describe('Signature utils', () => { ); expect(isValidSignatureLocal).to.be.true(); }); - - it('should return true for a valid Trezor signature', async () => { - dataHex = '0xd0d994e31c88f33fd8a572552a70ed339de579e5ba49ee1d17cc978bbe1cdd21'; - address = '0x6ecbe1db9ef729cbe972c83fb886247691fb6beb'; - const trezorSignature = - '0x1ce4760660e6495b5ae6723087bea073b3a99ce98ea81fdf00c240279c010e63d05b87bc34c4d67d4776e8d5aeb023a67484f4eaf0fd353b40893e5101e845cd9908'; - const isValidSignatureLocal = await signatureUtils.isValidSignatureAsync( - provider, - dataHex, - trezorSignature, - address, - ); - expect(isValidSignatureLocal).to.be.true(); - }); }); describe('#isValidECSignature', () => { const signature = { diff --git a/packages/types/CHANGELOG.json b/packages/types/CHANGELOG.json index 980a12ad33..1210168d48 100644 --- a/packages/types/CHANGELOG.json +++ b/packages/types/CHANGELOG.json @@ -5,6 +5,10 @@ { "note": "Add WalletError and ValidatorError revert reasons", "pr": 1012 + }, + { + "note": "Remove Caller and Trezor SignatureTypes", + "pr": 1015 } ] }, diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index beedc24a3d..5261ddfe26 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -136,7 +136,6 @@ export enum SignatureType { Wallet, Validator, PreSigned, - Trezor, NSignatureTypes, } From 241534a63dab54172326ec71d6b5e78733bb24c6 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Fri, 24 Aug 2018 02:42:20 -0700 Subject: [PATCH 036/120] Fixed trezor personal message in client+contracts; added a test using message signed by Trezor One (firmware v1.6.2) --- .../test/exchange/signature_validator.ts | 18 ++++++++++++++++++ packages/order-utils/src/signature_utils.ts | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/contracts/test/exchange/signature_validator.ts b/packages/contracts/test/exchange/signature_validator.ts index 9113e52480..a318d1f796 100644 --- a/packages/contracts/test/exchange/signature_validator.ts +++ b/packages/contracts/test/exchange/signature_validator.ts @@ -447,6 +447,24 @@ describe('MixinSignatureValidator', () => { ); expect(isValidSignature).to.be.false(); }); + + it('should return true when message was signed by a Trezor One (firmware version 1.6.2)', async () => { + // messageHash translates to 0x2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b + const messageHash = ethUtil.bufferToHex(ethUtil.toBuffer('++++++++++++++++++++++++++++++++')); + const signer = '0xc28b145f10f0bcf0fc000e778615f8fd73490bad'; + const v = ethUtil.toBuffer('0x1c'); + const r = ethUtil.toBuffer('0x7b888b596ccf87f0bacab0dcb483124973f7420f169b4824d7a12534ac1e9832'); + const s = ethUtil.toBuffer('0x0c8e14f7edc01459e13965f1da56e0c23ed11e2cca932571eee1292178f90424'); + const trezorSignatureType = ethUtil.toBuffer(`0x${SignatureType.EthSign}`); + const signature = Buffer.concat([v, r, s, trezorSignatureType]); + const signatureHex = ethUtil.bufferToHex(signature); + const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( + messageHash, + signer, + signatureHex, + ); + expect(isValidSignature).to.be.true(); + }); }); describe('setSignatureValidatorApproval', () => { diff --git a/packages/order-utils/src/signature_utils.ts b/packages/order-utils/src/signature_utils.ts index 23577efdc1..c18e895f58 100644 --- a/packages/order-utils/src/signature_utils.ts +++ b/packages/order-utils/src/signature_utils.ts @@ -347,7 +347,7 @@ export const signatureUtils = { }; function hashTrezorPersonalMessage(message: Buffer): Buffer { - const prefix = ethUtil.toBuffer('\x19Ethereum Signed Message:\n' + String.fromCharCode(message.byteLength)); + const prefix = ethUtil.toBuffer('\x19Ethereum Signed Message:\n' + message.byteLength); return ethUtil.sha3(Buffer.concat([prefix, message])); } From bb4d449e92da347c305d64fbe1855b13a8db361b Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Fri, 24 Aug 2018 10:59:37 -0700 Subject: [PATCH 037/120] Test case for Trezor Model T signature --- .../test/exchange/signature_validator.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/contracts/test/exchange/signature_validator.ts b/packages/contracts/test/exchange/signature_validator.ts index a318d1f796..6bc0bbc02a 100644 --- a/packages/contracts/test/exchange/signature_validator.ts +++ b/packages/contracts/test/exchange/signature_validator.ts @@ -465,6 +465,24 @@ describe('MixinSignatureValidator', () => { ); expect(isValidSignature).to.be.true(); }); + + it('should return true when message was signed by a Trezor Model T (firmware version 2.0.7)', async () => { + // messageHash translates to 0x2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b + const messageHash = ethUtil.bufferToHex(ethUtil.toBuffer('++++++++++++++++++++++++++++++++')); + const signer = '0x98ce6d9345e8ffa7d99ee0822272fae9d2c0e895'; + const v = ethUtil.toBuffer('0x1c'); + const r = ethUtil.toBuffer('0x423b71062c327f0ec4fe199b8da0f34185e59b4c1cb4cc23df86cac4a601fb3f'); + const s = ethUtil.toBuffer('0x53810d6591b5348b7ee08ee812c874b0fdfb942c9849d59512c90e295221091f'); + const trezorSignatureType = ethUtil.toBuffer(`0x${SignatureType.Trezor}`); + const signature = Buffer.concat([v, r, s, trezorSignatureType]); + const signatureHex = ethUtil.bufferToHex(signature); + const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( + messageHash, + signer, + signatureHex, + ); + expect(isValidSignature).to.be.true(); + }); }); describe('setSignatureValidatorApproval', () => { From d039a1adda6fd8ce87a254310e0f56568b10136b Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Fri, 24 Aug 2018 11:57:12 -0700 Subject: [PATCH 038/120] Fixed linter in signatureUtils --- packages/order-utils/src/signature_utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/order-utils/src/signature_utils.ts b/packages/order-utils/src/signature_utils.ts index c18e895f58..e5478d4d66 100644 --- a/packages/order-utils/src/signature_utils.ts +++ b/packages/order-utils/src/signature_utils.ts @@ -347,7 +347,7 @@ export const signatureUtils = { }; function hashTrezorPersonalMessage(message: Buffer): Buffer { - const prefix = ethUtil.toBuffer('\x19Ethereum Signed Message:\n' + message.byteLength); + const prefix = ethUtil.toBuffer(`\x19Ethereum Signed Message:\n${message.byteLength}`); return ethUtil.sha3(Buffer.concat([prefix, message])); } From a27112cbefbe9d9039d265cfc92c1022b0f9d103 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Fri, 24 Aug 2018 13:20:17 -0700 Subject: [PATCH 039/120] SignatureType.Trezor -> SignatureType.EthSign in Signature Validator tests --- packages/contracts/test/exchange/signature_validator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contracts/test/exchange/signature_validator.ts b/packages/contracts/test/exchange/signature_validator.ts index 6bc0bbc02a..da2febfd84 100644 --- a/packages/contracts/test/exchange/signature_validator.ts +++ b/packages/contracts/test/exchange/signature_validator.ts @@ -473,7 +473,7 @@ describe('MixinSignatureValidator', () => { const v = ethUtil.toBuffer('0x1c'); const r = ethUtil.toBuffer('0x423b71062c327f0ec4fe199b8da0f34185e59b4c1cb4cc23df86cac4a601fb3f'); const s = ethUtil.toBuffer('0x53810d6591b5348b7ee08ee812c874b0fdfb942c9849d59512c90e295221091f'); - const trezorSignatureType = ethUtil.toBuffer(`0x${SignatureType.Trezor}`); + const trezorSignatureType = ethUtil.toBuffer(`0x${SignatureType.EthSign}`); const signature = Buffer.concat([v, r, s, trezorSignatureType]); const signatureHex = ethUtil.bufferToHex(signature); const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( From 0629a7d1434e9a17ba98be4de66fd4a7fa7ff16f Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Fri, 24 Aug 2018 14:13:54 -0700 Subject: [PATCH 040/120] Remove remaining Trezor references --- packages/order-utils/src/signature_utils.ts | 13 +------------ packages/order-utils/test/signature_utils_test.ts | 9 --------- packages/types/src/index.ts | 3 +-- 3 files changed, 2 insertions(+), 23 deletions(-) diff --git a/packages/order-utils/src/signature_utils.ts b/packages/order-utils/src/signature_utils.ts index e5478d4d66..c0c9e71a76 100644 --- a/packages/order-utils/src/signature_utils.ts +++ b/packages/order-utils/src/signature_utils.ts @@ -291,7 +291,7 @@ export const signatureUtils = { /** * Combines the signature proof and the Signature Type. * @param signature The hex encoded signature proof - * @param signatureType The signature type, i.e EthSign, Trezor, Wallet etc. + * @param signatureType The signature type, i.e EthSign, Wallet etc. * @return Hex encoded string of signature proof with Signature Type */ convertToSignatureWithType(signature: string, signatureType: SignatureType): string { @@ -318,12 +318,6 @@ export const signatureUtils = { const prefixedMsgHex = ethUtil.bufferToHex(prefixedMsgBuff); return prefixedMsgHex; } - case SignerType.Trezor: { - const msgBuff = ethUtil.toBuffer(message); - const prefixedMsgBuff = hashTrezorPersonalMessage(msgBuff); - const prefixedMsgHex = ethUtil.bufferToHex(prefixedMsgBuff); - return prefixedMsgHex; - } default: throw new Error(`Unrecognized SignerType: ${signerType}`); } @@ -346,11 +340,6 @@ export const signatureUtils = { }, }; -function hashTrezorPersonalMessage(message: Buffer): Buffer { - const prefix = ethUtil.toBuffer(`\x19Ethereum Signed Message:\n${message.byteLength}`); - return ethUtil.sha3(Buffer.concat([prefix, message])); -} - function parseValidatorSignature(signature: string): ValidatorSignature { assert.isOneOfExpectedSignatureTypes(signature, [SignatureType.Validator]); // tslint:disable:custom-no-magic-numbers diff --git a/packages/order-utils/test/signature_utils_test.ts b/packages/order-utils/test/signature_utils_test.ts index 0e7831b41a..2ca1109a1c 100644 --- a/packages/order-utils/test/signature_utils_test.ts +++ b/packages/order-utils/test/signature_utils_test.ts @@ -256,15 +256,6 @@ describe('Signature utils', () => { r: '0xaca7da997ad177f040240cdccf6905b71ab16b74434388c3a72f34fd25d64393', s: '0x46b2bac274ff29b48b3ea6e2d04c1336eaceafda3c53ab483fc3ff12fac3ebf2', }; - it('should concatenate v,r,s and append the Trezor signature type', async () => { - const expectedSignatureWithSignatureType = - '0x1baca7da997ad177f040240cdccf6905b71ab16b74434388c3a72f34fd25d6439346b2bac274ff29b48b3ea6e2d04c1336eaceafda3c53ab483fc3ff12fac3ebf208'; - const signatureWithSignatureType = signatureUtils.convertECSignatureToSignatureHex( - ecSignature, - SignerType.Trezor, - ); - expect(signatureWithSignatureType).to.equal(expectedSignatureWithSignatureType); - }); it('should concatenate v,r,s and append the EthSign signature type when SignerType is Default', async () => { const expectedSignatureWithSignatureType = '0x1baca7da997ad177f040240cdccf6905b71ab16b74434388c3a72f34fd25d6439346b2bac274ff29b48b3ea6e2d04c1336eaceafda3c53ab483fc3ff12fac3ebf203'; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 5261ddfe26..4375fc6312 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -140,14 +140,13 @@ export enum SignatureType { } /** - * The type of the Signer implementation. Some signer implementations use different message prefixes (e.g Trezor) or implement different + * The type of the Signer implementation. Some signer implementations use different message prefixes or implement different * eth_sign behaviour (e.g Metamask). Default assumes a spec compliant `eth_sign`. */ export enum SignerType { Default = 'DEFAULT', Ledger = 'LEDGER', Metamask = 'METAMASK', - Trezor = 'TREZOR', } export enum AssetProxyId { From 3557cd93fc99495257cfeacc2bb58a810d25cf65 Mon Sep 17 00:00:00 2001 From: Brandon Millman Date: Fri, 24 Aug 2018 14:42:07 -0700 Subject: [PATCH 041/120] Add testnet network info to OrderValidator artifact --- .../artifacts/2.0.0-beta-testnet/OrderValidator.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/migrations/artifacts/2.0.0-beta-testnet/OrderValidator.json b/packages/migrations/artifacts/2.0.0-beta-testnet/OrderValidator.json index 652a6d3a22..99805c766c 100644 --- a/packages/migrations/artifacts/2.0.0-beta-testnet/OrderValidator.json +++ b/packages/migrations/artifacts/2.0.0-beta-testnet/OrderValidator.json @@ -782,5 +782,11 @@ } } }, - "networks": {} + "networks": { + "50": { + "address": "0xe86bb98fcf9bff3512c74589b78fb168200cc546", + "links": {}, + "constructorArgs": "[\"0x48bacb9266a570d521063ef5dd96e61686dbe788\",\"0xf47261b0000000000000000000000000871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c\"]" + } + } } \ No newline at end of file From 80291caf7cef16f0b300484755960d92d6750a6a Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 24 Aug 2018 16:16:44 -0700 Subject: [PATCH 042/120] Append -Floor to getPartialAmount and isRoundingError --- .../Forwarder/MixinExchangeWrapper.sol | 4 ++-- .../Forwarder/MixinForwarderCore.sol | 4 ++-- .../2.0.0/extensions/Forwarder/MixinWeth.sol | 2 +- .../protocol/Exchange/MixinExchangeCore.sol | 8 ++++---- .../protocol/Exchange/MixinMatchOrders.sol | 4 ++-- .../Exchange/MixinWrapperFunctions.sol | 4 ++-- .../2.0.0/protocol/Exchange/libs/LibMath.sol | 8 ++++---- .../TestExchangeInternals.sol | 8 ++++---- .../src/2.0.0/test/TestLibs/TestLibs.sol | 8 ++++---- packages/contracts/test/exchange/internal.ts | 20 +++++++++---------- packages/contracts/test/exchange/libs.ts | 6 +++--- .../utils/fill_order_combinatorial_utils.ts | 12 +++++------ packages/contracts/test/utils/order_utils.ts | 2 +- packages/order-utils/src/order_state_utils.ts | 4 ++-- .../order-utils/src/order_validation_utils.ts | 10 +++++----- packages/order-utils/src/utils.ts | 2 +- .../test/order_validation_utils_test.ts | 12 +++++------ 17 files changed, 59 insertions(+), 59 deletions(-) diff --git a/packages/contracts/src/2.0.0/extensions/Forwarder/MixinExchangeWrapper.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinExchangeWrapper.sol index 218713d3c9..a7ff400b9b 100644 --- a/packages/contracts/src/2.0.0/extensions/Forwarder/MixinExchangeWrapper.sol +++ b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinExchangeWrapper.sol @@ -163,7 +163,7 @@ contract MixinExchangeWrapper is // Convert the remaining amount of makerAsset to buy into remaining amount // of takerAsset to sell, assuming entire amount can be sold in the current order - uint256 remainingTakerAssetFillAmount = getPartialAmount( + uint256 remainingTakerAssetFillAmount = getPartialAmountFloor( orders[i].takerAssetAmount, orders[i].makerAssetAmount, remainingMakerAssetFillAmount @@ -231,7 +231,7 @@ contract MixinExchangeWrapper is // Convert the remaining amount of ZRX to buy into remaining amount // of WETH to sell, assuming entire amount can be sold in the current order. - uint256 remainingWethSellAmount = getPartialAmount( + uint256 remainingWethSellAmount = getPartialAmountFloor( orders[i].takerAssetAmount, safeSub(orders[i].makerAssetAmount, orders[i].takerFee), // our exchange rate after fees remainingZrxBuyAmount diff --git a/packages/contracts/src/2.0.0/extensions/Forwarder/MixinForwarderCore.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinForwarderCore.sol index 42cec4d36c..14f1918793 100644 --- a/packages/contracts/src/2.0.0/extensions/Forwarder/MixinForwarderCore.sol +++ b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinForwarderCore.sol @@ -87,7 +87,7 @@ contract MixinForwarderCore is uint256 makerAssetAmountPurchased; if (orders[0].makerAssetData.equals(ZRX_ASSET_DATA)) { // Calculate amount of WETH that won't be spent on ETH fees. - wethSellAmount = getPartialAmount( + wethSellAmount = getPartialAmountFloor( PERCENTAGE_DENOMINATOR, safeAdd(PERCENTAGE_DENOMINATOR, feePercentage), msg.value @@ -103,7 +103,7 @@ contract MixinForwarderCore is makerAssetAmountPurchased = safeSub(orderFillResults.makerAssetFilledAmount, orderFillResults.takerFeePaid); } else { // 5% of WETH is reserved for filling feeOrders and paying feeRecipient. - wethSellAmount = getPartialAmount( + wethSellAmount = getPartialAmountFloor( MAX_WETH_FILL_PERCENTAGE, PERCENTAGE_DENOMINATOR, msg.value diff --git a/packages/contracts/src/2.0.0/extensions/Forwarder/MixinWeth.sol b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinWeth.sol index 93e85e5993..5863b522d2 100644 --- a/packages/contracts/src/2.0.0/extensions/Forwarder/MixinWeth.sol +++ b/packages/contracts/src/2.0.0/extensions/Forwarder/MixinWeth.sol @@ -82,7 +82,7 @@ contract MixinWeth is uint256 wethRemaining = safeSub(msg.value, wethSold); // Calculate ETH fee to pay to feeRecipient. - uint256 ethFee = getPartialAmount( + uint256 ethFee = getPartialAmountFloor( feePercentage, PERCENTAGE_DENOMINATOR, wethSoldExcludingFeeOrders diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol index ab5c6e5071..f3a0591b2f 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol @@ -320,7 +320,7 @@ contract MixinExchangeCore is // Validate fill order rounding require( - !isRoundingError( + !isRoundingErrorFloor( takerAssetFilledAmount, order.takerAssetAmount, order.makerAssetAmount @@ -376,17 +376,17 @@ contract MixinExchangeCore is { // Compute proportional transfer amounts fillResults.takerAssetFilledAmount = takerAssetFilledAmount; - fillResults.makerAssetFilledAmount = getPartialAmount( + fillResults.makerAssetFilledAmount = getPartialAmountFloor( takerAssetFilledAmount, order.takerAssetAmount, order.makerAssetAmount ); - fillResults.makerFeePaid = getPartialAmount( + fillResults.makerFeePaid = getPartialAmountFloor( takerAssetFilledAmount, order.takerAssetAmount, order.makerFee ); - fillResults.takerFeePaid = getPartialAmount( + fillResults.takerFeePaid = getPartialAmountFloor( takerAssetFilledAmount, order.takerAssetAmount, order.takerFee diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol index 56b309a1bd..20f4b1c334 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol @@ -183,7 +183,7 @@ contract MixinMatchOrders is leftTakerAssetFilledAmount = leftTakerAssetAmountRemaining; // The right order receives an amount proportional to how much was spent. - rightTakerAssetFilledAmount = getPartialAmount( + rightTakerAssetFilledAmount = getPartialAmountFloor( rightOrder.takerAssetAmount, rightOrder.makerAssetAmount, leftTakerAssetFilledAmount @@ -193,7 +193,7 @@ contract MixinMatchOrders is rightTakerAssetFilledAmount = rightTakerAssetAmountRemaining; // The left order receives an amount proportional to how much was spent. - leftTakerAssetFilledAmount = getPartialAmount( + leftTakerAssetFilledAmount = getPartialAmountFloor( rightOrder.makerAssetAmount, rightOrder.takerAssetAmount, rightTakerAssetFilledAmount diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol index 86194f461a..1b77cfbcbd 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol @@ -298,7 +298,7 @@ contract MixinWrapperFunctions is // Convert the remaining amount of makerAsset to buy into remaining amount // of takerAsset to sell, assuming entire amount can be sold in the current order - uint256 remainingTakerAssetFillAmount = getPartialAmount( + uint256 remainingTakerAssetFillAmount = getPartialAmountFloor( orders[i].takerAssetAmount, orders[i].makerAssetAmount, remainingMakerAssetFillAmount @@ -350,7 +350,7 @@ contract MixinWrapperFunctions is // Convert the remaining amount of makerAsset to buy into remaining amount // of takerAsset to sell, assuming entire amount can be sold in the current order - uint256 remainingTakerAssetFillAmount = getPartialAmount( + uint256 remainingTakerAssetFillAmount = getPartialAmountFloor( orders[i].takerAssetAmount, orders[i].makerAssetAmount, remainingMakerAssetFillAmount diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol index 90ec9e2b69..7d58f70ce2 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol @@ -25,12 +25,12 @@ contract LibMath is SafeMath { - /// @dev Calculates partial value given a numerator and denominator. + /// @dev Calculates partial value given a numerator and denominator rounded down. /// @param numerator Numerator. /// @param denominator Denominator. /// @param target Value to calculate partial of. /// @return Partial value of target rounded down. - function getPartialAmount( + function getPartialAmountFloor( uint256 numerator, uint256 denominator, uint256 target @@ -48,7 +48,7 @@ contract LibMath is return partialAmount; } - /// @dev Calculates partial value given a numerator and denominator. + /// @dev Calculates partial value given a numerator and denominator rounded down. /// @param numerator Numerator. /// @param denominator Denominator. /// @param target Value to calculate partial of. @@ -79,7 +79,7 @@ contract LibMath is /// @param denominator Denominator. /// @param target Value to multiply with numerator/denominator. /// @return Rounding error is present. - function isRoundingError( + function isRoundingErrorFloor( uint256 numerator, uint256 denominator, uint256 target diff --git a/packages/contracts/src/2.0.0/test/TestExchangeInternals/TestExchangeInternals.sol b/packages/contracts/src/2.0.0/test/TestExchangeInternals/TestExchangeInternals.sol index 5e2ae2f0ed..da9313e026 100644 --- a/packages/contracts/src/2.0.0/test/TestExchangeInternals/TestExchangeInternals.sol +++ b/packages/contracts/src/2.0.0/test/TestExchangeInternals/TestExchangeInternals.sol @@ -67,7 +67,7 @@ contract TestExchangeInternals is /// @param denominator Denominator. /// @param target Value to calculate partial of. /// @return Partial value of target. - function publicGetPartialAmount( + function publicGetPartialAmountFloor( uint256 numerator, uint256 denominator, uint256 target @@ -76,7 +76,7 @@ contract TestExchangeInternals is pure returns (uint256 partialAmount) { - return getPartialAmount(numerator, denominator, target); + return getPartialAmountFloor(numerator, denominator, target); } /// @dev Calculates partial value given a numerator and denominator. @@ -101,7 +101,7 @@ contract TestExchangeInternals is /// @param denominator Denominator. /// @param target Value to multiply with numerator/denominator. /// @return Rounding error is present. - function publicIsRoundingError( + function publicIsRoundingErrorFloor( uint256 numerator, uint256 denominator, uint256 target @@ -110,7 +110,7 @@ contract TestExchangeInternals is pure returns (bool isError) { - return isRoundingError(numerator, denominator, target); + return isRoundingErrorFloor(numerator, denominator, target); } /// @dev Checks if rounding error >= 0.1%. diff --git a/packages/contracts/src/2.0.0/test/TestLibs/TestLibs.sol b/packages/contracts/src/2.0.0/test/TestLibs/TestLibs.sol index 8c3d122266..c8c58545f2 100644 --- a/packages/contracts/src/2.0.0/test/TestLibs/TestLibs.sol +++ b/packages/contracts/src/2.0.0/test/TestLibs/TestLibs.sol @@ -49,7 +49,7 @@ contract TestLibs is return fillOrderCalldata; } - function publicGetPartialAmount( + function publicGetPartialAmountFloor( uint256 numerator, uint256 denominator, uint256 target @@ -58,7 +58,7 @@ contract TestLibs is pure returns (uint256 partialAmount) { - partialAmount = getPartialAmount( + partialAmount = getPartialAmountFloor( numerator, denominator, target @@ -83,7 +83,7 @@ contract TestLibs is return partialAmount; } - function publicIsRoundingError( + function publicIsRoundingErrorFloor( uint256 numerator, uint256 denominator, uint256 target @@ -92,7 +92,7 @@ contract TestLibs is pure returns (bool isError) { - isError = isRoundingError( + isError = isRoundingErrorFloor( numerator, denominator, target diff --git a/packages/contracts/test/exchange/internal.ts b/packages/contracts/test/exchange/internal.ts index 0c6ab3707c..14c0ff4cb4 100644 --- a/packages/contracts/test/exchange/internal.ts +++ b/packages/contracts/test/exchange/internal.ts @@ -75,7 +75,7 @@ describe('Exchange core internal functions', () => { // Note(albrow): Don't forget to add beforeEach and afterEach calls to reset // the blockchain state for any tests which modify it! - async function referenceGetPartialAmountAsync( + async function referenceGetPartialAmountFloorAsync( numerator: BigNumber, denominator: BigNumber, target: BigNumber, @@ -165,18 +165,18 @@ describe('Exchange core internal functions', () => { // implementation or the Solidity implementation of // calculateFillResults. return { - makerAssetFilledAmount: await referenceGetPartialAmountAsync( + makerAssetFilledAmount: await referenceGetPartialAmountFloorAsync( takerAssetFilledAmount, orderTakerAssetAmount, otherAmount, ), takerAssetFilledAmount, - makerFeePaid: await referenceGetPartialAmountAsync( + makerFeePaid: await referenceGetPartialAmountFloorAsync( takerAssetFilledAmount, orderTakerAssetAmount, otherAmount, ), - takerFeePaid: await referenceGetPartialAmountAsync( + takerFeePaid: await referenceGetPartialAmountFloorAsync( takerAssetFilledAmount, orderTakerAssetAmount, otherAmount, @@ -199,18 +199,18 @@ describe('Exchange core internal functions', () => { ); }); - describe('getPartialAmount', async () => { - async function testGetPartialAmountAsync( + describe('getPartialAmountFloor', async () => { + async function testGetPartialAmountFloorAsync( numerator: BigNumber, denominator: BigNumber, target: BigNumber, ): Promise { - return testExchange.publicGetPartialAmount.callAsync(numerator, denominator, target); + return testExchange.publicGetPartialAmountFloor.callAsync(numerator, denominator, target); } await testCombinatoriallyWithReferenceFuncAsync( 'getPartialAmount', - referenceGetPartialAmountAsync, - testGetPartialAmountAsync, + referenceGetPartialAmountFloorAsync, + testGetPartialAmountFloorAsync, [uint256Values, uint256Values, uint256Values], ); }); @@ -284,7 +284,7 @@ describe('Exchange core internal functions', () => { denominator: BigNumber, target: BigNumber, ): Promise { - return testExchange.publicIsRoundingError.callAsync(numerator, denominator, target); + return testExchange.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target); } await testCombinatoriallyWithReferenceFuncAsync( 'isRoundingError', diff --git a/packages/contracts/test/exchange/libs.ts b/packages/contracts/test/exchange/libs.ts index a5f31a498e..37234489e6 100644 --- a/packages/contracts/test/exchange/libs.ts +++ b/packages/contracts/test/exchange/libs.ts @@ -77,7 +77,7 @@ describe('Exchange libs', () => { const denominator = new BigNumber(999); const target = new BigNumber(50); // rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1% - const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target); + const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target); expect(isRoundingError).to.be.true(); }); it('should return false if there is a rounding of 0.09%', async () => { @@ -85,7 +85,7 @@ describe('Exchange libs', () => { const denominator = new BigNumber(9991); const target = new BigNumber(500); // rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09% - const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target); + const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target); expect(isRoundingError).to.be.false(); }); it('should return true if there is a rounding error of 0.11%', async () => { @@ -93,7 +93,7 @@ describe('Exchange libs', () => { const denominator = new BigNumber(9989); const target = new BigNumber(500); // rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011% - const isRoundingError = await libs.publicIsRoundingError.callAsync(numerator, denominator, target); + const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target); expect(isRoundingError).to.be.true(); }); }); diff --git a/packages/contracts/test/utils/fill_order_combinatorial_utils.ts b/packages/contracts/test/utils/fill_order_combinatorial_utils.ts index a9318571ce..92d0f40030 100644 --- a/packages/contracts/test/utils/fill_order_combinatorial_utils.ts +++ b/packages/contracts/test/utils/fill_order_combinatorial_utils.ts @@ -467,17 +467,17 @@ export class FillOrderCombinatorialUtils { ? remainingTakerAmountToFill : alreadyFilledTakerAmount.add(takerAssetFillAmount); - const expFilledMakerAmount = orderUtils.getPartialAmount( + const expFilledMakerAmount = orderUtils.getPartialAmountFloor( expFilledTakerAmount, signedOrder.takerAssetAmount, signedOrder.makerAssetAmount, ); - const expMakerFeePaid = orderUtils.getPartialAmount( + const expMakerFeePaid = orderUtils.getPartialAmountFloor( expFilledTakerAmount, signedOrder.takerAssetAmount, signedOrder.makerFee, ); - const expTakerFeePaid = orderUtils.getPartialAmount( + const expTakerFeePaid = orderUtils.getPartialAmountFloor( expFilledTakerAmount, signedOrder.takerAssetAmount, signedOrder.takerFee, @@ -668,7 +668,7 @@ export class FillOrderCombinatorialUtils { signedOrder: SignedOrder, takerAssetFillAmount: BigNumber, ): Promise { - const makerAssetFillAmount = orderUtils.getPartialAmount( + const makerAssetFillAmount = orderUtils.getPartialAmountFloor( takerAssetFillAmount, signedOrder.takerAssetAmount, signedOrder.makerAssetAmount, @@ -705,7 +705,7 @@ export class FillOrderCombinatorialUtils { ); } - const makerFee = orderUtils.getPartialAmount( + const makerFee = orderUtils.getPartialAmountFloor( takerAssetFillAmount, signedOrder.takerAssetAmount, signedOrder.makerFee, @@ -829,7 +829,7 @@ export class FillOrderCombinatorialUtils { ); } - const takerFee = orderUtils.getPartialAmount( + const takerFee = orderUtils.getPartialAmountFloor( takerAssetFillAmount, signedOrder.takerAssetAmount, signedOrder.takerFee, diff --git a/packages/contracts/test/utils/order_utils.ts b/packages/contracts/test/utils/order_utils.ts index 019f6e74bb..444e27c447 100644 --- a/packages/contracts/test/utils/order_utils.ts +++ b/packages/contracts/test/utils/order_utils.ts @@ -5,7 +5,7 @@ import { constants } from './constants'; import { CancelOrder, MatchOrder } from './types'; export const orderUtils = { - getPartialAmount(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber { + getPartialAmountFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber { const partialAmount = numerator .mul(target) .div(denominator) diff --git a/packages/order-utils/src/order_state_utils.ts b/packages/order-utils/src/order_state_utils.ts index a0e24acf08..8398776aac 100644 --- a/packages/order-utils/src/order_state_utils.ts +++ b/packages/order-utils/src/order_state_utils.ts @@ -81,7 +81,7 @@ export class OrderStateUtils { const remainingTakerAssetAmount = signedOrder.takerAssetAmount.minus( sidedOrderRelevantState.filledTakerAssetAmount, ); - const isRoundingError = OrderValidationUtils.isRoundingError( + const isRoundingError = OrderValidationUtils.isRoundingErrorFloor( remainingTakerAssetAmount, signedOrder.takerAssetAmount, signedOrder.makerAssetAmount, @@ -191,7 +191,7 @@ export class OrderStateUtils { ); const remainingFillableTakerAssetAmountGivenMakersStatus = signedOrder.makerAssetAmount.eq(0) ? new BigNumber(0) - : utils.getPartialAmount( + : utils.getPartialAmountFloor( orderRelevantMakerState.remainingFillableAssetAmount, signedOrder.makerAssetAmount, signedOrder.takerAssetAmount, diff --git a/packages/order-utils/src/order_validation_utils.ts b/packages/order-utils/src/order_validation_utils.ts index 972e6f6d69..8227fb07c6 100644 --- a/packages/order-utils/src/order_validation_utils.ts +++ b/packages/order-utils/src/order_validation_utils.ts @@ -24,7 +24,7 @@ export class OrderValidationUtils { * @param denominator Denominator value. When used to check an order, pass in `order.takerAssetAmount` * @param target Target value. When used to check an order, pass in `order.makerAssetAmount` */ - public static isRoundingError(numerator: BigNumber, denominator: BigNumber, target: BigNumber): boolean { + public static isRoundingErrorFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): boolean { // Solidity's mulmod() in JS // Source: https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#mathematical-and-cryptographic-functions if (denominator.eq(0)) { @@ -58,7 +58,7 @@ export class OrderValidationUtils { zrxAssetData: string, ): Promise { try { - const fillMakerTokenAmount = utils.getPartialAmount( + const fillMakerTokenAmount = utils.getPartialAmountFloor( fillTakerAssetAmount, signedOrder.takerAssetAmount, signedOrder.makerAssetAmount, @@ -79,7 +79,7 @@ export class OrderValidationUtils { TradeSide.Taker, TransferType.Trade, ); - const makerFeeAmount = utils.getPartialAmount( + const makerFeeAmount = utils.getPartialAmountFloor( fillTakerAssetAmount, signedOrder.takerAssetAmount, signedOrder.makerFee, @@ -92,7 +92,7 @@ export class OrderValidationUtils { TradeSide.Maker, TransferType.Fee, ); - const takerFeeAmount = utils.getPartialAmount( + const takerFeeAmount = utils.getPartialAmountFloor( fillTakerAssetAmount, signedOrder.takerAssetAmount, signedOrder.takerFee, @@ -218,7 +218,7 @@ export class OrderValidationUtils { zrxAssetData, ); - const wouldRoundingErrorOccur = OrderValidationUtils.isRoundingError( + const wouldRoundingErrorOccur = OrderValidationUtils.isRoundingErrorFloor( desiredFillTakerTokenAmount, signedOrder.takerAssetAmount, signedOrder.makerAssetAmount, diff --git a/packages/order-utils/src/utils.ts b/packages/order-utils/src/utils.ts index 7aaaf06090..0ff05e8ed2 100644 --- a/packages/order-utils/src/utils.ts +++ b/packages/order-utils/src/utils.ts @@ -12,7 +12,7 @@ export const utils = { const milisecondsInSecond = 1000; return new BigNumber(Date.now() / milisecondsInSecond).round(); }, - getPartialAmount(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber { + getPartialAmountFloor(numerator: BigNumber, denominator: BigNumber, target: BigNumber): BigNumber { const fillMakerTokenAmount = numerator .mul(target) .div(denominator) diff --git a/packages/order-utils/test/order_validation_utils_test.ts b/packages/order-utils/test/order_validation_utils_test.ts index d3ff867d73..d3133c0a64 100644 --- a/packages/order-utils/test/order_validation_utils_test.ts +++ b/packages/order-utils/test/order_validation_utils_test.ts @@ -16,7 +16,7 @@ describe('OrderValidationUtils', () => { const denominator = new BigNumber(999); const target = new BigNumber(50); // rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1% - const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target); + const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target); expect(isRoundingError).to.be.false(); }); @@ -25,7 +25,7 @@ describe('OrderValidationUtils', () => { const denominator = new BigNumber(9991); const target = new BigNumber(500); // rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09% - const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target); + const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target); expect(isRoundingError).to.be.false(); }); @@ -34,7 +34,7 @@ describe('OrderValidationUtils', () => { const denominator = new BigNumber(9989); const target = new BigNumber(500); // rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011% - const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target); + const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target); expect(isRoundingError).to.be.true(); }); @@ -43,7 +43,7 @@ describe('OrderValidationUtils', () => { const denominator = new BigNumber(7); const target = new BigNumber(10); // rounding error = ((3*10/7) - floor(3*10/7)) / (3*10/7) = 6.67% - const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target); + const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target); expect(isRoundingError).to.be.true(); }); @@ -52,7 +52,7 @@ describe('OrderValidationUtils', () => { const denominator = new BigNumber(2); const target = new BigNumber(10); - const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target); + const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target); expect(isRoundingError).to.be.false(); }); @@ -63,7 +63,7 @@ describe('OrderValidationUtils', () => { const target = new BigNumber(105762562); // rounding error = ((76564*105762562/676373677) - floor(76564*105762562/676373677)) / // (76564*105762562/676373677) = 0.0007% - const isRoundingError = OrderValidationUtils.isRoundingError(numerator, denominator, target); + const isRoundingError = OrderValidationUtils.isRoundingErrorFloor(numerator, denominator, target); expect(isRoundingError).to.be.false(); }); }); From bc686fcbf3a0f9eea0c96107b9880314027f2d02 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 24 Aug 2018 16:17:02 -0700 Subject: [PATCH 043/120] Stylistic fixes --- .../2.0.0/protocol/Exchange/libs/LibMath.sol | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol index 7d58f70ce2..0e0fba5d24 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibMath.sol @@ -39,7 +39,10 @@ contract LibMath is pure returns (uint256 partialAmount) { - require(denominator > 0, "DIVISION_BY_ZERO"); + require( + denominator > 0, + "DIVISION_BY_ZERO" + ); partialAmount = safeDiv( safeMul(numerator, target), @@ -62,13 +65,19 @@ contract LibMath is pure returns (uint256 partialAmount) { - require(denominator > 0, "DIVISION_BY_ZERO"); + require( + denominator > 0, + "DIVISION_BY_ZERO" + ); // safeDiv computes `floor(a / b)`. We use the identity (a, b integer): // ceil(a / b) = floor((a + b - 1) / b) // To implement `ceil(a / b)` using safeDiv. partialAmount = safeDiv( - safeAdd(safeMul(numerator, target), safeSub(denominator, 1)), + safeAdd( + safeMul(numerator, target), + safeSub(denominator, 1) + ), denominator ); return partialAmount; @@ -88,7 +97,10 @@ contract LibMath is pure returns (bool isError) { - require(denominator > 0, "DIVISION_BY_ZERO"); + require( + denominator > 0, + "DIVISION_BY_ZERO" + ); // The absolute rounding error is the difference between the rounded // value and the ideal value. The relative rounding error is the @@ -135,7 +147,10 @@ contract LibMath is pure returns (bool isError) { - require(denominator > 0, "DIVISION_BY_ZERO"); + require( + denominator > 0, + "DIVISION_BY_ZERO" + ); // See the comments in `isRoundingError`. if (target == 0 || numerator == 0) { From 11328bd93d498abfcfbfa38ed69db8cb268f12be Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 24 Aug 2018 16:26:48 -0700 Subject: [PATCH 044/120] Skip self-transfers --- .../src/2.0.0/protocol/Exchange/MixinAssetProxyDispatcher.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinAssetProxyDispatcher.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinAssetProxyDispatcher.sol index e9f882194a..80475e6e35 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinAssetProxyDispatcher.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinAssetProxyDispatcher.sol @@ -83,7 +83,7 @@ contract MixinAssetProxyDispatcher is internal { // Do nothing if no amount should be transferred. - if (amount > 0) { + if (amount > 0 && from != to) { // Ensure assetData length is valid require( assetData.length > 3, From e706fa76acfbf933479f767749755446cdaf438a Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 17 Aug 2018 12:11:51 -0700 Subject: [PATCH 045/120] Add overfill and price assertion to assertValidFill --- .../protocol/Exchange/MixinExchangeCore.sol | 32 +++++++++++++++++-- .../Exchange/mixins/MExchangeCore.sol | 2 ++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol index ab5c6e5071..e6b2ddf3db 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol @@ -266,6 +266,7 @@ contract MixinExchangeCore is /// @param takerAddress Address of order taker. /// @param takerAssetFillAmount Desired amount of order to fill by taker. /// @param takerAssetFilledAmount Amount of takerAsset that will be filled. + /// @param makerAssetFilledAmount Amount of makerAsset that will be transfered. /// @param signature Proof that the orders was created by its maker. function assertValidFill( Order memory order, @@ -273,6 +274,7 @@ contract MixinExchangeCore is address takerAddress, uint256 takerAssetFillAmount, uint256 takerAssetFilledAmount, + uint256 makerAssetFilledAmount, bytes memory signature ) internal @@ -297,7 +299,7 @@ contract MixinExchangeCore is "INVALID_SENDER" ); } - + // Validate taker is allowed to fill this order if (order.takerAddress != address(0)) { require( @@ -317,7 +319,33 @@ contract MixinExchangeCore is "INVALID_ORDER_SIGNATURE" ); } - + + // Make sure taker does not pay more than desired amount + // NOTE: This assertion should never fail, it is here + // as an extra defence against potential bugs. + require( + takerAssetFilledAmount <= takerAssetFilledAmount, + "BUG_TAKER_OVERPAY" + ); + + // Make sure order is not overfilled + // NOTE: This assertion should never fail, it is here + // as an extra defence against potential bugs. + require( + safeAdd(orderInfo.orderTakerAssetFilledAmount, takerAssetFilledAmount) <= order.takerAssetAmount, + "BUG_ORDER_OVERFILL" + ); + + // Make sure order is filled at acceptable price + // NOTE: This assertion should never fail, it is here + // as an extra defence against potential bugs. + require( + safeMul(makerAssetFilledAmount, order.takerAssetAmount) + <= + safeMul(takerAssetFilledAmount, order.makerAssetAmount), + "BUG_ORDER_FILL_PRICING" + ); + // Validate fill order rounding require( !isRoundingError( diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MExchangeCore.sol index c165b647cb..eccb6a29d5 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MExchangeCore.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MExchangeCore.sol @@ -90,6 +90,7 @@ contract MExchangeCore is /// @param takerAddress Address of order taker. /// @param takerAssetFillAmount Desired amount of order to fill by taker. /// @param takerAssetFilledAmount Amount of takerAsset that will be filled. + /// @param makerAssetFilledAmount Amount of makerAsset that will be transfered. /// @param signature Proof that the orders was created by its maker. function assertValidFill( LibOrder.Order memory order, @@ -97,6 +98,7 @@ contract MExchangeCore is address takerAddress, uint256 takerAssetFillAmount, uint256 takerAssetFilledAmount, + uint256 makerAssetFilledAmount, bytes memory signature ) internal From d92fd437911a5b9c0af15322e39dd4c2a1f4ab60 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 17 Aug 2018 12:12:27 -0700 Subject: [PATCH 046/120] Update for new assertValidFill signature --- .../src/2.0.0/protocol/Exchange/MixinExchangeCore.sol | 9 +++++---- .../src/2.0.0/protocol/Exchange/MixinMatchOrders.sol | 4 +++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol index e6b2ddf3db..36060a1b62 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol @@ -98,6 +98,9 @@ contract MixinExchangeCore is uint256 remainingTakerAssetAmount = safeSub(order.takerAssetAmount, orderInfo.orderTakerAssetFilledAmount); uint256 takerAssetFilledAmount = min256(takerAssetFillAmount, remainingTakerAssetAmount); + // Compute proportional fill amounts + fillResults = calculateFillResults(order, takerAssetFilledAmount); + // Validate context assertValidFill( order, @@ -105,12 +108,10 @@ contract MixinExchangeCore is takerAddress, takerAssetFillAmount, takerAssetFilledAmount, + fillResults.makerAssetFilledAmount, signature ); - - // Compute proportional fill amounts - fillResults = calculateFillResults(order, takerAssetFilledAmount); - + // Update exchange internal state updateFilledState( order, diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol index 56b309a1bd..4d0411a63f 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol @@ -80,6 +80,7 @@ contract MixinMatchOrders is takerAddress, matchedFillResults.left.takerAssetFilledAmount, matchedFillResults.left.takerAssetFilledAmount, + matchedFillResults.left.makerAssetFilledAmount, leftSignature ); assertValidFill( @@ -88,9 +89,10 @@ contract MixinMatchOrders is takerAddress, matchedFillResults.right.takerAssetFilledAmount, matchedFillResults.right.takerAssetFilledAmount, + matchedFillResults.right.makerAssetFilledAmount, rightSignature ); - + // Update exchange state updateFilledState( leftOrder, From b16f5f55fb66aac624dfb82b881026b588f66b79 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 17 Aug 2018 14:19:19 -0700 Subject: [PATCH 047/120] Check fillable early --- .../src/2.0.0/protocol/Exchange/MixinExchangeCore.sol | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol index 36060a1b62..e281de2645 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol @@ -90,6 +90,12 @@ contract MixinExchangeCore is { // Fetch order info OrderInfo memory orderInfo = getOrderInfo(order); + + // An order can only be filled if its status is FILLABLE. + require( + orderInfo.orderStatus == uint8(OrderStatus.FILLABLE), + "ORDER_UNFILLABLE" + ); // Fetch taker address address takerAddress = getCurrentContextAddress(); From 07e56b3cc7f1171cb199b5f0e286971d0704adb6 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Thu, 23 Aug 2018 15:33:46 -0700 Subject: [PATCH 048/120] Fix taker overpay check --- .../contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol index e281de2645..b3671e7e8a 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol @@ -331,7 +331,7 @@ contract MixinExchangeCore is // NOTE: This assertion should never fail, it is here // as an extra defence against potential bugs. require( - takerAssetFilledAmount <= takerAssetFilledAmount, + takerAssetFilledAmount <= takerAssetFillAmount, "BUG_TAKER_OVERPAY" ); From a1d89435525795f6f412a823241740f10cbdf1d8 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Thu, 23 Aug 2018 16:00:01 -0700 Subject: [PATCH 049/120] Document accetable price check --- .../protocol/Exchange/MixinExchangeCore.sol | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol index b3671e7e8a..e5bd306dd3 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol @@ -343,13 +343,27 @@ contract MixinExchangeCore is "BUG_ORDER_OVERFILL" ); - // Make sure order is filled at acceptable price + // Make sure order is filled at acceptable price. + // The order has an implied price from the makers perspective: + // order price = order.makerAssetAmount / order.takerAssetAmount + // i.e. the number of makerAsset maker is paying per takerAsset. The + // maker is guaranteed to get this price or a better (lower) one. The + // actual price maker is getting in this fill is: + // fill price = makerAssetFilledAmount / takerAssetFilledAmount + // We need `fill price <= order price` for the fill to be fair to maker. + // This amounts to: + // makerAssetFilledAmount order.makerAssetAmount + // ------------------------ <= ----------------------- + // takerAssetFilledAmount order.takerAssetAmount + // or, equivalently: + // makerAssetFilledAmount * order.takerAssetAmount <= + // order.makerAssetAmount * takerAssetFilledAmount // NOTE: This assertion should never fail, it is here // as an extra defence against potential bugs. require( safeMul(makerAssetFilledAmount, order.takerAssetAmount) <= - safeMul(takerAssetFilledAmount, order.makerAssetAmount), + safeMul(order.makerAssetAmount, takerAssetFilledAmount), "BUG_ORDER_FILL_PRICING" ); From e6e7bae4459595343e07c26891577a004b0062eb Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Thu, 23 Aug 2018 16:51:31 -0700 Subject: [PATCH 050/120] Remove BUG_ from revert reasons --- .../src/2.0.0/protocol/Exchange/MixinExchangeCore.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol index e5bd306dd3..1a0a1a135e 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol @@ -332,7 +332,7 @@ contract MixinExchangeCore is // as an extra defence against potential bugs. require( takerAssetFilledAmount <= takerAssetFillAmount, - "BUG_TAKER_OVERPAY" + "TAKER_OVERPAY" ); // Make sure order is not overfilled @@ -340,7 +340,7 @@ contract MixinExchangeCore is // as an extra defence against potential bugs. require( safeAdd(orderInfo.orderTakerAssetFilledAmount, takerAssetFilledAmount) <= order.takerAssetAmount, - "BUG_ORDER_OVERFILL" + "ORDER_OVERFILL" ); // Make sure order is filled at acceptable price. @@ -364,7 +364,7 @@ contract MixinExchangeCore is safeMul(makerAssetFilledAmount, order.takerAssetAmount) <= safeMul(order.makerAssetAmount, takerAssetFilledAmount), - "BUG_ORDER_FILL_PRICING" + "INVALID_FILL_PRICE" ); // Validate fill order rounding From 749c6ecc30d1e52de4ef4f0da5864024d75d2ecb Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Thu, 23 Aug 2018 16:55:13 -0700 Subject: [PATCH 051/120] Add revert reasons to types --- packages/types/src/index.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 4375fc6312..486f71a3ab 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -165,6 +165,7 @@ export interface ERC721AssetData { tokenId: BigNumber; } +// TODO: DRY. These should be extracted from contract code. export enum RevertReason { OrderUnfillable = 'ORDER_UNFILLABLE', InvalidMaker = 'INVALID_MAKER', @@ -176,6 +177,10 @@ export enum RevertReason { InvalidSignature = 'INVALID_SIGNATURE', SignatureIllegal = 'SIGNATURE_ILLEGAL', SignatureUnsupported = 'SIGNATURE_UNSUPPORTED', + InvalidOrderSignature = 'INVALID_ORDER_SIGNATURE', + TakerOverpay = 'TAKER_OVERPAY', + OrderOverfill = 'ORDER_OVERFILL', + InvalidFillPrice = 'INVALID_FILL_PRICE', InvalidNewOrderEpoch = 'INVALID_NEW_ORDER_EPOCH', CompleteFillFailed = 'COMPLETE_FILL_FAILED', NegativeSpreadRequired = 'NEGATIVE_SPREAD_REQUIRED', From 3e4493b389334fa28ae0f0043e4dbda23f21adec Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 24 Aug 2018 10:49:05 -0700 Subject: [PATCH 052/120] Disallow self filling --- .../src/2.0.0/protocol/Exchange/MixinExchangeCore.sol | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol index 1a0a1a135e..b8b3899e8c 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol @@ -314,7 +314,13 @@ contract MixinExchangeCore is "INVALID_TAKER" ); } - + + // Orders can not be self-filled (use cancel instead) + require( + order.makerAddress != takerAddress, + "INVALID_TAKER" + ); + // Validate Maker signature (check only if first time seen) if (orderInfo.orderTakerAssetFilledAmount == 0) { require( From 29971f36cf5c0096dfd3b52c014c52b812a9e9ac Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 24 Aug 2018 13:41:56 -0700 Subject: [PATCH 053/120] Split into assertFillable and assertValidFill --- .../protocol/Exchange/MixinExchangeCore.sol | 54 ++++++++++--------- .../protocol/Exchange/MixinMatchOrders.sol | 18 +++++-- 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol index b8b3899e8c..4fd71092cb 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol @@ -91,14 +91,11 @@ contract MixinExchangeCore is // Fetch order info OrderInfo memory orderInfo = getOrderInfo(order); - // An order can only be filled if its status is FILLABLE. - require( - orderInfo.orderStatus == uint8(OrderStatus.FILLABLE), - "ORDER_UNFILLABLE" - ); - // Fetch taker address address takerAddress = getCurrentContextAddress(); + + // Assert that the order is fillable by taker + assertFillableOrder(order, orderInfo, taker, signature); // Get amount of takerAsset to fill uint256 remainingTakerAssetAmount = safeSub(order.takerAssetAmount, orderInfo.orderTakerAssetFilledAmount); @@ -110,8 +107,6 @@ contract MixinExchangeCore is // Validate context assertValidFill( order, - orderInfo, - takerAddress, takerAssetFillAmount, takerAssetFilledAmount, fillResults.makerAssetFilledAmount, @@ -266,22 +261,16 @@ contract MixinExchangeCore is order.takerAssetData ); } - + /// @dev Validates context for fillOrder. Succeeds or throws. /// @param order to be filled. /// @param orderInfo OrderStatus, orderHash, and amount already filled of order. /// @param takerAddress Address of order taker. - /// @param takerAssetFillAmount Desired amount of order to fill by taker. - /// @param takerAssetFilledAmount Amount of takerAsset that will be filled. - /// @param makerAssetFilledAmount Amount of makerAsset that will be transfered. /// @param signature Proof that the orders was created by its maker. - function assertValidFill( + function assertFillableOrder( Order memory order, OrderInfo memory orderInfo, - address takerAddress, - uint256 takerAssetFillAmount, - uint256 takerAssetFilledAmount, - uint256 makerAssetFilledAmount, + address taker, bytes memory signature ) internal @@ -292,13 +281,7 @@ contract MixinExchangeCore is orderInfo.orderStatus == uint8(OrderStatus.FILLABLE), "ORDER_UNFILLABLE" ); - - // Revert if fill amount is invalid - require( - takerAssetFillAmount != 0, - "INVALID_TAKER_AMOUNT" - ); - + // Validate sender is allowed to fill this order if (order.senderAddress != address(0)) { require( @@ -332,6 +315,29 @@ contract MixinExchangeCore is "INVALID_ORDER_SIGNATURE" ); } + } + + /// @dev Validates context for fillOrder. Succeeds or throws. + /// @param order to be filled. + /// @param takerAssetFillAmount Desired amount of order to fill by taker. + /// @param takerAssetFilledAmount Amount of takerAsset that will be filled. + /// @param makerAssetFilledAmount Amount of makerAsset that will be transfered. + /// @param signature Proof that the orders was created by its maker. + function assertValidFill( + Order memory order, + uint256 takerAssetFillAmount, + uint256 takerAssetFilledAmount, + uint256 makerAssetFilledAmount, + bytes memory signature + ) + internal + view + { + // Revert if fill amount is invalid + require( + takerAssetFillAmount != 0, + "INVALID_TAKER_AMOUNT" + ); // Make sure taker does not pay more than desired amount // NOTE: This assertion should never fail, it is here diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol index 4d0411a63f..5a5b0376e2 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol @@ -61,8 +61,20 @@ contract MixinMatchOrders is // Fetch taker address address takerAddress = getCurrentContextAddress(); - + // Either our context is valid or we revert + assertFillableOrder( + leftOrder, + leftOrderInfo, + takerAddress, + leftSignature + ); + assertFillableOrder( + righttOrder, + righttOrderInfo, + takerAddress, + leftSignature + ); assertValidMatch(leftOrder, rightOrder); // Compute proportional fill amounts @@ -76,8 +88,6 @@ contract MixinMatchOrders is // Validate fill contexts assertValidFill( leftOrder, - leftOrderInfo, - takerAddress, matchedFillResults.left.takerAssetFilledAmount, matchedFillResults.left.takerAssetFilledAmount, matchedFillResults.left.makerAssetFilledAmount, @@ -85,8 +95,6 @@ contract MixinMatchOrders is ); assertValidFill( rightOrder, - rightOrderInfo, - takerAddress, matchedFillResults.right.takerAssetFilledAmount, matchedFillResults.right.takerAssetFilledAmount, matchedFillResults.right.makerAssetFilledAmount, From e6f5cac87887709b5a3baaec059005301723f0a5 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 24 Aug 2018 13:42:10 -0700 Subject: [PATCH 054/120] Fix double definition of error --- packages/types/src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 486f71a3ab..5576a66782 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -177,7 +177,6 @@ export enum RevertReason { InvalidSignature = 'INVALID_SIGNATURE', SignatureIllegal = 'SIGNATURE_ILLEGAL', SignatureUnsupported = 'SIGNATURE_UNSUPPORTED', - InvalidOrderSignature = 'INVALID_ORDER_SIGNATURE', TakerOverpay = 'TAKER_OVERPAY', OrderOverfill = 'ORDER_OVERFILL', InvalidFillPrice = 'INVALID_FILL_PRICE', From e21599285941a092a6c6f2dbf58f14f467dcca85 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 24 Aug 2018 16:13:17 -0700 Subject: [PATCH 055/120] Fix mixin api --- .../protocol/Exchange/MixinExchangeCore.sol | 21 +++++++++------ .../protocol/Exchange/MixinMatchOrders.sol | 14 +++++----- .../Exchange/mixins/MExchangeCore.sol | 26 +++++++++++++------ 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol index 4fd71092cb..dc62db448e 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol @@ -95,7 +95,12 @@ contract MixinExchangeCore is address takerAddress = getCurrentContextAddress(); // Assert that the order is fillable by taker - assertFillableOrder(order, orderInfo, taker, signature); + assertFillableOrder( + order, + orderInfo, + takerAddress, + signature + ); // Get amount of takerAsset to fill uint256 remainingTakerAssetAmount = safeSub(order.takerAssetAmount, orderInfo.orderTakerAssetFilledAmount); @@ -107,10 +112,10 @@ contract MixinExchangeCore is // Validate context assertValidFill( order, + orderInfo, takerAssetFillAmount, takerAssetFilledAmount, - fillResults.makerAssetFilledAmount, - signature + fillResults.makerAssetFilledAmount ); // Update exchange internal state @@ -270,7 +275,7 @@ contract MixinExchangeCore is function assertFillableOrder( Order memory order, OrderInfo memory orderInfo, - address taker, + address takerAddress, bytes memory signature ) internal @@ -319,16 +324,16 @@ contract MixinExchangeCore is /// @dev Validates context for fillOrder. Succeeds or throws. /// @param order to be filled. + /// @param orderInfo OrderStatus, orderHash, and amount already filled of order. /// @param takerAssetFillAmount Desired amount of order to fill by taker. /// @param takerAssetFilledAmount Amount of takerAsset that will be filled. /// @param makerAssetFilledAmount Amount of makerAsset that will be transfered. - /// @param signature Proof that the orders was created by its maker. function assertValidFill( Order memory order, - uint256 takerAssetFillAmount, + OrderInfo memory orderInfo, + uint256 takerAssetFillAmount, // TODO: use FillResults uint256 takerAssetFilledAmount, - uint256 makerAssetFilledAmount, - bytes memory signature + uint256 makerAssetFilledAmount ) internal view diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol index 5a5b0376e2..c860640c4b 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol @@ -70,10 +70,10 @@ contract MixinMatchOrders is leftSignature ); assertFillableOrder( - righttOrder, - righttOrderInfo, + rightOrder, + rightOrderInfo, takerAddress, - leftSignature + rightSignature ); assertValidMatch(leftOrder, rightOrder); @@ -88,17 +88,17 @@ contract MixinMatchOrders is // Validate fill contexts assertValidFill( leftOrder, + leftOrderInfo, matchedFillResults.left.takerAssetFilledAmount, matchedFillResults.left.takerAssetFilledAmount, - matchedFillResults.left.makerAssetFilledAmount, - leftSignature + matchedFillResults.left.makerAssetFilledAmount ); assertValidFill( rightOrder, + rightOrderInfo, matchedFillResults.right.takerAssetFilledAmount, matchedFillResults.right.takerAssetFilledAmount, - matchedFillResults.right.makerAssetFilledAmount, - rightSignature + matchedFillResults.right.makerAssetFilledAmount ); // Update exchange state diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MExchangeCore.sol index eccb6a29d5..708cb329e3 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MExchangeCore.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MExchangeCore.sol @@ -83,23 +83,33 @@ contract MExchangeCore is bytes32 orderHash ) internal; - + /// @dev Validates context for fillOrder. Succeeds or throws. /// @param order to be filled. - /// @param orderInfo Status, orderHash, and amount already filled of order. + /// @param orderInfo OrderStatus, orderHash, and amount already filled of order. /// @param takerAddress Address of order taker. - /// @param takerAssetFillAmount Desired amount of order to fill by taker. - /// @param takerAssetFilledAmount Amount of takerAsset that will be filled. - /// @param makerAssetFilledAmount Amount of makerAsset that will be transfered. /// @param signature Proof that the orders was created by its maker. - function assertValidFill( + function assertFillableOrder( LibOrder.Order memory order, LibOrder.OrderInfo memory orderInfo, address takerAddress, + bytes memory signature + ) + internal + view; + + /// @dev Validates context for fillOrder. Succeeds or throws. + /// @param order to be filled. + /// @param orderInfo Status, orderHash, and amount already filled of order. + /// @param takerAssetFillAmount Desired amount of order to fill by taker. + /// @param takerAssetFilledAmount Amount of takerAsset that will be filled. + /// @param makerAssetFilledAmount Amount of makerAsset that will be transfered. + function assertValidFill( + LibOrder.Order memory order, + LibOrder.OrderInfo memory orderInfo, uint256 takerAssetFillAmount, uint256 takerAssetFilledAmount, - uint256 makerAssetFilledAmount, - bytes memory signature + uint256 makerAssetFilledAmount ) internal view; From cc1fac9bbee2656bdb327490de42922abfc5125a Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Fri, 24 Aug 2018 17:02:42 -0700 Subject: [PATCH 056/120] Fix linting errors --- packages/contracts/test/exchange/internal.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/contracts/test/exchange/internal.ts b/packages/contracts/test/exchange/internal.ts index 14c0ff4cb4..2521665c21 100644 --- a/packages/contracts/test/exchange/internal.ts +++ b/packages/contracts/test/exchange/internal.ts @@ -220,9 +220,9 @@ describe('Exchange core internal functions', () => { numerator: BigNumber, denominator: BigNumber, target: BigNumber, - ) { + ): Promise { if (denominator.eq(0)) { - throw new Error('revert DIVISION_BY_ZERO'); + throw divisionByZeroErrorForCall; } const product = numerator.mul(target); const offset = product.add(denominator.sub(1)); From 6b866d60533c7e46446bfb69639b07affd1aeb17 Mon Sep 17 00:00:00 2001 From: Remco Bloemen Date: Fri, 24 Aug 2018 17:29:52 -0700 Subject: [PATCH 057/120] Revert maker not equal taker check --- .../src/2.0.0/protocol/Exchange/MixinExchangeCore.sol | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol index dc62db448e..515606cb9e 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol @@ -303,12 +303,6 @@ contract MixinExchangeCore is ); } - // Orders can not be self-filled (use cancel instead) - require( - order.makerAddress != takerAddress, - "INVALID_TAKER" - ); - // Validate Maker signature (check only if first time seen) if (orderInfo.orderTakerAssetFilledAmount == 0) { require( @@ -339,6 +333,7 @@ contract MixinExchangeCore is view { // Revert if fill amount is invalid + // TODO: reconsider necessity for v2.1 require( takerAssetFillAmount != 0, "INVALID_TAKER_AMOUNT" From 044415e23d3a079e6301d8fb838da60456794c4f Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Mon, 20 Aug 2018 17:37:23 -0700 Subject: [PATCH 058/120] Remove redundant sload from getCurrentContextAddress --- .../src/2.0.0/protocol/Exchange/MixinTransactions.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinTransactions.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinTransactions.sol index 821d30279c..4a59b6c0f2 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinTransactions.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinTransactions.sol @@ -155,7 +155,8 @@ contract MixinTransactions is view returns (address) { - address contextAddress = currentContextAddress == address(0) ? msg.sender : currentContextAddress; + address currentContextAddress_ = currentContextAddress; + address contextAddress = currentContextAddress_ == address(0) ? msg.sender : currentContextAddress_; return contextAddress; } } From d8cb56caa33885397f557afac5a4ccb24efb47d0 Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Mon, 20 Aug 2018 17:38:25 -0700 Subject: [PATCH 059/120] Add ReentrancyGuard contract --- .../utils/ReentrancyGuard/ReentrancyGuard.sol | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol diff --git a/packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol b/packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol new file mode 100644 index 0000000000..70fc4ca6b4 --- /dev/null +++ b/packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol @@ -0,0 +1,44 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ +pragma solidity 0.4.24; + + +contract ReentrancyGuard { + + // Locked state of mutex + bool private locked = false; + + /// @dev Functions with this modifier cannot be reentered. + modifier nonReentrant() { + // Ensure mutex is unlocked + require( + !locked, + "REENTRANCY_ILLEGAL" + ); + + // Lock mutex before function call + locked = true; + + // Perform function call + _; + + // Unlock mutex after function call + locked = false; + } + +} From 6f88e9bdbdd8f44c45053b8c17c84411f9499084 Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Tue, 21 Aug 2018 16:06:21 -0700 Subject: [PATCH 060/120] Add internal fill functions, add reentrancy guard to public functions that make external calls --- .../protocol/Exchange/MixinExchangeCore.sol | 86 ++++++++++++------- .../protocol/Exchange/MixinMatchOrders.sol | 3 + .../Exchange/MixinWrapperFunctions.sol | 46 ++++++++-- .../Exchange/mixins/MExchangeCore.sol | 13 +++ .../Exchange/mixins/MWrapperFunctions.sol | 40 +++++++++ .../utils/ReentrancyGuard/ReentrancyGuard.sol | 1 - 6 files changed, 148 insertions(+), 41 deletions(-) create mode 100644 packages/contracts/src/2.0.0/protocol/Exchange/mixins/MWrapperFunctions.sol diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol index f3a0591b2f..d00323b154 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol @@ -19,6 +19,7 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; +import "../../utils/ReentrancyGuard/ReentrancyGuard.sol"; import "./libs/LibConstants.sol"; import "./libs/LibFillResults.sol"; import "./libs/LibOrder.sol"; @@ -30,6 +31,7 @@ import "./mixins/MAssetProxyDispatcher.sol"; contract MixinExchangeCore is + ReentrancyGuard, LibConstants, LibMath, LibOrder, @@ -86,43 +88,14 @@ contract MixinExchangeCore is bytes memory signature ) public + nonReentrant returns (FillResults memory fillResults) { - // Fetch order info - OrderInfo memory orderInfo = getOrderInfo(order); - - // Fetch taker address - address takerAddress = getCurrentContextAddress(); - - // Get amount of takerAsset to fill - uint256 remainingTakerAssetAmount = safeSub(order.takerAssetAmount, orderInfo.orderTakerAssetFilledAmount); - uint256 takerAssetFilledAmount = min256(takerAssetFillAmount, remainingTakerAssetAmount); - - // Validate context - assertValidFill( + fillResults = fillOrderInternal( order, - orderInfo, - takerAddress, takerAssetFillAmount, - takerAssetFilledAmount, signature ); - - // Compute proportional fill amounts - fillResults = calculateFillResults(order, takerAssetFilledAmount); - - // Update exchange internal state - updateFilledState( - order, - takerAddress, - orderInfo.orderHash, - orderInfo.orderTakerAssetFilledAmount, - fillResults - ); - - // Settle order - settleOrder(order, takerAddress, fillResults); - return fillResults; } @@ -203,6 +176,57 @@ contract MixinExchangeCore is return orderInfo; } + /// @dev Fills the input order. + /// @param order Order struct containing order specifications. + /// @param takerAssetFillAmount Desired amount of takerAsset to sell. + /// @param signature Proof that order has been created by maker. + /// @return Amounts filled and fees paid by maker and taker. + function fillOrderInternal( + Order memory order, + uint256 takerAssetFillAmount, + bytes memory signature + ) + internal + returns (FillResults memory fillResults) + { + // Fetch order info + OrderInfo memory orderInfo = getOrderInfo(order); + + // Fetch taker address + address takerAddress = getCurrentContextAddress(); + + // Get amount of takerAsset to fill + uint256 remainingTakerAssetAmount = safeSub(order.takerAssetAmount, orderInfo.orderTakerAssetFilledAmount); + uint256 takerAssetFilledAmount = min256(takerAssetFillAmount, remainingTakerAssetAmount); + + // Validate context + assertValidFill( + order, + orderInfo, + takerAddress, + takerAssetFillAmount, + takerAssetFilledAmount, + signature + ); + + // Compute proportional fill amounts + fillResults = calculateFillResults(order, takerAssetFilledAmount); + + // Update exchange internal state + updateFilledState( + order, + takerAddress, + orderInfo.orderHash, + orderInfo.orderTakerAssetFilledAmount, + fillResults + ); + + // Settle order + settleOrder(order, takerAddress, fillResults); + + return fillResults; + } + /// @dev Updates state with results of a fill order. /// @param order that was filled. /// @param takerAddress Address of taker who filled the order. diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol index 20f4b1c334..25220a673e 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol @@ -14,6 +14,7 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; +import "../../utils/ReentrancyGuard/ReentrancyGuard.sol"; import "./libs/LibConstants.sol"; import "./libs/LibMath.sol"; import "./libs/LibOrder.sol"; @@ -25,6 +26,7 @@ import "./mixins/MAssetProxyDispatcher.sol"; contract MixinMatchOrders is + ReentrancyGuard, LibConstants, LibMath, MAssetProxyDispatcher, @@ -48,6 +50,7 @@ contract MixinMatchOrders is bytes memory rightSignature ) public + nonReentrant returns (LibFillResults.MatchedFillResults memory matchedFillResults) { // We assume that rightOrder.takerAssetData == leftOrder.makerAssetData and rightOrder.makerAssetData == leftOrder.takerAssetData. diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol index 1b77cfbcbd..ff1cb6995f 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol @@ -19,14 +19,17 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; +import "../../utils/ReentrancyGuard/ReentrancyGuard.sol"; import "./libs/LibMath.sol"; import "./libs/LibOrder.sol"; import "./libs/LibFillResults.sol"; import "./libs/LibAbiEncoder.sol"; import "./mixins/MExchangeCore.sol"; +import "./mixins/MWrapperFunctions.sol"; contract MixinWrapperFunctions is + ReentrancyGuard, LibMath, LibFillResults, LibAbiEncoder, @@ -43,17 +46,14 @@ contract MixinWrapperFunctions is bytes memory signature ) public + nonReentrant returns (FillResults memory fillResults) { - fillResults = fillOrder( + fillResults = fillOrKillOrderInternal( order, takerAssetFillAmount, signature ); - require( - fillResults.takerAssetFilledAmount == takerAssetFillAmount, - "COMPLETE_FILL_FAILED" - ); return fillResults; } @@ -117,11 +117,12 @@ contract MixinWrapperFunctions is bytes[] memory signatures ) public + nonReentrant returns (FillResults memory totalFillResults) { uint256 ordersLength = orders.length; for (uint256 i = 0; i != ordersLength; i++) { - FillResults memory singleFillResults = fillOrder( + FillResults memory singleFillResults = fillOrderInternal( orders[i], takerAssetFillAmounts[i], signatures[i] @@ -143,11 +144,12 @@ contract MixinWrapperFunctions is bytes[] memory signatures ) public + nonReentrant returns (FillResults memory totalFillResults) { uint256 ordersLength = orders.length; for (uint256 i = 0; i != ordersLength; i++) { - FillResults memory singleFillResults = fillOrKillOrder( + FillResults memory singleFillResults = fillOrKillOrderInternal( orders[i], takerAssetFillAmounts[i], signatures[i] @@ -195,6 +197,7 @@ contract MixinWrapperFunctions is bytes[] memory signatures ) public + nonReentrant returns (FillResults memory totalFillResults) { bytes memory takerAssetData = orders[0].takerAssetData; @@ -210,7 +213,7 @@ contract MixinWrapperFunctions is uint256 remainingTakerAssetFillAmount = safeSub(takerAssetFillAmount, totalFillResults.takerAssetFilledAmount); // Attempt to sell the remaining amount of takerAsset - FillResults memory singleFillResults = fillOrder( + FillResults memory singleFillResults = fillOrderInternal( orders[i], remainingTakerAssetFillAmount, signatures[i] @@ -282,6 +285,7 @@ contract MixinWrapperFunctions is bytes[] memory signatures ) public + nonReentrant returns (FillResults memory totalFillResults) { bytes memory makerAssetData = orders[0].makerAssetData; @@ -305,7 +309,7 @@ contract MixinWrapperFunctions is ); // Attempt to sell the remaining amount of takerAsset - FillResults memory singleFillResults = fillOrder( + FillResults memory singleFillResults = fillOrderInternal( orders[i], remainingTakerAssetFillAmount, signatures[i] @@ -400,4 +404,28 @@ contract MixinWrapperFunctions is } return ordersInfo; } + + /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled. + /// @param order Order struct containing order specifications. + /// @param takerAssetFillAmount Desired amount of takerAsset to sell. + /// @param signature Proof that order has been created by maker. + function fillOrKillOrderInternal( + LibOrder.Order memory order, + uint256 takerAssetFillAmount, + bytes memory signature + ) + internal + returns (FillResults memory fillResults) + { + fillResults = fillOrderInternal( + order, + takerAssetFillAmount, + signature + ); + require( + fillResults.takerAssetFilledAmount == takerAssetFillAmount, + "COMPLETE_FILL_FAILED" + ); + return fillResults; + } } diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MExchangeCore.sol index c165b647cb..41832fe4b2 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MExchangeCore.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MExchangeCore.sol @@ -59,6 +59,19 @@ contract MExchangeCore is uint256 orderEpoch // Orders with specified makerAddress and senderAddress with a salt less than this value are considered cancelled. ); + /// @dev Fills the input order. + /// @param order Order struct containing order specifications. + /// @param takerAssetFillAmount Desired amount of takerAsset to sell. + /// @param signature Proof that order has been created by maker. + /// @return Amounts filled and fees paid by maker and taker. + function fillOrderInternal( + LibOrder.Order memory order, + uint256 takerAssetFillAmount, + bytes memory signature + ) + internal + returns (LibFillResults.FillResults memory fillResults); + /// @dev Updates state with results of a fill order. /// @param order that was filled. /// @param takerAddress Address of taker who filled the order. diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MWrapperFunctions.sol b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MWrapperFunctions.sol new file mode 100644 index 0000000000..e04d4a429b --- /dev/null +++ b/packages/contracts/src/2.0.0/protocol/Exchange/mixins/MWrapperFunctions.sol @@ -0,0 +1,40 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity 0.4.24; +pragma experimental ABIEncoderV2; + +import "../libs/LibOrder.sol"; +import "../libs/LibFillResults.sol"; +import "../interfaces/IWrapperFunctions.sol"; + + +contract MWrapperFunctions { + + /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled. + /// @param order LibOrder.Order struct containing order specifications. + /// @param takerAssetFillAmount Desired amount of takerAsset to sell. + /// @param signature Proof that order has been created by maker. + function fillOrKillOrderInternal( + LibOrder.Order memory order, + uint256 takerAssetFillAmount, + bytes memory signature + ) + internal + returns (LibFillResults.FillResults memory fillResults); +} diff --git a/packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol b/packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol index 70fc4ca6b4..5d6f6970d6 100644 --- a/packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol +++ b/packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol @@ -40,5 +40,4 @@ contract ReentrancyGuard { // Unlock mutex after function call locked = false; } - } From cf12daea2f3a907f6a111c12d1e67c2e8b0a8797 Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Tue, 21 Aug 2018 17:53:40 -0700 Subject: [PATCH 061/120] Add ReentrantToken --- packages/contracts/compiler.json | 1 + packages/contracts/package.json | 2 +- .../ReentrantERC20Token.sol | 173 ++++++++++++++++++ 3 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 packages/contracts/src/2.0.0/test/ReentrantERC20Token/ReentrantERC20Token.sol diff --git a/packages/contracts/compiler.json b/packages/contracts/compiler.json index 27bb69a36d..f66114e875 100644 --- a/packages/contracts/compiler.json +++ b/packages/contracts/compiler.json @@ -40,6 +40,7 @@ "MultiSigWallet", "MultiSigWalletWithTimeLock", "OrderValidator", + "ReentrantERC20Token", "TestAssetProxyOwner", "TestAssetProxyDispatcher", "TestConstants", diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 0ead2f43f8..8d75eb4ce0 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -34,7 +34,7 @@ }, "config": { "abis": - "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|DummyNoReturnERC20Token|ERC20Proxy|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|InvalidERC721Receiver|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|OrderValidator|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestExchangeInternals|TestLibBytes|TestLibs|TestSignatureValidator|TestStaticCallReceiver|Validator|Wallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json" + "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|DummyNoReturnERC20Token|ERC20Proxy|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|InvalidERC721Receiver|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|OrderValidator|ReentrantERC20Token|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestExchangeInternals|TestLibBytes|TestLibs|TestSignatureValidator|Validator|Wallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json" }, "repository": { "type": "git", diff --git a/packages/contracts/src/2.0.0/test/ReentrantERC20Token/ReentrantERC20Token.sol b/packages/contracts/src/2.0.0/test/ReentrantERC20Token/ReentrantERC20Token.sol new file mode 100644 index 0000000000..f5c98177f3 --- /dev/null +++ b/packages/contracts/src/2.0.0/test/ReentrantERC20Token/ReentrantERC20Token.sol @@ -0,0 +1,173 @@ +/* + + Copyright 2018 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +pragma solidity 0.4.24; +pragma experimental ABIEncoderV2; + +import "../../tokens/ERC20Token/ERC20Token.sol"; +import "../../protocol/Exchange/interfaces/IExchange.sol"; +import "../../protocol/Exchange/libs/LibOrder.sol"; + + +contract ReentrantERC20Token is + ERC20Token +{ + // solhint-disable-next-line var-name-mixedcase + IExchange internal EXCHANGE; + + // All of these functions are potentially vulnerable to reentrancy + enum ExchangeFunction { + FILL_ORDER, + FILL_OR_KILL_ORDER, + FILL_ORDER_NO_THROW, + BATCH_FILL_ORDERS, + BATCH_FILL_OR_KILL_ORDERS, + BATCH_FILL_ORDERS_NO_THROW, + MARKET_BUY_ORDERS, + MARKET_BUY_ORDERS_NO_THROW, + MARKET_SELL_ORDERS, + MARKET_SELL_ORDERS_NO_THROW, + MATCH_ORDERS + } + + uint8 internal currentFunctionId = 0; + + constructor (address _exchange) + public + { + EXCHANGE = IExchange(_exchange); + } + + /// @dev Set the current function that will be called when `transferFrom` is called. + /// @param _currentFunctionId Id that corresponds to function name. + function setCurrentFunction(uint8 _currentFunctionId) + external + { + currentFunctionId = _currentFunctionId; + } + + /// @dev A version of `transferFrom` that attempts to reenter the Exchange contract. + /// @param _from The address of the sender + /// @param _to The address of the recipient + /// @param _value The amount of token to be transferred + function transferFrom( + address _from, + address _to, + uint256 _value + ) + external + returns (bool) + { + // This order would normally be invalid, but it will be used strictly for testing reentrnacy. + // Any reentrancy checks will happen before any other checks that invalidate the order. + LibOrder.Order memory order = LibOrder.Order({ + makerAddress: address(0), + takerAddress: address(0), + feeRecipientAddress: address(0), + senderAddress: address(0), + makerAssetAmount: 0, + takerAssetAmount: 0, + makerFee: 0, + takerFee: 0, + expirationTimeSeconds: 0, + salt: 0, + makerAssetData: "", + takerAssetData: "" + }); + + // Initialize remaining null parameters + bytes memory signature = ""; + LibOrder.Order[] memory orders = new LibOrder.Order[](1); + orders[0] = order; + uint256[] memory takerAssetFillAmounts = new uint256[](1); + takerAssetFillAmounts[0] = 0; + bytes[] memory signatures = new bytes[](1); + signatures[0] = signature; + + // Attempt to reenter Exchange by calling function with currentFunctionId + if (currentFunctionId == uint8(ExchangeFunction.FILL_ORDER)) { + EXCHANGE.fillOrder( + order, + 0, + signature + ); + } else if (currentFunctionId == uint8(ExchangeFunction.FILL_OR_KILL_ORDER)) { + EXCHANGE.fillOrKillOrder( + order, + 0, + signature + ); + } else if (currentFunctionId == uint8(ExchangeFunction.FILL_ORDER_NO_THROW)) { + EXCHANGE.fillOrderNoThrow( + order, + 0, + signature + ); + } else if (currentFunctionId == uint8(ExchangeFunction.BATCH_FILL_ORDERS)) { + EXCHANGE.batchFillOrders( + orders, + takerAssetFillAmounts, + signatures + ); + } else if (currentFunctionId == uint8(ExchangeFunction.BATCH_FILL_OR_KILL_ORDERS)) { + EXCHANGE.batchFillOrKillOrders( + orders, + takerAssetFillAmounts, + signatures + ); + } else if (currentFunctionId == uint8(ExchangeFunction.BATCH_FILL_ORDERS_NO_THROW)) { + EXCHANGE.batchFillOrdersNoThrow( + orders, + takerAssetFillAmounts, + signatures + ); + } else if (currentFunctionId == uint8(ExchangeFunction.MARKET_BUY_ORDERS)) { + EXCHANGE.marketBuyOrders( + orders, + 0, + signatures + ); + } else if (currentFunctionId == uint8(ExchangeFunction.MARKET_BUY_ORDERS_NO_THROW)) { + EXCHANGE.marketBuyOrdersNoThrow( + orders, + 0, + signatures + ); + } else if (currentFunctionId == uint8(ExchangeFunction.MARKET_SELL_ORDERS)) { + EXCHANGE.marketSellOrders( + orders, + 0, + signatures + ); + } else if (currentFunctionId == uint8(ExchangeFunction.MARKET_SELL_ORDERS_NO_THROW)) { + EXCHANGE.marketSellOrdersNoThrow( + orders, + 0, + signatures + ); + } else if (currentFunctionId == uint8(ExchangeFunction.MATCH_ORDERS)) { + EXCHANGE.matchOrders( + order, + order, + signature, + signature + ); + } + return true; + } +} \ No newline at end of file From 6d0dedc62cb1be54dbdd287fd59d7b568a199007 Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Wed, 22 Aug 2018 17:57:57 -0700 Subject: [PATCH 062/120] Split modifiers into check only and check, lock, unlock --- .../2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol b/packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol index 5d6f6970d6..2b980c7cad 100644 --- a/packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol +++ b/packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol @@ -31,6 +31,19 @@ contract ReentrancyGuard { "REENTRANCY_ILLEGAL" ); + // Perform function call + _; + } + + /// @dev Functions with this modifer cannot be reentered. The mutex will be locked + /// before function execution and unlocked after. + modifier lockMutex() { + // Ensure mutex is unlocked + require( + !locked, + "REENTRANCY_ILLEGAL" + ); + // Lock mutex before function call locked = true; From c75212bef0b3801ecda09a89d5e30e359dcf1b63 Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Wed, 22 Aug 2018 17:58:47 -0700 Subject: [PATCH 063/120] Add nonReentrant modifiers on functions that use getCurrentContextAddress only, add lockMutex modifier on functions that make external calls --- .../protocol/Exchange/MixinExchangeCore.sol | 4 +++- .../protocol/Exchange/MixinMatchOrders.sol | 2 +- .../Exchange/MixinSignatureValidator.sol | 3 +++ .../Exchange/MixinWrapperFunctions.sol | 23 ++++++++----------- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol index d00323b154..f02514fc6f 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol @@ -56,6 +56,7 @@ contract MixinExchangeCore is /// @param targetOrderEpoch Orders created with a salt less or equal to this value will be cancelled. function cancelOrdersUpTo(uint256 targetOrderEpoch) external + nonReentrant { address makerAddress = getCurrentContextAddress(); // If this function is called via `executeTransaction`, we only update the orderEpoch for the makerAddress/msg.sender combination. @@ -88,7 +89,7 @@ contract MixinExchangeCore is bytes memory signature ) public - nonReentrant + lockMutex returns (FillResults memory fillResults) { fillResults = fillOrderInternal( @@ -104,6 +105,7 @@ contract MixinExchangeCore is /// @param order Order to cancel. Order must be OrderStatus.FILLABLE. function cancelOrder(Order memory order) public + nonReentrant { // Fetch current order status OrderInfo memory orderInfo = getOrderInfo(order); diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol index 25220a673e..39c47e6f9d 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol @@ -50,7 +50,7 @@ contract MixinMatchOrders is bytes memory rightSignature ) public - nonReentrant + lockMutex returns (LibFillResults.MatchedFillResults memory matchedFillResults) { // We assume that rightOrder.takerAssetData == leftOrder.makerAssetData and rightOrder.makerAssetData == leftOrder.takerAssetData. diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol index f30adcdb81..4eb6a2fa6b 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol @@ -19,6 +19,7 @@ pragma solidity 0.4.24; import "../../utils/LibBytes/LibBytes.sol"; +import "../../utils/ReentrancyGuard/ReentrancyGuard.sol"; import "./mixins/MSignatureValidator.sol"; import "./mixins/MTransactions.sol"; import "./interfaces/IWallet.sol"; @@ -26,6 +27,7 @@ import "./interfaces/IValidator.sol"; contract MixinSignatureValidator is + ReentrancyGuard, MSignatureValidator, MTransactions { @@ -69,6 +71,7 @@ contract MixinSignatureValidator is bool approval ) external + nonReentrant { address signerAddress = getCurrentContextAddress(); allowedValidators[signerAddress][validatorAddress] = approval; diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol index ff1cb6995f..b0474b110a 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol @@ -46,7 +46,7 @@ contract MixinWrapperFunctions is bytes memory signature ) public - nonReentrant + lockMutex returns (FillResults memory fillResults) { fillResults = fillOrKillOrderInternal( @@ -69,6 +69,7 @@ contract MixinWrapperFunctions is bytes memory signature ) public + nonReentrant returns (FillResults memory fillResults) { // ABI encode calldata for `fillOrder` @@ -88,14 +89,7 @@ contract MixinWrapperFunctions is fillOrderCalldata, // write output over input 128 // output size is 128 bytes ) - switch success - case 0 { - mstore(fillResults, 0) - mstore(add(fillResults, 32), 0) - mstore(add(fillResults, 64), 0) - mstore(add(fillResults, 96), 0) - } - case 1 { + if success { mstore(fillResults, mload(fillOrderCalldata)) mstore(add(fillResults, 32), mload(add(fillOrderCalldata, 32))) mstore(add(fillResults, 64), mload(add(fillOrderCalldata, 64))) @@ -117,7 +111,7 @@ contract MixinWrapperFunctions is bytes[] memory signatures ) public - nonReentrant + lockMutex returns (FillResults memory totalFillResults) { uint256 ordersLength = orders.length; @@ -144,7 +138,7 @@ contract MixinWrapperFunctions is bytes[] memory signatures ) public - nonReentrant + lockMutex returns (FillResults memory totalFillResults) { uint256 ordersLength = orders.length; @@ -172,6 +166,7 @@ contract MixinWrapperFunctions is bytes[] memory signatures ) public + nonReentrant returns (FillResults memory totalFillResults) { uint256 ordersLength = orders.length; @@ -197,7 +192,7 @@ contract MixinWrapperFunctions is bytes[] memory signatures ) public - nonReentrant + lockMutex returns (FillResults memory totalFillResults) { bytes memory takerAssetData = orders[0].takerAssetData; @@ -242,6 +237,7 @@ contract MixinWrapperFunctions is bytes[] memory signatures ) public + nonReentrant returns (FillResults memory totalFillResults) { bytes memory takerAssetData = orders[0].takerAssetData; @@ -285,7 +281,7 @@ contract MixinWrapperFunctions is bytes[] memory signatures ) public - nonReentrant + lockMutex returns (FillResults memory totalFillResults) { bytes memory makerAssetData = orders[0].makerAssetData; @@ -338,6 +334,7 @@ contract MixinWrapperFunctions is bytes[] memory signatures ) public + nonReentrant returns (FillResults memory totalFillResults) { bytes memory makerAssetData = orders[0].makerAssetData; From 56c3c29febe6264eee7f1c3f1ed8f1dc7c4685c6 Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Wed, 22 Aug 2018 18:00:01 -0700 Subject: [PATCH 064/120] Update ReentrantERC20Token with new functions and check that revert is occuring for correct reason --- .../ReentrantERC20Token.sol | 110 ++++++++++++------ 1 file changed, 75 insertions(+), 35 deletions(-) diff --git a/packages/contracts/src/2.0.0/test/ReentrantERC20Token/ReentrantERC20Token.sol b/packages/contracts/src/2.0.0/test/ReentrantERC20Token/ReentrantERC20Token.sol index f5c98177f3..8d575d09a0 100644 --- a/packages/contracts/src/2.0.0/test/ReentrantERC20Token/ReentrantERC20Token.sol +++ b/packages/contracts/src/2.0.0/test/ReentrantERC20Token/ReentrantERC20Token.sol @@ -19,6 +19,7 @@ pragma solidity 0.4.24; pragma experimental ABIEncoderV2; +import "../../utils/LibBytes/LibBytes.sol"; import "../../tokens/ERC20Token/ERC20Token.sol"; import "../../protocol/Exchange/interfaces/IExchange.sol"; import "../../protocol/Exchange/libs/LibOrder.sol"; @@ -27,9 +28,17 @@ import "../../protocol/Exchange/libs/LibOrder.sol"; contract ReentrantERC20Token is ERC20Token { + + using LibBytes for bytes; + // solhint-disable-next-line var-name-mixedcase IExchange internal EXCHANGE; + bytes internal constant REENTRANCY_ILLEGAL_REVERT_REASON = abi.encodeWithSelector( + bytes4(keccak256("Error(string)")), + "REENTRANCY_ILLEGAL" + ); + // All of these functions are potentially vulnerable to reentrancy enum ExchangeFunction { FILL_ORDER, @@ -42,7 +51,10 @@ contract ReentrantERC20Token is MARKET_BUY_ORDERS_NO_THROW, MARKET_SELL_ORDERS, MARKET_SELL_ORDERS_NO_THROW, - MATCH_ORDERS + MATCH_ORDERS, + CANCEL_ORDER, + CANCEL_ORDERS_UP_TO, + SET_SIGNATURE_VALIDATOR_APPROVAL } uint8 internal currentFunctionId = 0; @@ -75,99 +87,127 @@ contract ReentrantERC20Token is { // This order would normally be invalid, but it will be used strictly for testing reentrnacy. // Any reentrancy checks will happen before any other checks that invalidate the order. - LibOrder.Order memory order = LibOrder.Order({ - makerAddress: address(0), - takerAddress: address(0), - feeRecipientAddress: address(0), - senderAddress: address(0), - makerAssetAmount: 0, - takerAssetAmount: 0, - makerFee: 0, - takerFee: 0, - expirationTimeSeconds: 0, - salt: 0, - makerAssetData: "", - takerAssetData: "" - }); + LibOrder.Order memory order; // Initialize remaining null parameters - bytes memory signature = ""; - LibOrder.Order[] memory orders = new LibOrder.Order[](1); - orders[0] = order; - uint256[] memory takerAssetFillAmounts = new uint256[](1); - takerAssetFillAmounts[0] = 0; - bytes[] memory signatures = new bytes[](1); - signatures[0] = signature; - - // Attempt to reenter Exchange by calling function with currentFunctionId + bytes memory signature; + LibOrder.Order[] memory orders; + uint256[] memory takerAssetFillAmounts; + bytes[] memory signatures; + bytes memory calldata; + + // Create calldata for function that corresponds to currentFunctionId if (currentFunctionId == uint8(ExchangeFunction.FILL_ORDER)) { - EXCHANGE.fillOrder( + calldata = abi.encodeWithSelector( + EXCHANGE.fillOrder.selector, order, 0, signature ); } else if (currentFunctionId == uint8(ExchangeFunction.FILL_OR_KILL_ORDER)) { - EXCHANGE.fillOrKillOrder( + calldata = abi.encodeWithSelector( + EXCHANGE.fillOrKillOrder.selector, order, 0, signature ); } else if (currentFunctionId == uint8(ExchangeFunction.FILL_ORDER_NO_THROW)) { - EXCHANGE.fillOrderNoThrow( + calldata = abi.encodeWithSelector( + EXCHANGE.fillOrderNoThrow.selector, order, 0, signature ); } else if (currentFunctionId == uint8(ExchangeFunction.BATCH_FILL_ORDERS)) { - EXCHANGE.batchFillOrders( + calldata = abi.encodeWithSelector( + EXCHANGE.batchFillOrders.selector, orders, takerAssetFillAmounts, signatures ); } else if (currentFunctionId == uint8(ExchangeFunction.BATCH_FILL_OR_KILL_ORDERS)) { - EXCHANGE.batchFillOrKillOrders( + calldata = abi.encodeWithSelector( + EXCHANGE.batchFillOrKillOrders.selector, orders, takerAssetFillAmounts, signatures ); } else if (currentFunctionId == uint8(ExchangeFunction.BATCH_FILL_ORDERS_NO_THROW)) { - EXCHANGE.batchFillOrdersNoThrow( + calldata = abi.encodeWithSelector( + EXCHANGE.batchFillOrdersNoThrow.selector, orders, takerAssetFillAmounts, signatures ); } else if (currentFunctionId == uint8(ExchangeFunction.MARKET_BUY_ORDERS)) { - EXCHANGE.marketBuyOrders( + calldata = abi.encodeWithSelector( + EXCHANGE.marketBuyOrders.selector, orders, 0, signatures ); } else if (currentFunctionId == uint8(ExchangeFunction.MARKET_BUY_ORDERS_NO_THROW)) { - EXCHANGE.marketBuyOrdersNoThrow( + calldata = abi.encodeWithSelector( + EXCHANGE.marketBuyOrdersNoThrow.selector, orders, 0, signatures ); } else if (currentFunctionId == uint8(ExchangeFunction.MARKET_SELL_ORDERS)) { - EXCHANGE.marketSellOrders( + calldata = abi.encodeWithSelector( + EXCHANGE.marketSellOrders.selector, orders, 0, signatures ); } else if (currentFunctionId == uint8(ExchangeFunction.MARKET_SELL_ORDERS_NO_THROW)) { - EXCHANGE.marketSellOrdersNoThrow( + calldata = abi.encodeWithSelector( + EXCHANGE.marketSellOrdersNoThrow.selector, orders, 0, signatures ); } else if (currentFunctionId == uint8(ExchangeFunction.MATCH_ORDERS)) { - EXCHANGE.matchOrders( + calldata = abi.encodeWithSelector( + EXCHANGE.matchOrders.selector, order, order, signature, signature ); + } else if (currentFunctionId == uint8(ExchangeFunction.CANCEL_ORDER)) { + calldata = abi.encodeWithSelector( + EXCHANGE.cancelOrder.selector, + order + ); + } else if (currentFunctionId == uint8(ExchangeFunction.CANCEL_ORDERS_UP_TO)) { + calldata = abi.encodeWithSelector( + EXCHANGE.cancelOrdersUpTo.selector, + 0 + ); + } else if (currentFunctionId == uint8(ExchangeFunction.SET_SIGNATURE_VALIDATOR_APPROVAL)) { + calldata = abi.encodeWithSelector( + EXCHANGE.setSignatureValidatorApproval.selector, + address(0), + false + ); } + + // Call Exchange function, swallow error + address(EXCHANGE).call(calldata); + + // Revert reason is 100 bytes + bytes memory returnData = new bytes(100); + + // Copy return data + assembly { + returndatacopy(add(returnData, 32), 0, 100) + } + + // Revert if function reverted with REENTRANCY_ILLEGAL error + require(!REENTRANCY_ILLEGAL_REVERT_REASON.equals(returnData)); + + // Transfer will return true if function failed for any other reason return true; } } \ No newline at end of file From 7d5a23969d5514ca3c942f11a48a8e858b9d0188 Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Wed, 22 Aug 2018 18:01:45 -0700 Subject: [PATCH 065/120] Add reentrancy tests for fillOrder and wrapper functions --- packages/contracts/test/exchange/core.ts | 28 +++ packages/contracts/test/exchange/wrapper.ts | 193 ++++++++++++++++++++ packages/contracts/test/utils/artifacts.ts | 2 + packages/contracts/test/utils/constants.ts | 16 ++ 4 files changed, 239 insertions(+) diff --git a/packages/contracts/test/exchange/core.ts b/packages/contracts/test/exchange/core.ts index f9d8b77830..8ba55a0abc 100644 --- a/packages/contracts/test/exchange/core.ts +++ b/packages/contracts/test/exchange/core.ts @@ -14,6 +14,7 @@ import { DummyNoReturnERC20TokenContract } from '../../generated_contract_wrappe import { ERC20ProxyContract } from '../../generated_contract_wrappers/erc20_proxy'; import { ERC721ProxyContract } from '../../generated_contract_wrappers/erc721_proxy'; import { ExchangeCancelEventArgs, ExchangeContract } from '../../generated_contract_wrappers/exchange'; +import { ReentrantERC20TokenContract } from '../../generated_contract_wrappers/reentrant_erc20_token'; import { TestStaticCallReceiverContract } from '../../generated_contract_wrappers/test_static_call_receiver'; import { artifacts } from '../utils/artifacts'; import { expectTransactionFailedAsync } from '../utils/assertions'; @@ -42,6 +43,7 @@ describe('Exchange core', () => { let zrxToken: DummyERC20TokenContract; let erc721Token: DummyERC721TokenContract; let noReturnErc20Token: DummyNoReturnERC20TokenContract; + let reentrantErc20Token: ReentrantERC20TokenContract; let exchange: ExchangeContract; let erc20Proxy: ERC20ProxyContract; let erc721Proxy: ERC721ProxyContract; @@ -117,6 +119,12 @@ describe('Exchange core', () => { provider, txDefaults, ); + reentrantErc20Token = await ReentrantERC20TokenContract.deployFrom0xArtifactAsync( + artifacts.ReentrantERC20Token, + provider, + txDefaults, + exchange.address, + ); defaultMakerAssetAddress = erc20TokenA.address; defaultTakerAssetAddress = erc20TokenB.address; @@ -144,6 +152,26 @@ describe('Exchange core', () => { signedOrder = await orderFactory.newSignedOrderAsync(); }); + const reentrancyTest = (functionNames: string[]) => { + _.forEach(functionNames, async (functionName: string, functionId: number) => { + const description = `should not allow fillOrder to reenter the Exchange contract via ${functionName}`; + it(description, async () => { + signedOrder = await orderFactory.newSignedOrderAsync({ + makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address), + }); + await web3Wrapper.awaitTransactionSuccessAsync( + await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + await expectTransactionFailedAsync( + exchangeWrapper.fillOrderAsync(signedOrder, takerAddress), + RevertReason.TransferFailed, + ); + }); + }); + }; + describe('fillOrder reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX)); + it('should throw if signature is invalid', async () => { signedOrder = await orderFactory.newSignedOrderAsync({ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), diff --git a/packages/contracts/test/exchange/wrapper.ts b/packages/contracts/test/exchange/wrapper.ts index d48441dca0..aadb5ab597 100644 --- a/packages/contracts/test/exchange/wrapper.ts +++ b/packages/contracts/test/exchange/wrapper.ts @@ -11,6 +11,7 @@ import { DummyERC721TokenContract } from '../../generated_contract_wrappers/dumm import { ERC20ProxyContract } from '../../generated_contract_wrappers/erc20_proxy'; import { ERC721ProxyContract } from '../../generated_contract_wrappers/erc721_proxy'; import { ExchangeContract } from '../../generated_contract_wrappers/exchange'; +import { ReentrantERC20TokenContract } from '../../generated_contract_wrappers/reentrant_erc20_token'; import { artifacts } from '../utils/artifacts'; import { expectTransactionFailedAsync } from '../utils/assertions'; import { getLatestBlockTimestampAsync, increaseTimeAndMineBlockAsync } from '../utils/block_timestamp'; @@ -40,6 +41,7 @@ describe('Exchange wrappers', () => { let exchange: ExchangeContract; let erc20Proxy: ERC20ProxyContract; let erc721Proxy: ERC721ProxyContract; + let reentrantErc20Token: ReentrantERC20TokenContract; let exchangeWrapper: ExchangeWrapper; let erc20Wrapper: ERC20Wrapper; @@ -104,6 +106,13 @@ describe('Exchange wrappers', () => { constants.AWAIT_TRANSACTION_MINED_MS, ); + reentrantErc20Token = await ReentrantERC20TokenContract.deployFrom0xArtifactAsync( + artifacts.ReentrantERC20Token, + provider, + txDefaults, + exchange.address, + ); + defaultMakerAssetAddress = erc20TokenA.address; defaultTakerAssetAddress = erc20TokenB.address; @@ -126,6 +135,26 @@ describe('Exchange wrappers', () => { await blockchainLifecycle.revertAsync(); }); describe('fillOrKillOrder', () => { + const reentrancyTest = (functionNames: string[]) => { + _.forEach(functionNames, async (functionName: string, functionId: number) => { + const description = `should not allow fillOrKillOrder to reenter the Exchange contract via ${functionName}`; + it(description, async () => { + const signedOrder = await orderFactory.newSignedOrderAsync({ + makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address), + }); + await web3Wrapper.awaitTransactionSuccessAsync( + await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + await expectTransactionFailedAsync( + exchangeWrapper.fillOrKillOrderAsync(signedOrder, takerAddress), + RevertReason.TransferFailed, + ); + }); + }); + }; + describe('fillOrKillOrder reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX)); + it('should transfer the correct amounts', async () => { const signedOrder = await orderFactory.newSignedOrderAsync({ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), @@ -197,6 +226,25 @@ describe('Exchange wrappers', () => { }); describe('fillOrderNoThrow', () => { + const reentrancyTest = (functionNames: string[]) => { + _.forEach(functionNames, async (functionName: string, functionId: number) => { + const description = `should not allow fillOrderNoThrow to reenter the Exchange contract via ${functionName}`; + it(description, async () => { + const signedOrder = await orderFactory.newSignedOrderAsync({ + makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address), + }); + await web3Wrapper.awaitTransactionSuccessAsync( + await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + await exchangeWrapper.fillOrderNoThrowAsync(signedOrder, takerAddress); + const newBalances = await erc20Wrapper.getBalancesAsync(); + expect(erc20Balances).to.deep.equal(newBalances); + }); + }); + }; + describe('fillOrderNoThrow reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX)); + it('should transfer the correct amounts', async () => { const signedOrder = await orderFactory.newSignedOrderAsync({ makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), @@ -397,6 +445,26 @@ describe('Exchange wrappers', () => { }); describe('batchFillOrders', () => { + const reentrancyTest = (functionNames: string[]) => { + _.forEach(functionNames, async (functionName: string, functionId: number) => { + const description = `should not allow batchFillOrders to reenter the Exchange contract via ${functionName}`; + it(description, async () => { + const signedOrder = await orderFactory.newSignedOrderAsync({ + makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address), + }); + await web3Wrapper.awaitTransactionSuccessAsync( + await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + await expectTransactionFailedAsync( + exchangeWrapper.batchFillOrdersAsync([signedOrder], takerAddress), + RevertReason.TransferFailed, + ); + }); + }); + }; + describe('batchFillOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX)); + it('should transfer the correct amounts', async () => { const takerAssetFillAmounts: BigNumber[] = []; const makerAssetAddress = erc20TokenA.address; @@ -446,6 +514,26 @@ describe('Exchange wrappers', () => { }); describe('batchFillOrKillOrders', () => { + const reentrancyTest = (functionNames: string[]) => { + _.forEach(functionNames, async (functionName: string, functionId: number) => { + const description = `should not allow batchFillOrKillOrders to reenter the Exchange contract via ${functionName}`; + it(description, async () => { + const signedOrder = await orderFactory.newSignedOrderAsync({ + makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address), + }); + await web3Wrapper.awaitTransactionSuccessAsync( + await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + await expectTransactionFailedAsync( + exchangeWrapper.batchFillOrKillOrdersAsync([signedOrder], takerAddress), + RevertReason.TransferFailed, + ); + }); + }); + }; + describe('batchFillOrKillOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX)); + it('should transfer the correct amounts', async () => { const takerAssetFillAmounts: BigNumber[] = []; const makerAssetAddress = erc20TokenA.address; @@ -512,6 +600,25 @@ describe('Exchange wrappers', () => { }); describe('batchFillOrdersNoThrow', async () => { + const reentrancyTest = (functionNames: string[]) => { + _.forEach(functionNames, async (functionName: string, functionId: number) => { + const description = `should not allow batchFillOrdersNoThrow to reenter the Exchange contract via ${functionName}`; + it(description, async () => { + const signedOrder = await orderFactory.newSignedOrderAsync({ + makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address), + }); + await web3Wrapper.awaitTransactionSuccessAsync( + await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + await exchangeWrapper.batchFillOrdersNoThrowAsync([signedOrder], takerAddress); + const newBalances = await erc20Wrapper.getBalancesAsync(); + expect(erc20Balances).to.deep.equal(newBalances); + }); + }); + }; + describe('batchFillOrdersNoThrow reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX)); + it('should transfer the correct amounts', async () => { const takerAssetFillAmounts: BigNumber[] = []; const makerAssetAddress = erc20TokenA.address; @@ -625,6 +732,28 @@ describe('Exchange wrappers', () => { }); describe('marketSellOrders', () => { + const reentrancyTest = (functionNames: string[]) => { + _.forEach(functionNames, async (functionName: string, functionId: number) => { + const description = `should not allow marketSellOrders to reenter the Exchange contract via ${functionName}`; + it(description, async () => { + const signedOrder = await orderFactory.newSignedOrderAsync({ + makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address), + }); + await web3Wrapper.awaitTransactionSuccessAsync( + await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + await expectTransactionFailedAsync( + exchangeWrapper.marketSellOrdersAsync([signedOrder], takerAddress, { + takerAssetFillAmount: signedOrder.takerAssetAmount, + }), + RevertReason.TransferFailed, + ); + }); + }); + }; + describe('marketSellOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX)); + it('should stop when the entire takerAssetFillAmount is filled', async () => { const takerAssetFillAmount = signedOrders[0].takerAssetAmount.plus( signedOrders[1].takerAssetAmount.div(2), @@ -717,6 +846,27 @@ describe('Exchange wrappers', () => { }); describe('marketSellOrdersNoThrow', () => { + const reentrancyTest = (functionNames: string[]) => { + _.forEach(functionNames, async (functionName: string, functionId: number) => { + const description = `should not allow marketSellOrdersNoThrow to reenter the Exchange contract via ${functionName}`; + it(description, async () => { + const signedOrder = await orderFactory.newSignedOrderAsync({ + makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address), + }); + await web3Wrapper.awaitTransactionSuccessAsync( + await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + await exchangeWrapper.marketSellOrdersNoThrowAsync([signedOrder], takerAddress, { + takerAssetFillAmount: signedOrder.takerAssetAmount, + }); + const newBalances = await erc20Wrapper.getBalancesAsync(); + expect(erc20Balances).to.deep.equal(newBalances); + }); + }); + }; + describe('marketSellOrdersNoThrow reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX)); + it('should stop when the entire takerAssetFillAmount is filled', async () => { const takerAssetFillAmount = signedOrders[0].takerAssetAmount.plus( signedOrders[1].takerAssetAmount.div(2), @@ -843,6 +993,28 @@ describe('Exchange wrappers', () => { }); describe('marketBuyOrders', () => { + const reentrancyTest = (functionNames: string[]) => { + _.forEach(functionNames, async (functionName: string, functionId: number) => { + const description = `should not allow marketBuyOrders to reenter the Exchange contract via ${functionName}`; + it(description, async () => { + const signedOrder = await orderFactory.newSignedOrderAsync({ + makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address), + }); + await web3Wrapper.awaitTransactionSuccessAsync( + await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + await expectTransactionFailedAsync( + exchangeWrapper.marketBuyOrdersAsync([signedOrder], takerAddress, { + makerAssetFillAmount: signedOrder.makerAssetAmount, + }), + RevertReason.TransferFailed, + ); + }); + }); + }; + describe('marketBuyOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX)); + it('should stop when the entire makerAssetFillAmount is filled', async () => { const makerAssetFillAmount = signedOrders[0].makerAssetAmount.plus( signedOrders[1].makerAssetAmount.div(2), @@ -933,6 +1105,27 @@ describe('Exchange wrappers', () => { }); describe('marketBuyOrdersNoThrow', () => { + const reentrancyTest = (functionNames: string[]) => { + _.forEach(functionNames, async (functionName: string, functionId: number) => { + const description = `should not allow marketBuyOrdersNoThrow to reenter the Exchange contract via ${functionName}`; + it(description, async () => { + const signedOrder = await orderFactory.newSignedOrderAsync({ + makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address), + }); + await web3Wrapper.awaitTransactionSuccessAsync( + await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + await exchangeWrapper.marketBuyOrdersNoThrowAsync([signedOrder], takerAddress, { + makerAssetFillAmount: signedOrder.makerAssetAmount, + }); + const newBalances = await erc20Wrapper.getBalancesAsync(); + expect(erc20Balances).to.deep.equal(newBalances); + }); + }); + }; + describe('marketBuyOrdersNoThrow reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX)); + it('should stop when the entire makerAssetFillAmount is filled', async () => { const makerAssetFillAmount = signedOrders[0].makerAssetAmount.plus( signedOrders[1].makerAssetAmount.div(2), diff --git a/packages/contracts/test/utils/artifacts.ts b/packages/contracts/test/utils/artifacts.ts index 2f6fcef719..5ddb5cc7f1 100644 --- a/packages/contracts/test/utils/artifacts.ts +++ b/packages/contracts/test/utils/artifacts.ts @@ -16,6 +16,7 @@ import * as MixinAuthorizable from '../../artifacts/MixinAuthorizable.json'; import * as MultiSigWallet from '../../artifacts/MultiSigWallet.json'; import * as MultiSigWalletWithTimeLock from '../../artifacts/MultiSigWalletWithTimeLock.json'; import * as OrderValidator from '../../artifacts/OrderValidator.json'; +import * as ReentrantERC20Token from '../../artifacts/ReentrantERC20Token.json'; import * as TestAssetProxyDispatcher from '../../artifacts/TestAssetProxyDispatcher.json'; import * as TestAssetProxyOwner from '../../artifacts/TestAssetProxyOwner.json'; import * as TestConstants from '../../artifacts/TestConstants.json'; @@ -49,6 +50,7 @@ export const artifacts = { MultiSigWallet: (MultiSigWallet as any) as ContractArtifact, MultiSigWalletWithTimeLock: (MultiSigWalletWithTimeLock as any) as ContractArtifact, OrderValidator: (OrderValidator as any) as ContractArtifact, + ReentrantERC20Token: (ReentrantERC20Token as any) as ContractArtifact, TestAssetProxyOwner: (TestAssetProxyOwner as any) as ContractArtifact, TestAssetProxyDispatcher: (TestAssetProxyDispatcher as any) as ContractArtifact, TestConstants: (TestConstants as any) as ContractArtifact, diff --git a/packages/contracts/test/utils/constants.ts b/packages/contracts/test/utils/constants.ts index 65eaee3984..7060b5091b 100644 --- a/packages/contracts/test/utils/constants.ts +++ b/packages/contracts/test/utils/constants.ts @@ -51,4 +51,20 @@ export const constants = { WORD_LENGTH: 32, ZERO_AMOUNT: new BigNumber(0), PERCENTAGE_DENOMINATOR: new BigNumber(10).pow(18), + FUNCTIONS_WITH_MUTEX: [ + 'FILL_ORDER', + 'FILL_OR_KILL_ORDER', + 'FILL_ORDER_NO_THROW', + 'BATCH_FILL_ORDERS', + 'BATCH_FILL_OR_KILL_ORDERS', + 'BATCH_FILL_ORDERS_NO_THROW', + 'MARKET_BUY_ORDERS', + 'MARKET_BUY_ORDERS_NO_THROW', + 'MARKET_SELL_ORDERS', + 'MARKET_SELL_ORDERS_NO_THROW', + 'MATCH_ORDERS', + 'CANCEL_ORDER', + 'CANCEL_ORDERS_UP_TO', + 'SET_SIGNATURE_VALIDATOR_APPROVAL', + ], }; From a09ee907396d35468e0ad632fb990cb1c8870b49 Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Wed, 22 Aug 2018 23:27:43 -0700 Subject: [PATCH 066/120] Add tests for matchOrders --- packages/contracts/test/exchange/core.ts | 2 +- .../contracts/test/exchange/match_orders.ts | 173 ++++++------------ 2 files changed, 53 insertions(+), 122 deletions(-) diff --git a/packages/contracts/test/exchange/core.ts b/packages/contracts/test/exchange/core.ts index 8ba55a0abc..3bb71b58f9 100644 --- a/packages/contracts/test/exchange/core.ts +++ b/packages/contracts/test/exchange/core.ts @@ -530,7 +530,7 @@ describe('Exchange core', () => { // HACK(albrow): We need to hardcode the gas estimate here because // the Geth gas estimator doesn't work with the way we use // delegatecall and swallow errors. - gas: 490000, + gas: 600000, }); const newBalances = await erc20Wrapper.getBalancesAsync(); diff --git a/packages/contracts/test/exchange/match_orders.ts b/packages/contracts/test/exchange/match_orders.ts index 46b3569bd6..8cd873a850 100644 --- a/packages/contracts/test/exchange/match_orders.ts +++ b/packages/contracts/test/exchange/match_orders.ts @@ -11,6 +11,7 @@ import { DummyERC721TokenContract } from '../../generated_contract_wrappers/dumm import { ERC20ProxyContract } from '../../generated_contract_wrappers/erc20_proxy'; import { ERC721ProxyContract } from '../../generated_contract_wrappers/erc721_proxy'; import { ExchangeContract } from '../../generated_contract_wrappers/exchange'; +import { ReentrantERC20TokenContract } from '../../generated_contract_wrappers/reentrant_erc20_token'; import { artifacts } from '../utils/artifacts'; import { expectTransactionFailedAsync } from '../utils/assertions'; import { chaiSetup } from '../utils/chai_setup'; @@ -39,6 +40,7 @@ describe('matchOrders', () => { let erc20TokenB: DummyERC20TokenContract; let zrxToken: DummyERC20TokenContract; let erc721Token: DummyERC721TokenContract; + let reentrantErc20Token: ReentrantERC20TokenContract; let exchange: ExchangeContract; let erc20Proxy: ERC20ProxyContract; let erc721Proxy: ERC721ProxyContract; @@ -127,21 +129,39 @@ describe('matchOrders', () => { }), constants.AWAIT_TRANSACTION_MINED_MS, ); + + reentrantErc20Token = await ReentrantERC20TokenContract.deployFrom0xArtifactAsync( + artifacts.ReentrantERC20Token, + provider, + txDefaults, + exchange.address, + ); + // Set default addresses defaultERC20MakerAssetAddress = erc20TokenA.address; defaultERC20TakerAssetAddress = erc20TokenB.address; defaultERC721AssetAddress = erc721Token.address; // Create default order parameters - const defaultOrderParams = { + const defaultOrderParamsLeft = { ...constants.STATIC_ORDER_PARAMS, + makerAddress: makerAddressLeft, exchangeAddress: exchange.address, makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), + feeRecipientAddress: feeRecipientAddressLeft, + }; + const defaultOrderParamsRight = { + ...constants.STATIC_ORDER_PARAMS, + makerAddress: makerAddressRight, + exchangeAddress: exchange.address, + makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), + takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), + feeRecipientAddress: feeRecipientAddressRight, }; const privateKeyLeft = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressLeft)]; - orderFactoryLeft = new OrderFactory(privateKeyLeft, defaultOrderParams); + orderFactoryLeft = new OrderFactory(privateKeyLeft, defaultOrderParamsLeft); const privateKeyRight = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressRight)]; - orderFactoryRight = new OrderFactory(privateKeyRight, defaultOrderParams); + orderFactoryRight = new OrderFactory(privateKeyRight, defaultOrderParamsRight); // Set match order tester matchOrderTester = new MatchOrderTester(exchangeWrapper, erc20Wrapper, erc721Wrapper, zrxToken.address); }); @@ -157,21 +177,44 @@ describe('matchOrders', () => { erc721TokenIdsByOwner = await erc721Wrapper.getBalancesAsync(); }); + const reentrancyTest = (functionNames: string[]) => { + _.forEach(functionNames, async (functionName: string, functionId: number) => { + const description = `should not allow matchOrders to reenter the Exchange contract via ${functionName}`; + it(description, async () => { + const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ + makerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address), + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + }); + const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ + makerAddress: makerAddressRight, + takerAssetData: assetDataUtils.encodeERC20AssetData(reentrantErc20Token.address), + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), + feeRecipientAddress: feeRecipientAddressRight, + }); + await web3Wrapper.awaitTransactionSuccessAsync( + await reentrantErc20Token.setCurrentFunction.sendTransactionAsync(functionId), + constants.AWAIT_TRANSACTION_MINED_MS, + ); + await expectTransactionFailedAsync( + exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress), + RevertReason.TransferFailed, + ); + }); + }); + }; + describe('matchOrders reentrancy tests', () => reentrancyTest(constants.FUNCTIONS_WITH_MUTEX)); + it('should transfer the correct amounts when orders completely fill each other', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAddress: makerAddressLeft, makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - feeRecipientAddress: feeRecipientAddressLeft, }); const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAddress: makerAddressRight, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), - feeRecipientAddress: feeRecipientAddressRight, }); // Match signedOrderLeft with signedOrderRight await matchOrderTester.matchOrdersAndVerifyBalancesAsync( @@ -192,18 +235,12 @@ describe('matchOrders', () => { it('should transfer the correct amounts when orders completely fill each other and taker doesnt take a profit', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAddress: makerAddressLeft, makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - feeRecipientAddress: feeRecipientAddressLeft, }); const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAddress: makerAddressRight, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), - feeRecipientAddress: feeRecipientAddressRight, }); // Store original taker balance const takerInitialBalances = _.cloneDeep(erc20BalancesByOwner[takerAddress][defaultERC20MakerAssetAddress]); @@ -237,18 +274,12 @@ describe('matchOrders', () => { it('should transfer the correct amounts when left order is completely filled and right order is partially filled', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAddress: makerAddressLeft, makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - feeRecipientAddress: feeRecipientAddressLeft, }); const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAddress: makerAddressRight, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18), - feeRecipientAddress: feeRecipientAddressRight, }); // Match orders await matchOrderTester.matchOrdersAndVerifyBalancesAsync( @@ -269,18 +300,12 @@ describe('matchOrders', () => { it('should transfer the correct amounts when right order is completely filled and left order is partially filled', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAddress: makerAddressLeft, makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), - feeRecipientAddress: feeRecipientAddressLeft, }); const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAddress: makerAddressRight, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), - feeRecipientAddress: feeRecipientAddressRight, }); // Match orders await matchOrderTester.matchOrdersAndVerifyBalancesAsync( @@ -301,18 +326,12 @@ describe('matchOrders', () => { it('should transfer the correct amounts when consecutive calls are used to completely fill the left order', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAddress: makerAddressLeft, makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), - feeRecipientAddress: feeRecipientAddressLeft, }); const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAddress: makerAddressRight, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), - feeRecipientAddress: feeRecipientAddressRight, }); // Match orders let newERC20BalancesByOwner: ERC20BalancesByOwner; @@ -340,12 +359,8 @@ describe('matchOrders', () => { // However, we use 100/50 to ensure a partial fill as we want to go down the "left fill" // branch in the contract twice for this test. const signedOrderRight2 = await orderFactoryRight.newSignedOrderAsync({ - makerAddress: makerAddressRight, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18), - feeRecipientAddress: feeRecipientAddressRight, }); // Match signedOrderLeft with signedOrderRight2 const leftTakerAssetFilledAmount = signedOrderRight.makerAssetAmount; @@ -370,19 +385,13 @@ describe('matchOrders', () => { it('should transfer the correct amounts when consecutive calls are used to completely fill the right order', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAddress: makerAddressLeft, makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), - feeRecipientAddress: feeRecipientAddressLeft, }); const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAddress: makerAddressRight, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), - feeRecipientAddress: feeRecipientAddressRight, }); // Match orders let newERC20BalancesByOwner: ERC20BalancesByOwner; @@ -410,10 +419,8 @@ describe('matchOrders', () => { // However, we use 100/50 to ensure a partial fill as we want to go down the "right fill" // branch in the contract twice for this test. const signedOrderLeft2 = await orderFactoryLeft.newSignedOrderAsync({ - makerAddress: makerAddressLeft, makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18), - feeRecipientAddress: feeRecipientAddressLeft, }); // Match signedOrderLeft2 with signedOrderRight const leftTakerAssetFilledAmount = new BigNumber(0); @@ -441,15 +448,11 @@ describe('matchOrders', () => { it('should transfer the correct amounts if fee recipient is the same across both matched orders', async () => { const feeRecipientAddress = feeRecipientAddressLeft; const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAddress: makerAddressLeft, makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), feeRecipientAddress, }); const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAddress: makerAddressRight, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), feeRecipientAddress, @@ -467,18 +470,12 @@ describe('matchOrders', () => { it('should transfer the correct amounts if taker is also the left order maker', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAddress: makerAddressLeft, makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - feeRecipientAddress: feeRecipientAddressLeft, }); const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAddress: makerAddressRight, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), - feeRecipientAddress: feeRecipientAddressRight, }); // Match orders takerAddress = signedOrderLeft.makerAddress; @@ -494,18 +491,12 @@ describe('matchOrders', () => { it('should transfer the correct amounts if taker is also the right order maker', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAddress: makerAddressLeft, makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - feeRecipientAddress: feeRecipientAddressLeft, }); const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAddress: makerAddressRight, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), - feeRecipientAddress: feeRecipientAddressRight, }); // Match orders takerAddress = signedOrderRight.makerAddress; @@ -521,18 +512,12 @@ describe('matchOrders', () => { it('should transfer the correct amounts if taker is also the left fee recipient', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAddress: makerAddressLeft, makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - feeRecipientAddress: feeRecipientAddressLeft, }); const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAddress: makerAddressRight, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), - feeRecipientAddress: feeRecipientAddressRight, }); // Match orders takerAddress = feeRecipientAddressLeft; @@ -548,18 +533,12 @@ describe('matchOrders', () => { it('should transfer the correct amounts if taker is also the right fee recipient', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAddress: makerAddressLeft, makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - feeRecipientAddress: feeRecipientAddressLeft, }); const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAddress: makerAddressRight, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), - feeRecipientAddress: feeRecipientAddressRight, }); // Match orders takerAddress = feeRecipientAddressRight; @@ -575,18 +554,12 @@ describe('matchOrders', () => { it('should transfer the correct amounts if left maker is the left fee recipient and right maker is the right fee recipient', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAddress: makerAddressLeft, makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - feeRecipientAddress: makerAddressLeft, }); const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAddress: makerAddressRight, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), - feeRecipientAddress: makerAddressRight, }); // Match orders await matchOrderTester.matchOrdersAndVerifyBalancesAsync( @@ -601,18 +574,12 @@ describe('matchOrders', () => { it('Should throw if left order is not fillable', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAddress: makerAddressLeft, makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - feeRecipientAddress: feeRecipientAddressLeft, }); const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAddress: makerAddressRight, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), - feeRecipientAddress: feeRecipientAddressRight, }); // Cancel left order await exchangeWrapper.cancelOrderAsync(signedOrderLeft, signedOrderLeft.makerAddress); @@ -626,18 +593,12 @@ describe('matchOrders', () => { it('Should throw if right order is not fillable', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAddress: makerAddressLeft, makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - feeRecipientAddress: feeRecipientAddressLeft, }); const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAddress: makerAddressRight, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), - feeRecipientAddress: feeRecipientAddressRight, }); // Cancel right order await exchangeWrapper.cancelOrderAsync(signedOrderRight, signedOrderRight.makerAddress); @@ -651,18 +612,12 @@ describe('matchOrders', () => { it('should throw if there is not a positive spread', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAddress: makerAddressLeft, makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), - feeRecipientAddress: feeRecipientAddressLeft, }); const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAddress: makerAddressRight, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), 18), - feeRecipientAddress: feeRecipientAddressRight, }); // Match orders return expectTransactionFailedAsync( @@ -674,18 +629,13 @@ describe('matchOrders', () => { it('should throw if the left maker asset is not equal to the right taker asset ', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAddress: makerAddressLeft, makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - feeRecipientAddress: feeRecipientAddressLeft, }); const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAddress: makerAddressRight, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), - feeRecipientAddress: feeRecipientAddressRight, }); // Match orders return expectTransactionFailedAsync( @@ -701,20 +651,13 @@ describe('matchOrders', () => { it('should throw if the right maker asset is not equal to the left taker asset', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAddress: makerAddressLeft, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - feeRecipientAddress: feeRecipientAddressLeft, }); const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAddress: makerAddressRight, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), - feeRecipientAddress: feeRecipientAddressRight, }); // Match orders return expectTransactionFailedAsync( @@ -727,20 +670,14 @@ describe('matchOrders', () => { // Create orders to match const erc721TokenToTransfer = erc721LeftMakerAssetIds[0]; const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAddress: makerAddressLeft, makerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), makerAssetAmount: new BigNumber(1), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - feeRecipientAddress: feeRecipientAddressLeft, }); const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAddress: makerAddressRight, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), takerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), takerAssetAmount: new BigNumber(1), - feeRecipientAddress: feeRecipientAddressRight, }); // Match orders await matchOrderTester.matchOrdersAndVerifyBalancesAsync( @@ -762,20 +699,14 @@ describe('matchOrders', () => { // Create orders to match const erc721TokenToTransfer = erc721RightMakerAssetIds[0]; const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAddress: makerAddressLeft, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), takerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer), makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), takerAssetAmount: new BigNumber(1), - feeRecipientAddress: feeRecipientAddressLeft, }); const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAddress: makerAddressRight, makerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), makerAssetAmount: new BigNumber(1), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), - feeRecipientAddress: feeRecipientAddressRight, }); // Match orders await matchOrderTester.matchOrdersAndVerifyBalancesAsync( From c28c3db63fb80d5d5e82ccd3b327cb8c408cc6fa Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Thu, 23 Aug 2018 16:43:46 -0700 Subject: [PATCH 067/120] Only use one nonReentrant modifier, remove modifier from fillOrderNoThrow variations --- .../protocol/Exchange/MixinExchangeCore.sol | 2 +- .../protocol/Exchange/MixinMatchOrders.sol | 2 +- .../Exchange/MixinWrapperFunctions.sol | 17 ++++------ .../ReentrantERC20Token.sol | 33 +------------------ .../utils/ReentrancyGuard/ReentrancyGuard.sol | 14 +------- packages/contracts/test/utils/constants.ts | 4 --- 6 files changed, 11 insertions(+), 61 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol index f02514fc6f..291af37929 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinExchangeCore.sol @@ -89,7 +89,7 @@ contract MixinExchangeCore is bytes memory signature ) public - lockMutex + nonReentrant returns (FillResults memory fillResults) { fillResults = fillOrderInternal( diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol index 39c47e6f9d..25220a673e 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol @@ -50,7 +50,7 @@ contract MixinMatchOrders is bytes memory rightSignature ) public - lockMutex + nonReentrant returns (LibFillResults.MatchedFillResults memory matchedFillResults) { // We assume that rightOrder.takerAssetData == leftOrder.makerAssetData and rightOrder.makerAssetData == leftOrder.takerAssetData. diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol index b0474b110a..39fa724cc3 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinWrapperFunctions.sol @@ -33,7 +33,8 @@ contract MixinWrapperFunctions is LibMath, LibFillResults, LibAbiEncoder, - MExchangeCore + MExchangeCore, + MWrapperFunctions { /// @dev Fills the input order. Reverts if exact takerAssetFillAmount not filled. @@ -46,7 +47,7 @@ contract MixinWrapperFunctions is bytes memory signature ) public - lockMutex + nonReentrant returns (FillResults memory fillResults) { fillResults = fillOrKillOrderInternal( @@ -69,7 +70,6 @@ contract MixinWrapperFunctions is bytes memory signature ) public - nonReentrant returns (FillResults memory fillResults) { // ABI encode calldata for `fillOrder` @@ -111,7 +111,7 @@ contract MixinWrapperFunctions is bytes[] memory signatures ) public - lockMutex + nonReentrant returns (FillResults memory totalFillResults) { uint256 ordersLength = orders.length; @@ -138,7 +138,7 @@ contract MixinWrapperFunctions is bytes[] memory signatures ) public - lockMutex + nonReentrant returns (FillResults memory totalFillResults) { uint256 ordersLength = orders.length; @@ -166,7 +166,6 @@ contract MixinWrapperFunctions is bytes[] memory signatures ) public - nonReentrant returns (FillResults memory totalFillResults) { uint256 ordersLength = orders.length; @@ -192,7 +191,7 @@ contract MixinWrapperFunctions is bytes[] memory signatures ) public - lockMutex + nonReentrant returns (FillResults memory totalFillResults) { bytes memory takerAssetData = orders[0].takerAssetData; @@ -237,7 +236,6 @@ contract MixinWrapperFunctions is bytes[] memory signatures ) public - nonReentrant returns (FillResults memory totalFillResults) { bytes memory takerAssetData = orders[0].takerAssetData; @@ -281,7 +279,7 @@ contract MixinWrapperFunctions is bytes[] memory signatures ) public - lockMutex + nonReentrant returns (FillResults memory totalFillResults) { bytes memory makerAssetData = orders[0].makerAssetData; @@ -334,7 +332,6 @@ contract MixinWrapperFunctions is bytes[] memory signatures ) public - nonReentrant returns (FillResults memory totalFillResults) { bytes memory makerAssetData = orders[0].makerAssetData; diff --git a/packages/contracts/src/2.0.0/test/ReentrantERC20Token/ReentrantERC20Token.sol b/packages/contracts/src/2.0.0/test/ReentrantERC20Token/ReentrantERC20Token.sol index 8d575d09a0..8bfdd2e665 100644 --- a/packages/contracts/src/2.0.0/test/ReentrantERC20Token/ReentrantERC20Token.sol +++ b/packages/contracts/src/2.0.0/test/ReentrantERC20Token/ReentrantERC20Token.sol @@ -40,17 +40,14 @@ contract ReentrantERC20Token is ); // All of these functions are potentially vulnerable to reentrancy + // We do not test any "noThrow" functions because `fillOrderNoThrow` makes a delegatecall to `fillOrder` enum ExchangeFunction { FILL_ORDER, FILL_OR_KILL_ORDER, - FILL_ORDER_NO_THROW, BATCH_FILL_ORDERS, BATCH_FILL_OR_KILL_ORDERS, - BATCH_FILL_ORDERS_NO_THROW, MARKET_BUY_ORDERS, - MARKET_BUY_ORDERS_NO_THROW, MARKET_SELL_ORDERS, - MARKET_SELL_ORDERS_NO_THROW, MATCH_ORDERS, CANCEL_ORDER, CANCEL_ORDERS_UP_TO, @@ -111,13 +108,6 @@ contract ReentrantERC20Token is 0, signature ); - } else if (currentFunctionId == uint8(ExchangeFunction.FILL_ORDER_NO_THROW)) { - calldata = abi.encodeWithSelector( - EXCHANGE.fillOrderNoThrow.selector, - order, - 0, - signature - ); } else if (currentFunctionId == uint8(ExchangeFunction.BATCH_FILL_ORDERS)) { calldata = abi.encodeWithSelector( EXCHANGE.batchFillOrders.selector, @@ -132,13 +122,6 @@ contract ReentrantERC20Token is takerAssetFillAmounts, signatures ); - } else if (currentFunctionId == uint8(ExchangeFunction.BATCH_FILL_ORDERS_NO_THROW)) { - calldata = abi.encodeWithSelector( - EXCHANGE.batchFillOrdersNoThrow.selector, - orders, - takerAssetFillAmounts, - signatures - ); } else if (currentFunctionId == uint8(ExchangeFunction.MARKET_BUY_ORDERS)) { calldata = abi.encodeWithSelector( EXCHANGE.marketBuyOrders.selector, @@ -146,13 +129,6 @@ contract ReentrantERC20Token is 0, signatures ); - } else if (currentFunctionId == uint8(ExchangeFunction.MARKET_BUY_ORDERS_NO_THROW)) { - calldata = abi.encodeWithSelector( - EXCHANGE.marketBuyOrdersNoThrow.selector, - orders, - 0, - signatures - ); } else if (currentFunctionId == uint8(ExchangeFunction.MARKET_SELL_ORDERS)) { calldata = abi.encodeWithSelector( EXCHANGE.marketSellOrders.selector, @@ -160,13 +136,6 @@ contract ReentrantERC20Token is 0, signatures ); - } else if (currentFunctionId == uint8(ExchangeFunction.MARKET_SELL_ORDERS_NO_THROW)) { - calldata = abi.encodeWithSelector( - EXCHANGE.marketSellOrdersNoThrow.selector, - orders, - 0, - signatures - ); } else if (currentFunctionId == uint8(ExchangeFunction.MATCH_ORDERS)) { calldata = abi.encodeWithSelector( EXCHANGE.matchOrders.selector, diff --git a/packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol b/packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol index 2b980c7cad..1dee512d49 100644 --- a/packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol +++ b/packages/contracts/src/2.0.0/utils/ReentrancyGuard/ReentrancyGuard.sol @@ -23,21 +23,9 @@ contract ReentrancyGuard { // Locked state of mutex bool private locked = false; - /// @dev Functions with this modifier cannot be reentered. - modifier nonReentrant() { - // Ensure mutex is unlocked - require( - !locked, - "REENTRANCY_ILLEGAL" - ); - - // Perform function call - _; - } - /// @dev Functions with this modifer cannot be reentered. The mutex will be locked /// before function execution and unlocked after. - modifier lockMutex() { + modifier nonReentrant() { // Ensure mutex is unlocked require( !locked, diff --git a/packages/contracts/test/utils/constants.ts b/packages/contracts/test/utils/constants.ts index 7060b5091b..ee4378d2ef 100644 --- a/packages/contracts/test/utils/constants.ts +++ b/packages/contracts/test/utils/constants.ts @@ -54,14 +54,10 @@ export const constants = { FUNCTIONS_WITH_MUTEX: [ 'FILL_ORDER', 'FILL_OR_KILL_ORDER', - 'FILL_ORDER_NO_THROW', 'BATCH_FILL_ORDERS', 'BATCH_FILL_OR_KILL_ORDERS', - 'BATCH_FILL_ORDERS_NO_THROW', 'MARKET_BUY_ORDERS', - 'MARKET_BUY_ORDERS_NO_THROW', 'MARKET_SELL_ORDERS', - 'MARKET_SELL_ORDERS_NO_THROW', 'MATCH_ORDERS', 'CANCEL_ORDER', 'CANCEL_ORDERS_UP_TO', From c8500cab10b8ffd175acd760cbd1286577a1c4b1 Mon Sep 17 00:00:00 2001 From: Amir Bandeali Date: Fri, 24 Aug 2018 16:35:43 -0700 Subject: [PATCH 068/120] Fix build --- packages/contracts/package.json | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 8d75eb4ce0..1c1ac81da5 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -20,11 +20,14 @@ "test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov", "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html", "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha", - "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit", + "run_mocha": + "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit", "compile": "sol-compiler --contracts-dir src", "clean": "shx rm -rf lib generated_contract_wrappers", - "generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output generated_contract_wrappers --backend ethers", - "lint": "tslint --project . --exclude **/src/generated_contract_wrappers/**/* --exclude **/lib/**/* && yarn lint-contracts", + "generate_contract_wrappers": + "abi-gen --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output generated_contract_wrappers --backend ethers", + "lint": + "tslint --project . --exclude **/src/generated_contract_wrappers/**/* --exclude **/lib/**/* && yarn lint-contracts", "coverage:report:text": "istanbul report text", "coverage:report:html": "istanbul report html && open coverage/index.html", "profiler:report:html": "istanbul report html && open coverage/index.html", @@ -34,7 +37,7 @@ }, "config": { "abis": - "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|DummyNoReturnERC20Token|ERC20Proxy|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|InvalidERC721Receiver|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|OrderValidator|ReentrantERC20Token|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestExchangeInternals|TestLibBytes|TestLibs|TestSignatureValidator|Validator|Wallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json" + "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|DummyNoReturnERC20Token|ERC20Proxy|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|InvalidERC721Receiver|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|OrderValidator|ReentrantERC20Token|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestExchangeInternals|TestLibBytes|TestLibs|TestSignatureValidator|TestStaticCallReceiver|Validator|Wallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json" }, "repository": { "type": "git", From 407f63ef2055e8cd01af010a2e6d3a6c548c9793 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Mon, 20 Aug 2018 13:13:38 -0700 Subject: [PATCH 069/120] Removed calculateFillResults from matchOrders workflow. Eliminates compounded rounding errors. --- .../protocol/Exchange/MixinMatchOrders.sol | 67 ++++++++----------- 1 file changed, 29 insertions(+), 38 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol index 25220a673e..2012aa6dbe 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol @@ -109,7 +109,7 @@ contract MixinMatchOrders is rightOrderInfo.orderTakerAssetFilledAmount, matchedFillResults.right ); - + // Settle matched orders. Succeeds or throws. settleMatchedOrders( leftOrder, @@ -169,52 +169,43 @@ contract MixinMatchOrders is // The amount saved by the left maker goes to the taker. // Either the left or right order will be fully filled; possibly both. // The left order is fully filled iff the right order can sell more than left can buy. - // That is: the amount required to fill the left order is less than or equal to - // the amount we can spend from the right order: - // <= * - // <= * / - // * <= * + + // Derive maker asset amounts for left & right orders, given store taker assert amounts uint256 leftTakerAssetAmountRemaining = safeSub(leftOrder.takerAssetAmount, leftOrderTakerAssetFilledAmount); + uint256 leftMakerAssetAmountRemaining = getPartialAmountFloor( + leftOrder.makerAssetAmount, + leftOrder.takerAssetAmount, + leftTakerAssetAmountRemaining + ); uint256 rightTakerAssetAmountRemaining = safeSub(rightOrder.takerAssetAmount, rightOrderTakerAssetFilledAmount); - uint256 leftTakerAssetFilledAmount; - uint256 rightTakerAssetFilledAmount; - if ( - safeMul(leftTakerAssetAmountRemaining, rightOrder.takerAssetAmount) <= - safeMul(rightTakerAssetAmountRemaining, rightOrder.makerAssetAmount) - ) { - // Left order will be fully filled: maximally fill left - leftTakerAssetFilledAmount = leftTakerAssetAmountRemaining; + uint256 rightMakerAssetAmountRemaining = getPartialAmountFloor( + rightOrder.makerAssetAmount, + rightOrder.takerAssetAmount, + rightTakerAssetAmountRemaining + ); - // The right order receives an amount proportional to how much was spent. - rightTakerAssetFilledAmount = getPartialAmountFloor( - rightOrder.takerAssetAmount, - rightOrder.makerAssetAmount, - leftTakerAssetFilledAmount + if (leftTakerAssetAmountRemaining >= rightMakerAssetAmountRemaining) { + // Case 1: Right order is fully filled: maximally fill right + matchedFillResults.right.makerAssetFilledAmount = rightMakerAssetAmountRemaining; + matchedFillResults.right.takerAssetFilledAmount = rightTakerAssetAmountRemaining; + matchedFillResults.left.makerAssetFilledAmount = getPartialAmountFloor( + leftOrder.makerAssetAmount, + leftOrder.takerAssetAmount, + matchedFillResults.right.makerAssetFilledAmount ); + matchedFillResults.left.takerAssetFilledAmount = matchedFillResults.right.makerAssetFilledAmount; } else { - // Right order will be fully filled: maximally fill right - rightTakerAssetFilledAmount = rightTakerAssetAmountRemaining; - - // The left order receives an amount proportional to how much was spent. - leftTakerAssetFilledAmount = getPartialAmountFloor( - rightOrder.makerAssetAmount, + // Case 2: Left order is fully filled: maximall fill left + matchedFillResults.left.makerAssetFilledAmount = leftMakerAssetAmountRemaining; + matchedFillResults.left.takerAssetFilledAmount = leftTakerAssetAmountRemaining; + matchedFillResults.right.makerAssetFilledAmount = matchedFillResults.left.takerAssetFilledAmount; + matchedFillResults.right.takerAssetFilledAmount = getPartialAmountCeil( rightOrder.takerAssetAmount, - rightTakerAssetFilledAmount + rightOrder.makerAssetAmount, + matchedFillResults.left.takerAssetFilledAmount ); } - // Calculate fill results for left order - matchedFillResults.left = calculateFillResults( - leftOrder, - leftTakerAssetFilledAmount - ); - - // Calculate fill results for right order - matchedFillResults.right = calculateFillResults( - rightOrder, - rightTakerAssetFilledAmount - ); - // Calculate amount given to taker matchedFillResults.leftMakerAssetSpreadAmount = safeSub( matchedFillResults.left.makerAssetFilledAmount, From 057891b342cf639b493adcf0a136f7ee421aaaf9 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Mon, 20 Aug 2018 13:22:21 -0700 Subject: [PATCH 070/120] Added fees to matchOrders (previously in calculateFillResults --- .../protocol/Exchange/MixinMatchOrders.sol | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol index 2012aa6dbe..58f131819e 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol @@ -212,6 +212,30 @@ contract MixinMatchOrders is matchedFillResults.right.takerAssetFilledAmount ); + // Compute fees for left order + matchedFillResults.left.makerFeePaid = getPartialAmount( + matchedFillResults.left.takerAssetFilledAmount, + leftOrder.takerAssetAmount, + leftOrder.makerFee + ); + matchedFillResults.left.takerFeePaid = getPartialAmount( + matchedFillResults.left.takerAssetFilledAmount, + leftOrder.takerAssetAmount, + leftOrder.takerFee + ); + + // Compute fees for right order + matchedFillResults.right.makerFeePaid = getPartialAmount( + matchedFillResults.right.takerAssetFilledAmount, + rightOrder.takerAssetAmount, + rightOrder.makerFee + ); + matchedFillResults.right.takerFeePaid = getPartialAmount( + matchedFillResults.right.takerAssetFilledAmount, + rightOrder.takerAssetAmount, + rightOrder.takerFee + ); + // Return fill results return matchedFillResults; } From 0ecdf1e2132141b199fa929ec1c6ca9979f06302 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Mon, 20 Aug 2018 14:02:40 -0700 Subject: [PATCH 071/120] All existing tests pass. --- .../contracts/test/exchange/match_orders.ts | 105 +++++++++++++++++- .../test/utils/match_order_tester.ts | 53 +++++---- 2 files changed, 137 insertions(+), 21 deletions(-) diff --git a/packages/contracts/test/exchange/match_orders.ts b/packages/contracts/test/exchange/match_orders.ts index 8cd873a850..78f33ec7c6 100644 --- a/packages/contracts/test/exchange/match_orders.ts +++ b/packages/contracts/test/exchange/match_orders.ts @@ -28,7 +28,7 @@ chaiSetup.configure(); const expect = chai.expect; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); -describe('matchOrders', () => { +describe.only('matchOrders', () => { let makerAddressLeft: string; let makerAddressRight: string; let owner: string; @@ -176,6 +176,109 @@ describe('matchOrders', () => { erc20BalancesByOwner = await erc20Wrapper.getBalancesAsync(); erc721TokenIdsByOwner = await erc721Wrapper.getBalancesAsync(); }); + + + /* + it.only('should transfer the correct amounts when orders completely fill each other', async () => { + // Create orders to match + const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ + makerAddress: makerAddressLeft, + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2000), 0), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1001), 0), + feeRecipientAddress: feeRecipientAddressLeft, + }); + const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ + makerAddress: makerAddressRight, + makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), + takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10000), 0), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(3000), 0), + feeRecipientAddress: feeRecipientAddressRight, + }); + // Match signedOrderLeft with signedOrderRight + await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + signedOrderLeft, + signedOrderRight, + takerAddress, + erc20BalancesByOwner, + erc721TokenIdsByOwner, + ); + // // Verify left order was fully filled + // const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft); + // expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); + // Verify right order was fully filled + // const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight); + // expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); + }); + */ + + it.only('Jacobs Example', async () => { + // Create orders to match + const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ + makerAddress: makerAddressLeft, + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 0), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 0), + feeRecipientAddress: feeRecipientAddressLeft, + }); + const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ + makerAddress: makerAddressRight, + makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), + takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 0), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 0), + feeRecipientAddress: feeRecipientAddressRight, + }); + // Match signedOrderLeft with signedOrderRight + await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + signedOrderLeft, + signedOrderRight, + takerAddress, + erc20BalancesByOwner, + erc721TokenIdsByOwner, + ); + // // Verify left order was fully filled + const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft); + //expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); + console.log("*** LEFT ORDER INFO ***\n", JSON.stringify(leftOrderInfo), "\n***************"); + // Verify right order was fully filled + const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight); + // expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); + console.log("*** RIGHT ORDER INFO ***\n", JSON.stringify(rightOrderInfo), "\n***************"); + }); + + + /* + it.only('Jacobs Example', async () => { + // Create orders to match + const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ + makerAddress: makerAddressLeft, + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 0), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 0), + feeRecipientAddress: feeRecipientAddressLeft, + }); + const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ + makerAddress: makerAddressRight, + makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), + takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 0), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0), + feeRecipientAddress: feeRecipientAddressRight, + }); + // Match signedOrderLeft with signedOrderRight + await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + signedOrderLeft, + signedOrderRight, + takerAddress, + erc20BalancesByOwner, + erc721TokenIdsByOwner, + ); + // // Verify left order was fully filled + // const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft); + // expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); + // Verify right order was fully filled + // const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight); + // expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); + });*/ const reentrancyTest = (functionNames: string[]) => { _.forEach(functionNames, async (functionName: string, functionId: number) => { diff --git a/packages/contracts/test/utils/match_order_tester.ts b/packages/contracts/test/utils/match_order_tester.ts index fa2eabc12a..ded4293220 100644 --- a/packages/contracts/test/utils/match_order_tester.ts +++ b/packages/contracts/test/utils/match_order_tester.ts @@ -9,6 +9,7 @@ import { ERC20Wrapper } from './erc20_wrapper'; import { ERC721Wrapper } from './erc721_wrapper'; import { ExchangeWrapper } from './exchange_wrapper'; import { ERC20BalancesByOwner, ERC721TokenIdsByOwner, TransferAmountsByMatchOrders as TransferAmounts } from './types'; +import { TransactionReceiptWithDecodedLogs } from '../../../../node_modules/ethereum-types'; chaiSetup.configure(); const expect = chai.expect; @@ -108,7 +109,7 @@ export class MatchOrderTester { : new BigNumber(0); expect(expectedOrderFilledAmountRight).to.be.bignumber.equal(orderTakerAssetFilledAmountRight); // Match left & right orders - await this._exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress); + const transactionReceipt = await this._exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress); const newERC20BalancesByOwner = await this._erc20Wrapper.getBalancesAsync(); const newERC721TokenIdsByOwner = await this._erc721Wrapper.getBalancesAsync(); // Calculate expected balance changes @@ -117,6 +118,8 @@ export class MatchOrderTester { signedOrderRight, orderTakerAssetFilledAmountLeft, orderTakerAssetFilledAmountRight, + transactionReceipt, + takerAddress ); let expectedERC20BalancesByOwner: ERC20BalancesByOwner; let expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner; @@ -135,6 +138,7 @@ export class MatchOrderTester { expectedERC721TokenIdsByOwner, newERC721TokenIdsByOwner, ); + expect(didExpectedBalancesMatchRealBalances).to.be.true(); return [newERC20BalancesByOwner, newERC721TokenIdsByOwner]; } @@ -150,26 +154,35 @@ export class MatchOrderTester { signedOrderRight: SignedOrder, orderTakerAssetFilledAmountLeft: BigNumber, orderTakerAssetFilledAmountRight: BigNumber, + transactionReceipt: TransactionReceiptWithDecodedLogs, + takerAddress: string ): Promise { - let amountBoughtByLeftMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( - orderHashUtils.getOrderHashHex(signedOrderLeft), - ); - amountBoughtByLeftMaker = amountBoughtByLeftMaker.minus(orderTakerAssetFilledAmountLeft); - const amountSoldByLeftMaker = amountBoughtByLeftMaker - .times(signedOrderLeft.makerAssetAmount) - .dividedToIntegerBy(signedOrderLeft.takerAssetAmount); - const amountReceivedByRightMaker = amountBoughtByLeftMaker - .times(signedOrderRight.takerAssetAmount) - .dividedToIntegerBy(signedOrderRight.makerAssetAmount); - const amountReceivedByTaker = amountSoldByLeftMaker.minus(amountReceivedByRightMaker); - let amountBoughtByRightMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( - orderHashUtils.getOrderHashHex(signedOrderRight), - ); - amountBoughtByRightMaker = amountBoughtByRightMaker.minus(orderTakerAssetFilledAmountRight); - const amountSoldByRightMaker = amountBoughtByRightMaker - .times(signedOrderRight.makerAssetAmount) - .dividedToIntegerBy(signedOrderRight.takerAssetAmount); - const amountReceivedByLeftMaker = amountSoldByRightMaker; + // Parse logs + expect(transactionReceipt.logs.length).to.be.equal(2); + // First log is for left fill + const leftLog = ((transactionReceipt.logs[0] as any) as {args: { makerAddress: string, takerAddress: string, makerAssetFilledAmount: string, takerAssetFilledAmount: string, makerFeePaid: string, takerFeePaid: string}}); + expect(leftLog.args.makerAddress).to.be.equal(signedOrderLeft.makerAddress); + expect(leftLog.args.takerAddress).to.be.equal(takerAddress); + const amountBoughtByLeftMaker = new BigNumber(leftLog.args.takerAssetFilledAmount); + const amountSoldByLeftMaker = new BigNumber(leftLog.args.makerAssetFilledAmount); + // Second log is for right fill + const rightLog = ((transactionReceipt.logs[1] as any) as {args: { makerAddress: string, takerAddress: string, makerAssetFilledAmount: string, takerAssetFilledAmount: string, makerFeePaid: string, takerFeePaid: string}}); + expect(rightLog.args.makerAddress).to.be.equal(signedOrderRight.makerAddress); + expect(rightLog.args.takerAddress).to.be.equal(takerAddress); + const amountBoughtByRightMaker = new BigNumber(rightLog.args.takerAssetFilledAmount); + const amountSoldByRightMaker = new BigNumber(rightLog.args.makerAssetFilledAmount); + // Determine amount received by taker + const amountReceivedByTaker = amountSoldByLeftMaker.sub(amountBoughtByRightMaker); + + const amountReceivedByLeftMaker = amountBoughtByLeftMaker; + const amountReceivedByRightMaker = amountBoughtByRightMaker; + + console.log("Amount bought by left maker = ", JSON.stringify(amountBoughtByLeftMaker)); + console.log("Amount sold by left maker = ", JSON.stringify(amountSoldByLeftMaker)); + console.log("Amount bought by right maker = ", JSON.stringify(amountBoughtByRightMaker)); + console.log("Amount sold by right maker = ", JSON.stringify(amountSoldByRightMaker)); + console.log("Amount received by taker = ", JSON.stringify(amountReceivedByTaker)); + //const amountReceivedByLeftMaker = amountSoldByRightMaker; const feePaidByLeftMaker = signedOrderLeft.makerFee .times(amountSoldByLeftMaker) .dividedToIntegerBy(signedOrderLeft.makerAssetAmount); From a32b201afe6c90a6bd06b88a5d512408cd3cb032 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Mon, 20 Aug 2018 17:00:08 -0700 Subject: [PATCH 072/120] Rounding for fees in match orders addressed, plus example --- .../protocol/Exchange/MixinMatchOrders.sol | 8 +- .../test/utils/match_order_tester.ts | 84 +++++++++++++++++-- 2 files changed, 83 insertions(+), 9 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol index 58f131819e..b3f376eb8d 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol @@ -214,8 +214,8 @@ contract MixinMatchOrders is // Compute fees for left order matchedFillResults.left.makerFeePaid = getPartialAmount( - matchedFillResults.left.takerAssetFilledAmount, - leftOrder.takerAssetAmount, + matchedFillResults.left.makerAssetFilledAmount, + leftOrder.makerAssetAmount, leftOrder.makerFee ); matchedFillResults.left.takerFeePaid = getPartialAmount( @@ -226,8 +226,8 @@ contract MixinMatchOrders is // Compute fees for right order matchedFillResults.right.makerFeePaid = getPartialAmount( - matchedFillResults.right.takerAssetFilledAmount, - rightOrder.takerAssetAmount, + matchedFillResults.right.makerAssetFilledAmount, + rightOrder.makerAssetAmount, rightOrder.makerFee ); matchedFillResults.right.takerFeePaid = getPartialAmount( diff --git a/packages/contracts/test/utils/match_order_tester.ts b/packages/contracts/test/utils/match_order_tester.ts index ded4293220..5160b47d3e 100644 --- a/packages/contracts/test/utils/match_order_tester.ts +++ b/packages/contracts/test/utils/match_order_tester.ts @@ -139,7 +139,78 @@ export class MatchOrderTester { newERC721TokenIdsByOwner, ); + // Compute actual transfer amounts + let actualTransferAmounts = {}; + const makerAssetProxyIdLeft = assetDataUtils.decodeAssetProxyId(signedOrderLeft.makerAssetData); + if (makerAssetProxyIdLeft === AssetProxyId.ERC20) { + const erc20AssetData = assetDataUtils.decodeERC20AssetData(signedOrderLeft.makerAssetData); + const makerAssetAddressLeft = erc20AssetData.tokenAddress; + actualTransferAmounts.amountSoldByLeftMaker = erc20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sub(newERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft]); + actualTransferAmounts.amountBoughtByRightMaker = newERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sub(erc20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft]); + actualTransferAmounts.amountReceivedByRightMaker = actualTransferAmounts.amountBoughtByRightMaker; + actualTransferAmounts.amountReceivedByTaker = newERC20BalancesByOwner[takerAddress][makerAssetAddressLeft].sub(erc20BalancesByOwner[takerAddress][makerAssetAddressLeft]); + } else if(makerAssetProxyIdLeft === AssetProxyId.ERC721) { + } + const makerAssetProxyIdRight = assetDataUtils.decodeAssetProxyId(signedOrderRight.makerAssetData); + if (makerAssetProxyIdRight === AssetProxyId.ERC20) { + const erc20AssetData = assetDataUtils.decodeERC20AssetData(signedOrderRight.makerAssetData); + const makerAssetAddressRight = erc20AssetData.tokenAddress; + actualTransferAmounts.amountSoldByRightMaker = erc20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight].sub(newERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]); + actualTransferAmounts.amountBoughtByLeftMaker = newERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sub(erc20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight]); + actualTransferAmounts.amountReceivedByLeftMaker = actualTransferAmounts.amountBoughtByLeftMaker; + } else if(makerAssetProxyIdRight === AssetProxyId.ERC721) { + } + // Fees + actualTransferAmounts.feePaidByLeftMaker = erc20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress].sub(newERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress]); + actualTransferAmounts.feePaidByRightMaker = erc20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress].sub(newERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress]); + actualTransferAmounts.totalFeePaidByTaker = erc20BalancesByOwner[takerAddress][this._feeTokenAddress].sub(newERC20BalancesByOwner[takerAddress][this._feeTokenAddress]); + + console.log("amountBoughtByLeftMaker"); + expect(expectedTransferAmounts.amountBoughtByLeftMaker).to.be.bignumber.equal(actualTransferAmounts.amountBoughtByLeftMaker); + console.log("amountSoldByLeftMaker"); + expect(expectedTransferAmounts.amountSoldByLeftMaker).to.be.bignumber.equal(actualTransferAmounts.amountSoldByLeftMaker); + console.log("amountBoughtByRightMaker"); + expect(expectedTransferAmounts.amountBoughtByRightMaker).to.be.bignumber.equal(actualTransferAmounts.amountBoughtByRightMaker); + console.log("amountSoldByRightMaker"); + expect(expectedTransferAmounts.amountSoldByRightMaker).to.be.bignumber.equal(actualTransferAmounts.amountSoldByRightMaker); + console.log("amountReceivedByTaker"); + expect(expectedTransferAmounts.amountReceivedByTaker).to.be.bignumber.equal(actualTransferAmounts.amountReceivedByTaker); + console.log("feePaidByLeftMaker"); + expect(expectedTransferAmounts.feePaidByLeftMaker).to.be.bignumber.equal(actualTransferAmounts.feePaidByLeftMaker); + console.log("feePaidByRightMaker"); + expect(expectedTransferAmounts.feePaidByRightMaker).to.be.bignumber.equal(actualTransferAmounts.feePaidByRightMaker); + console.log("totalFeePaidByTaker"); + expect(expectedTransferAmounts.totalFeePaidByTaker).to.be.bignumber.equal(actualTransferAmounts.totalFeePaidByTaker); + + + +/* + const actualTransferAmounts = { + // Left Maker + amountBoughtByLeftMaker, + amountSoldByLeftMaker, + amountReceivedByLeftMaker, + feePaidByLeftMaker, + // Right Maker + amountBoughtByRightMaker, + amountSoldByRightMaker, + amountReceivedByRightMaker, + feePaidByRightMaker, + // Taker + amountReceivedByTaker, + feePaidByTakerLeft, + feePaidByTakerRight, + totalFeePaidByTaker, + // Fee Recipients + feeReceivedLeft, + feeReceivedRight, + };*/ + + // This is a catch-all to ensure that no other balances changed + console.log("Catch-all"); expect(didExpectedBalancesMatchRealBalances).to.be.true(); + + return [newERC20BalancesByOwner, newERC721TokenIdsByOwner]; } /// @dev Calculates expected transfer amounts between order makers, fee recipients, and @@ -180,7 +251,7 @@ export class MatchOrderTester { console.log("Amount bought by left maker = ", JSON.stringify(amountBoughtByLeftMaker)); console.log("Amount sold by left maker = ", JSON.stringify(amountSoldByLeftMaker)); console.log("Amount bought by right maker = ", JSON.stringify(amountBoughtByRightMaker)); - console.log("Amount sold by right maker = ", JSON.stringify(amountSoldByRightMaker)); + console.log("Amount sold by right maker = ", JSON.stringify(amountSoldByRightMaker)); console.log("Amount received by taker = ", JSON.stringify(amountReceivedByTaker)); //const amountReceivedByLeftMaker = amountSoldByRightMaker; const feePaidByLeftMaker = signedOrderLeft.makerFee @@ -189,12 +260,15 @@ export class MatchOrderTester { const feePaidByRightMaker = signedOrderRight.makerFee .times(amountSoldByRightMaker) .dividedToIntegerBy(signedOrderRight.makerAssetAmount); + const feePaidByTakerLeft = signedOrderLeft.takerFee - .times(amountSoldByLeftMaker) - .dividedToIntegerBy(signedOrderLeft.makerAssetAmount); + .times(amountBoughtByLeftMaker) + .dividedToIntegerBy(signedOrderLeft.takerAssetAmount); + + const feePaidByTakerRight = signedOrderRight.takerFee - .times(amountSoldByRightMaker) - .dividedToIntegerBy(signedOrderRight.makerAssetAmount); + .times(amountBoughtByRightMaker) + .dividedToIntegerBy(signedOrderRight.takerAssetAmount); const totalFeePaidByTaker = feePaidByTakerLeft.add(feePaidByTakerRight); const feeReceivedLeft = feePaidByLeftMaker.add(feePaidByTakerLeft); const feeReceivedRight = feePaidByRightMaker.add(feePaidByTakerRight); From ca5c9e77c0f068cf653afc9c8b61bdc25318f8e2 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Tue, 21 Aug 2018 14:45:39 -0700 Subject: [PATCH 073/120] Ironing out the new set of test cases for order matchubng --- .../contracts/test/exchange/match_orders.ts | 2 +- .../test/utils/match_order_tester.ts | 111 ++++++++++++++++-- 2 files changed, 102 insertions(+), 11 deletions(-) diff --git a/packages/contracts/test/exchange/match_orders.ts b/packages/contracts/test/exchange/match_orders.ts index 78f33ec7c6..b2ffa31b2f 100644 --- a/packages/contracts/test/exchange/match_orders.ts +++ b/packages/contracts/test/exchange/match_orders.ts @@ -212,7 +212,7 @@ describe.only('matchOrders', () => { }); */ - it.only('Jacobs Example', async () => { + it('Jacobs Example', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ makerAddress: makerAddressLeft, diff --git a/packages/contracts/test/utils/match_order_tester.ts b/packages/contracts/test/utils/match_order_tester.ts index 5160b47d3e..f9e45319a5 100644 --- a/packages/contracts/test/utils/match_order_tester.ts +++ b/packages/contracts/test/utils/match_order_tester.ts @@ -57,6 +57,27 @@ export class MatchOrderTester { ); return doesErc721TokenIdsMatch; } + + /* + private static compareTokenIdLists(list1: BigNumber[], list2: BigNumber[]) { + // ERC721 Token Ids + list1 = _.(list1); + _.sortBy(tokenIds); + }); + }, + ); + const sortedNewERC721TokenIdsByOwner = _.mapValues(realERC721TokenIdsByOwner, tokenIdsByOwner => { + _.mapValues(tokenIdsByOwner, tokenIds => { + _.sortBy(tokenIds); + }); + }); + const doesErc721TokenIdsMatch = _.isEqual( + sortedExpectedNewERC721TokenIdsByOwner, + sortedNewERC721TokenIdsByOwner, + ); + return doesErc721TokenIdsMatch; + }*/ + /// @dev Constructs new MatchOrderTester. /// @param exchangeWrapper Used to call to the Exchange. /// @param erc20Wrapper Used to fetch ERC20 balances. @@ -139,6 +160,68 @@ export class MatchOrderTester { newERC721TokenIdsByOwner, ); + // Individual balance comparisons + const makerAssetProxyIdLeft = assetDataUtils.decodeAssetProxyId(signedOrderLeft.makerAssetData); + const makerERC20AssetDataLeft = makerAssetProxyIdLeft == AssetProxyId.ERC20 ? assetDataUtils.decodeERC20AssetData(signedOrderLeft.makerAssetData) : assetDataUtils.decodeERC721AssetData(signedOrderLeft.makerAssetData); + const makerAssetAddressLeft = makerERC20AssetDataLeft.tokenAddress; + const makerAssetProxyIdRight = assetDataUtils.decodeAssetProxyId(signedOrderRight.makerAssetData); + const makerERC20AssetDataRight = makerAssetProxyIdRight == AssetProxyId.ERC20 ? assetDataUtils.decodeERC20AssetData(signedOrderRight.makerAssetData) : assetDataUtils.decodeERC721AssetData(signedOrderRight.makerAssetData); + const makerAssetAddressRight = makerERC20AssetDataRight.tokenAddress; + + console.log("Left Maker: Sell Amount"); + if(makerAssetProxyIdLeft == AssetProxyId.ERC20) { + expect(newERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft]).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft]); + } else if(makerAssetProxyIdLeft == AssetProxyId.ERC721) { + expect(newERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort()).to.be.deep.equal(newERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort()); + } else { + throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdLeft}`); + } + + console.log("Left Maker: Buy Amount"); + if(makerAssetProxyIdRight == AssetProxyId.ERC20) { + expect(newERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight]).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight]); + } else if(makerAssetProxyIdRight == AssetProxyId.ERC721) { + expect(newERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort()).to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort()); + } else { + throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdRight}`); + } + + console.log("Left Maker: Fees"); + expect(newERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress]).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress]); + + console.log("Right Maker: Sell Amount"); + if(makerAssetProxyIdRight == AssetProxyId.ERC20) { + expect(newERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]); + } else if(makerAssetProxyIdRight == AssetProxyId.ERC721) { + expect(newERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]).to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]); + } else { + throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdRight}`); + } + + console.log("Right Maker: Buy Amount"); + if(makerAssetProxyIdLeft == AssetProxyId.ERC20) { + expect(newERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft]).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft]); + } else if(makerAssetProxyIdLeft == AssetProxyId.ERC721) { + expect(newERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort()).to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort()); + } else { + throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdLeft}`); + } + console.log("Right Maker: Fees"); + expect(newERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress]).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress]); + console.log("Taker: Receive Amount"); + if(makerAssetProxyIdLeft == AssetProxyId.ERC20) { + expect(newERC20BalancesByOwner[takerAddress][makerAssetAddressLeft]).to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][makerAssetAddressLeft]); + } else if(makerAssetProxyIdLeft == AssetProxyId.ERC721) { + expect(newERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort()).to.be.deep.equal(expectedERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort()); + } else { + throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdLeft}`); + } + console.log("Taker: Fees"); + expect(newERC20BalancesByOwner[takerAddress][this._feeTokenAddress]).to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][this._feeTokenAddress]); + console.log("Balance catch-all"); + expect(didExpectedBalancesMatchRealBalances).to.be.true(); + + /* // Compute actual transfer amounts let actualTransferAmounts = {}; const makerAssetProxyIdLeft = assetDataUtils.decodeAssetProxyId(signedOrderLeft.makerAssetData); @@ -163,24 +246,24 @@ export class MatchOrderTester { // Fees actualTransferAmounts.feePaidByLeftMaker = erc20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress].sub(newERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress]); actualTransferAmounts.feePaidByRightMaker = erc20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress].sub(newERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress]); - actualTransferAmounts.totalFeePaidByTaker = erc20BalancesByOwner[takerAddress][this._feeTokenAddress].sub(newERC20BalancesByOwner[takerAddress][this._feeTokenAddress]); + actualTransferAmounts.totalFeePaidByTaker = erc20BalancesByOwner[takerAddress][this._feeTokenAddress].sub(newERC20BalancesByOwner[takerAddress][this._feeTokenAddress]); console.log("amountBoughtByLeftMaker"); - expect(expectedTransferAmounts.amountBoughtByLeftMaker).to.be.bignumber.equal(actualTransferAmounts.amountBoughtByLeftMaker); + // expect(expectedTransferAmounts.amountBoughtByLeftMaker).to.be.bignumber.equal(actualTransferAmounts.amountBoughtByLeftMaker); console.log("amountSoldByLeftMaker"); - expect(expectedTransferAmounts.amountSoldByLeftMaker).to.be.bignumber.equal(actualTransferAmounts.amountSoldByLeftMaker); + // expect(expectedTransferAmounts.amountSoldByLeftMaker).to.be.bignumber.equal(actualTransferAmounts.amountSoldByLeftMaker); console.log("amountBoughtByRightMaker"); - expect(expectedTransferAmounts.amountBoughtByRightMaker).to.be.bignumber.equal(actualTransferAmounts.amountBoughtByRightMaker); + // expect(expectedTransferAmounts.amountBoughtByRightMaker).to.be.bignumber.equal(actualTransferAmounts.amountBoughtByRightMaker); console.log("amountSoldByRightMaker"); - expect(expectedTransferAmounts.amountSoldByRightMaker).to.be.bignumber.equal(actualTransferAmounts.amountSoldByRightMaker); + //expect(expectedTransferAmounts.amountSoldByRightMaker).to.be.bignumber.equal(actualTransferAmounts.amountSoldByRightMaker); console.log("amountReceivedByTaker"); - expect(expectedTransferAmounts.amountReceivedByTaker).to.be.bignumber.equal(actualTransferAmounts.amountReceivedByTaker); + //expect(expectedTransferAmounts.amountReceivedByTaker).to.be.bignumber.equal(actualTransferAmounts.amountReceivedByTaker); console.log("feePaidByLeftMaker"); - expect(expectedTransferAmounts.feePaidByLeftMaker).to.be.bignumber.equal(actualTransferAmounts.feePaidByLeftMaker); + // expect(expectedTransferAmounts.feePaidByLeftMaker).to.be.bignumber.equal(actualTransferAmounts.feePaidByLeftMaker); console.log("feePaidByRightMaker"); - expect(expectedTransferAmounts.feePaidByRightMaker).to.be.bignumber.equal(actualTransferAmounts.feePaidByRightMaker); + //expect(expectedTransferAmounts.feePaidByRightMaker).to.be.bignumber.equal(actualTransferAmounts.feePaidByRightMaker); console.log("totalFeePaidByTaker"); - expect(expectedTransferAmounts.totalFeePaidByTaker).to.be.bignumber.equal(actualTransferAmounts.totalFeePaidByTaker); + // expect(expectedTransferAmounts.totalFeePaidByTaker).to.be.bignumber.equal(actualTransferAmounts.totalFeePaidByTaker); @@ -204,11 +287,12 @@ export class MatchOrderTester { // Fee Recipients feeReceivedLeft, feeReceivedRight, - };*/ + }; // This is a catch-all to ensure that no other balances changed console.log("Catch-all"); expect(didExpectedBalancesMatchRealBalances).to.be.true(); + */ return [newERC20BalancesByOwner, newERC721TokenIdsByOwner]; @@ -351,6 +435,13 @@ export class MatchOrderTester { _.remove(expectedNewERC721TokenIdsByOwner[makerAddressLeft][makerAssetAddressLeft], makerAssetIdLeft); // Right Maker expectedNewERC721TokenIdsByOwner[makerAddressRight][takerAssetAddressRight].push(takerAssetIdRight); + console.log("*** TRANSFERINF: " + JSON.stringify(makerAssetIdLeft)); + console.log("****"); + console.log(JSON.stringify(expectedNewERC721TokenIdsByOwner[makerAddressLeft][makerAssetAddressLeft])); + console.log("****"); + console.log(JSON.stringify(expectedNewERC721TokenIdsByOwner[makerAddressRight][takerAssetAddressRight])); + console.log("****"); + // Taker: Since there is only 1 asset transferred, the taker does not receive any of the left maker asset. } // Left Taker Asset (Right Maker Asset) From f697814849142a8a98229e17433f942eef5c25d3 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Wed, 22 Aug 2018 14:05:44 -0700 Subject: [PATCH 074/120] First balance test with intentional values --- .../contracts/test/exchange/match_orders.ts | 35 ++++-- .../test/utils/match_order_tester.ts | 119 +++++++++++------- 2 files changed, 95 insertions(+), 59 deletions(-) diff --git a/packages/contracts/test/exchange/match_orders.ts b/packages/contracts/test/exchange/match_orders.ts index b2ffa31b2f..3cffef7ad9 100644 --- a/packages/contracts/test/exchange/match_orders.ts +++ b/packages/contracts/test/exchange/match_orders.ts @@ -21,10 +21,11 @@ import { ERC721Wrapper } from '../utils/erc721_wrapper'; import { ExchangeWrapper } from '../utils/exchange_wrapper'; import { MatchOrderTester } from '../utils/match_order_tester'; import { OrderFactory } from '../utils/order_factory'; -import { ERC20BalancesByOwner, ERC721TokenIdsByOwner, OrderInfo, OrderStatus } from '../utils/types'; +import { ERC20BalancesByOwner, ERC721TokenIdsByOwner, OrderInfo, TransferAmountsByMatchOrders as TransferAmounts, OrderStatus } from '../utils/types'; import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; chaiSetup.configure(); + const expect = chai.expect; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); @@ -212,7 +213,7 @@ describe.only('matchOrders', () => { }); */ - it('Jacobs Example', async () => { + it.only('Jacobs Example', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ makerAddress: makerAddressLeft, @@ -228,6 +229,23 @@ describe.only('matchOrders', () => { takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 0), feeRecipientAddress: feeRecipientAddressRight, }); + // TODO: These values will change after implementation of rounding up has been merged + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 0), + amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 0), + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), // 100% + // Right Maker + amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 0), + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 16), // 75% + // Taker + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(9), 0), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), // 100% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 17), // 50% + }; + const expectedEndStateLeft = OrderStatus.FILLABLE; + const expectedEndStateRight = OrderStatus.FULLY_FILLED; // Match signedOrderLeft with signedOrderRight await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, @@ -235,15 +253,10 @@ describe.only('matchOrders', () => { takerAddress, erc20BalancesByOwner, erc721TokenIdsByOwner, + expectedTransferAmounts, + expectedEndStateLeft, + expectedEndStateRight ); - // // Verify left order was fully filled - const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft); - //expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); - console.log("*** LEFT ORDER INFO ***\n", JSON.stringify(leftOrderInfo), "\n***************"); - // Verify right order was fully filled - const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight); - // expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); - console.log("*** RIGHT ORDER INFO ***\n", JSON.stringify(rightOrderInfo), "\n***************"); }); @@ -825,6 +838,6 @@ describe.only('matchOrders', () => { // Verify right order was fully filled const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight); expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); - }); + });*/ }); }); // tslint:disable-line:max-file-line-count diff --git a/packages/contracts/test/utils/match_order_tester.ts b/packages/contracts/test/utils/match_order_tester.ts index f9e45319a5..7b071015fa 100644 --- a/packages/contracts/test/utils/match_order_tester.ts +++ b/packages/contracts/test/utils/match_order_tester.ts @@ -8,7 +8,7 @@ import { chaiSetup } from './chai_setup'; import { ERC20Wrapper } from './erc20_wrapper'; import { ERC721Wrapper } from './erc721_wrapper'; import { ExchangeWrapper } from './exchange_wrapper'; -import { ERC20BalancesByOwner, ERC721TokenIdsByOwner, TransferAmountsByMatchOrders as TransferAmounts } from './types'; +import { ERC20BalancesByOwner, ERC721TokenIdsByOwner, TransferAmountsByMatchOrders as TransferAmounts , OrderStatus} from './types'; import { TransactionReceiptWithDecodedLogs } from '../../../../node_modules/ethereum-types'; chaiSetup.configure(); @@ -58,25 +58,30 @@ export class MatchOrderTester { return doesErc721TokenIdsMatch; } - /* - private static compareTokenIdLists(list1: BigNumber[], list2: BigNumber[]) { - // ERC721 Token Ids - list1 = _.(list1); - _.sortBy(tokenIds); - }); - }, + private async _verifyInitialOrderStates( + signedOrderLeft: SignedOrder, + signedOrderRight: SignedOrder, + initialTakerAssetFilledAmountLeft?: BigNumber, + initialTakerAssetFilledAmountRight?: BigNumber, + ): Promise<[BigNumber, BigNumber]> { + // Verify Left order preconditions + const orderTakerAssetFilledAmountLeft = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( + orderHashUtils.getOrderHashHex(signedOrderLeft), ); - const sortedNewERC721TokenIdsByOwner = _.mapValues(realERC721TokenIdsByOwner, tokenIdsByOwner => { - _.mapValues(tokenIdsByOwner, tokenIds => { - _.sortBy(tokenIds); - }); - }); - const doesErc721TokenIdsMatch = _.isEqual( - sortedExpectedNewERC721TokenIdsByOwner, - sortedNewERC721TokenIdsByOwner, + const expectedOrderFilledAmountLeft = initialTakerAssetFilledAmountLeft + ? initialTakerAssetFilledAmountLeft + : new BigNumber(0); + expect(expectedOrderFilledAmountLeft).to.be.bignumber.equal(orderTakerAssetFilledAmountLeft); + // Verify Right order preconditions + const orderTakerAssetFilledAmountRight = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( + orderHashUtils.getOrderHashHex(signedOrderRight), ); - return doesErc721TokenIdsMatch; - }*/ + const expectedOrderFilledAmountRight = initialTakerAssetFilledAmountRight + ? initialTakerAssetFilledAmountRight + : new BigNumber(0); + expect(expectedOrderFilledAmountRight).to.be.bignumber.equal(orderTakerAssetFilledAmountRight); + return [orderTakerAssetFilledAmountLeft, orderTakerAssetFilledAmountRight]; + } /// @dev Constructs new MatchOrderTester. /// @param exchangeWrapper Used to call to the Exchange. @@ -110,30 +115,45 @@ export class MatchOrderTester { takerAddress: string, erc20BalancesByOwner: ERC20BalancesByOwner, erc721TokenIdsByOwner: ERC721TokenIdsByOwner, + expectedTransferAmounts: TransferAmounts, + leftOrderEndState: OrderStatus, + rightOrderEndState: OrderStatus, initialTakerAssetFilledAmountLeft?: BigNumber, initialTakerAssetFilledAmountRight?: BigNumber, ): Promise<[ERC20BalancesByOwner, ERC721TokenIdsByOwner]> { - // Verify Left order preconditions - const orderTakerAssetFilledAmountLeft = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( - orderHashUtils.getOrderHashHex(signedOrderLeft), + // Verify initial order states + let orderTakerAssetFilledAmountLeft: BigNumber; + let orderTakerAssetFilledAmountRight: BigNumber; + [orderTakerAssetFilledAmountLeft, orderTakerAssetFilledAmountRight] = await this._verifyInitialOrderStates( + signedOrderLeft, + signedOrderRight, + initialTakerAssetFilledAmountLeft, + initialTakerAssetFilledAmountRight ); - const expectedOrderFilledAmountLeft = initialTakerAssetFilledAmountLeft - ? initialTakerAssetFilledAmountLeft - : new BigNumber(0); - expect(expectedOrderFilledAmountLeft).to.be.bignumber.equal(orderTakerAssetFilledAmountLeft); - // Verify Right order preconditions - const orderTakerAssetFilledAmountRight = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( - orderHashUtils.getOrderHashHex(signedOrderRight), - ); - const expectedOrderFilledAmountRight = initialTakerAssetFilledAmountRight - ? initialTakerAssetFilledAmountRight - : new BigNumber(0); - expect(expectedOrderFilledAmountRight).to.be.bignumber.equal(orderTakerAssetFilledAmountRight); // Match left & right orders const transactionReceipt = await this._exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress); const newERC20BalancesByOwner = await this._erc20Wrapper.getBalancesAsync(); const newERC721TokenIdsByOwner = await this._erc721Wrapper.getBalancesAsync(); + // Calculate expected fees + + + // Verify logs + + // Verify balances + + + + console.log(JSON.stringify(transactionReceipt, null, 4)); + + // Verify logs (and return values) + + // Verify exchange state + + // Verify balances + + // Calculate expected balance changes + /* const expectedTransferAmounts = await this._calculateExpectedTransferAmountsAsync( signedOrderLeft, signedOrderRight, @@ -141,7 +161,7 @@ export class MatchOrderTester { orderTakerAssetFilledAmountRight, transactionReceipt, takerAddress - ); + );*/ let expectedERC20BalancesByOwner: ERC20BalancesByOwner; let expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner; [expectedERC20BalancesByOwner, expectedERC721TokenIdsByOwner] = this._calculateExpectedBalances( @@ -169,6 +189,7 @@ export class MatchOrderTester { const makerAssetAddressRight = makerERC20AssetDataRight.tokenAddress; console.log("Left Maker: Sell Amount"); + // describe('asdad', () => { if(makerAssetProxyIdLeft == AssetProxyId.ERC20) { expect(newERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft]).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft]); } else if(makerAssetProxyIdLeft == AssetProxyId.ERC721) { @@ -177,6 +198,8 @@ export class MatchOrderTester { throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdLeft}`); } + // }); + console.log("Left Maker: Buy Amount"); if(makerAssetProxyIdRight == AssetProxyId.ERC20) { expect(newERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight]).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight]); @@ -292,11 +315,12 @@ export class MatchOrderTester { // This is a catch-all to ensure that no other balances changed console.log("Catch-all"); expect(didExpectedBalancesMatchRealBalances).to.be.true(); - */ - + +*/ return [newERC20BalancesByOwner, newERC721TokenIdsByOwner]; } + /// @dev Calculates expected transfer amounts between order makers, fee recipients, and /// the taker when two orders are matched. /// @param signedOrderLeft First matched order. @@ -312,7 +336,7 @@ export class MatchOrderTester { transactionReceipt: TransactionReceiptWithDecodedLogs, takerAddress: string ): Promise { - // Parse logs + // Parse logs expect(transactionReceipt.logs.length).to.be.equal(2); // First log is for left fill const leftLog = ((transactionReceipt.logs[0] as any) as {args: { makerAddress: string, takerAddress: string, makerAssetFilledAmount: string, takerAssetFilledAmount: string, makerFeePaid: string, takerFeePaid: string}}); @@ -344,7 +368,6 @@ export class MatchOrderTester { const feePaidByRightMaker = signedOrderRight.makerFee .times(amountSoldByRightMaker) .dividedToIntegerBy(signedOrderRight.makerAssetAmount); - const feePaidByTakerLeft = signedOrderLeft.takerFee .times(amountBoughtByLeftMaker) .dividedToIntegerBy(signedOrderLeft.takerAssetAmount); @@ -361,21 +384,21 @@ export class MatchOrderTester { // Left Maker amountBoughtByLeftMaker, amountSoldByLeftMaker, - amountReceivedByLeftMaker, + // amountReceivedByLeftMaker, feePaidByLeftMaker, // Right Maker amountBoughtByRightMaker, amountSoldByRightMaker, - amountReceivedByRightMaker, + // amountReceivedByRightMaker, feePaidByRightMaker, // Taker amountReceivedByTaker, feePaidByTakerLeft, feePaidByTakerRight, - totalFeePaidByTaker, + // totalFeePaidByTaker, // Fee Recipients - feeReceivedLeft, - feeReceivedRight, + // feeReceivedLeft, + // feeReceivedRight, }; return expectedTransferAmounts; } @@ -418,7 +441,7 @@ export class MatchOrderTester { expectedNewERC20BalancesByOwner[makerAddressRight][ takerAssetAddressRight ] = expectedNewERC20BalancesByOwner[makerAddressRight][takerAssetAddressRight].add( - expectedTransferAmounts.amountReceivedByRightMaker, + expectedTransferAmounts.amountBoughtByRightMaker, ); // Taker expectedNewERC20BalancesByOwner[takerAddress][makerAssetAddressLeft] = expectedNewERC20BalancesByOwner[ @@ -455,7 +478,7 @@ export class MatchOrderTester { // Left Maker expectedNewERC20BalancesByOwner[makerAddressLeft][takerAssetAddressLeft] = expectedNewERC20BalancesByOwner[ makerAddressLeft - ][takerAssetAddressLeft].add(expectedTransferAmounts.amountReceivedByLeftMaker); + ][takerAssetAddressLeft].add(expectedTransferAmounts.amountBoughtByLeftMaker); // Right Maker expectedNewERC20BalancesByOwner[makerAddressRight][ makerAssetAddressRight @@ -485,18 +508,18 @@ export class MatchOrderTester { // Taker Fees expectedNewERC20BalancesByOwner[takerAddress][this._feeTokenAddress] = expectedNewERC20BalancesByOwner[ takerAddress - ][this._feeTokenAddress].minus(expectedTransferAmounts.totalFeePaidByTaker); + ][this._feeTokenAddress].minus(expectedTransferAmounts.feePaidByTakerLeft.add(expectedTransferAmounts.feePaidByTakerRight)); // Left Fee Recipient Fees expectedNewERC20BalancesByOwner[feeRecipientAddressLeft][ this._feeTokenAddress ] = expectedNewERC20BalancesByOwner[feeRecipientAddressLeft][this._feeTokenAddress].add( - expectedTransferAmounts.feeReceivedLeft, + expectedTransferAmounts.feePaidByLeftMaker.add(expectedTransferAmounts.feePaidByTakerLeft), ); // Right Fee Recipient Fees expectedNewERC20BalancesByOwner[feeRecipientAddressRight][ this._feeTokenAddress ] = expectedNewERC20BalancesByOwner[feeRecipientAddressRight][this._feeTokenAddress].add( - expectedTransferAmounts.feeReceivedRight, + expectedTransferAmounts.feePaidByRightMaker.add(expectedTransferAmounts.feePaidByTakerRight), ); return [expectedNewERC20BalancesByOwner, expectedNewERC721TokenIdsByOwner]; From 8c706ac6392c79ef46da37dd4b76f58f7d3f57e4 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Wed, 22 Aug 2018 15:22:27 -0700 Subject: [PATCH 075/120] Verify logs --- .../test/utils/match_order_tester.ts | 116 +++++++----------- 1 file changed, 44 insertions(+), 72 deletions(-) diff --git a/packages/contracts/test/utils/match_order_tester.ts b/packages/contracts/test/utils/match_order_tester.ts index 7b071015fa..15915e511b 100644 --- a/packages/contracts/test/utils/match_order_tester.ts +++ b/packages/contracts/test/utils/match_order_tester.ts @@ -134,10 +134,15 @@ export class MatchOrderTester { const transactionReceipt = await this._exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress); const newERC20BalancesByOwner = await this._erc20Wrapper.getBalancesAsync(); const newERC721TokenIdsByOwner = await this._erc721Wrapper.getBalancesAsync(); - // Calculate expected fees - - - // Verify logs + // Verify logs & return values + this._verifyLogsAsync( + signedOrderLeft, + signedOrderRight, + transactionReceipt, + takerAddress, + expectedTransferAmounts + ); + // Verify exchange state // Verify balances @@ -328,78 +333,45 @@ export class MatchOrderTester { /// @param orderTakerAssetFilledAmountLeft How much left order has been filled, prior to matching orders. /// @param orderTakerAssetFilledAmountRight How much the right order has been filled, prior to matching orders. /// @return TransferAmounts A struct containing the expected transfer amounts. - private async _calculateExpectedTransferAmountsAsync( + private async _verifyLogsAsync( signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder, - orderTakerAssetFilledAmountLeft: BigNumber, - orderTakerAssetFilledAmountRight: BigNumber, transactionReceipt: TransactionReceiptWithDecodedLogs, - takerAddress: string - ): Promise { + takerAddress: string, + expectedTransferAmounts: TransferAmounts + ) { // Parse logs - expect(transactionReceipt.logs.length).to.be.equal(2); - // First log is for left fill - const leftLog = ((transactionReceipt.logs[0] as any) as {args: { makerAddress: string, takerAddress: string, makerAssetFilledAmount: string, takerAssetFilledAmount: string, makerFeePaid: string, takerFeePaid: string}}); - expect(leftLog.args.makerAddress).to.be.equal(signedOrderLeft.makerAddress); - expect(leftLog.args.takerAddress).to.be.equal(takerAddress); - const amountBoughtByLeftMaker = new BigNumber(leftLog.args.takerAssetFilledAmount); - const amountSoldByLeftMaker = new BigNumber(leftLog.args.makerAssetFilledAmount); - // Second log is for right fill - const rightLog = ((transactionReceipt.logs[1] as any) as {args: { makerAddress: string, takerAddress: string, makerAssetFilledAmount: string, takerAssetFilledAmount: string, makerFeePaid: string, takerFeePaid: string}}); - expect(rightLog.args.makerAddress).to.be.equal(signedOrderRight.makerAddress); - expect(rightLog.args.takerAddress).to.be.equal(takerAddress); - const amountBoughtByRightMaker = new BigNumber(rightLog.args.takerAssetFilledAmount); - const amountSoldByRightMaker = new BigNumber(rightLog.args.makerAssetFilledAmount); - // Determine amount received by taker - const amountReceivedByTaker = amountSoldByLeftMaker.sub(amountBoughtByRightMaker); - - const amountReceivedByLeftMaker = amountBoughtByLeftMaker; - const amountReceivedByRightMaker = amountBoughtByRightMaker; - - console.log("Amount bought by left maker = ", JSON.stringify(amountBoughtByLeftMaker)); - console.log("Amount sold by left maker = ", JSON.stringify(amountSoldByLeftMaker)); - console.log("Amount bought by right maker = ", JSON.stringify(amountBoughtByRightMaker)); - console.log("Amount sold by right maker = ", JSON.stringify(amountSoldByRightMaker)); - console.log("Amount received by taker = ", JSON.stringify(amountReceivedByTaker)); - //const amountReceivedByLeftMaker = amountSoldByRightMaker; - const feePaidByLeftMaker = signedOrderLeft.makerFee - .times(amountSoldByLeftMaker) - .dividedToIntegerBy(signedOrderLeft.makerAssetAmount); - const feePaidByRightMaker = signedOrderRight.makerFee - .times(amountSoldByRightMaker) - .dividedToIntegerBy(signedOrderRight.makerAssetAmount); - const feePaidByTakerLeft = signedOrderLeft.takerFee - .times(amountBoughtByLeftMaker) - .dividedToIntegerBy(signedOrderLeft.takerAssetAmount); - - - const feePaidByTakerRight = signedOrderRight.takerFee - .times(amountBoughtByRightMaker) - .dividedToIntegerBy(signedOrderRight.takerAssetAmount); - const totalFeePaidByTaker = feePaidByTakerLeft.add(feePaidByTakerRight); - const feeReceivedLeft = feePaidByLeftMaker.add(feePaidByTakerLeft); - const feeReceivedRight = feePaidByRightMaker.add(feePaidByTakerRight); - // Return values - const expectedTransferAmounts = { - // Left Maker - amountBoughtByLeftMaker, - amountSoldByLeftMaker, - // amountReceivedByLeftMaker, - feePaidByLeftMaker, - // Right Maker - amountBoughtByRightMaker, - amountSoldByRightMaker, - // amountReceivedByRightMaker, - feePaidByRightMaker, - // Taker - amountReceivedByTaker, - feePaidByTakerLeft, - feePaidByTakerRight, - // totalFeePaidByTaker, - // Fee Recipients - // feeReceivedLeft, - // feeReceivedRight, - }; + expect(transactionReceipt.logs.length, "Checking number of logs").to.be.equal(2); + // First log is for left fill + const leftLog = ((transactionReceipt.logs[0] as any) as {args: { makerAddress: string, takerAddress: string, makerAssetFilledAmount: string, takerAssetFilledAmount: string, makerFeePaid: string, takerFeePaid: string}}); + expect(leftLog.args.makerAddress, "Checking logged maker address of left order").to.be.equal(signedOrderLeft.makerAddress); + expect(leftLog.args.takerAddress, "Checking logged taker address of right order").to.be.equal(takerAddress); + const amountBoughtByLeftMaker = new BigNumber(leftLog.args.takerAssetFilledAmount); + const amountSoldByLeftMaker = new BigNumber(leftLog.args.makerAssetFilledAmount); + const feePaidByLeftMaker = new BigNumber(leftLog.args.makerFeePaid); + const feePaidByTakerLeft = new BigNumber(leftLog.args.takerFeePaid); + // Second log is for right fill + const rightLog = ((transactionReceipt.logs[1] as any) as {args: { makerAddress: string, takerAddress: string, makerAssetFilledAmount: string, takerAssetFilledAmount: string, makerFeePaid: string, takerFeePaid: string}}); + expect(rightLog.args.makerAddress, "Checking logged maker address of right order").to.be.equal(signedOrderRight.makerAddress); + expect(rightLog.args.takerAddress, "Checking loggerd taker address of right order").to.be.equal(takerAddress); + const amountBoughtByRightMaker = new BigNumber(rightLog.args.takerAssetFilledAmount); + const amountSoldByRightMaker = new BigNumber(rightLog.args.makerAssetFilledAmount); + const feePaidByRightMaker = new BigNumber(rightLog.args.makerFeePaid); + const feePaidByTakerRight = new BigNumber(rightLog.args.takerFeePaid); + // Derive amount received by taker + const amountReceivedByTaker = amountSoldByLeftMaker.sub(amountBoughtByRightMaker); + // Verify log values - left order + expect(expectedTransferAmounts.amountBoughtByLeftMaker, "Checking logged amount bought by left maker").to.be.bignumber.equal(amountBoughtByLeftMaker); + expect(expectedTransferAmounts.amountSoldByLeftMaker, "Checking logged amount sold by left maker").to.be.bignumber.equal(amountSoldByLeftMaker); + expect(expectedTransferAmounts.feePaidByLeftMaker, "Checking logged fee paid by left maker").to.be.bignumber.equal(feePaidByLeftMaker); + expect(expectedTransferAmounts.feePaidByTakerLeft, "Checking logged fee paid on left order by taker").to.be.bignumber.equal(feePaidByTakerLeft); + // Verify log values - right order + expect(expectedTransferAmounts.amountBoughtByRightMaker, "Checking logged amount bought by right maker").to.be.bignumber.equal(amountBoughtByRightMaker); + expect(expectedTransferAmounts.amountSoldByRightMaker, "Checking logged amount sold by right maker").to.be.bignumber.equal(amountSoldByRightMaker); + expect(expectedTransferAmounts.feePaidByRightMaker, "Checking logged fee paid by right maker").to.be.bignumber.equal(feePaidByRightMaker); + expect(expectedTransferAmounts.feePaidByTakerRight, "Checking logged fee paid on right order by taker").to.be.bignumber.equal(feePaidByTakerRight); + // Verify deriv ed amount received by taker + expect(expectedTransferAmounts.amountReceivedByTaker, "Checking logged amount received by taker").to.be.bignumber.equal(amountReceivedByTaker); return expectedTransferAmounts; } /// @dev Calculates the expected balances of order makers, fee recipients, and the taker, From d2912561585a044eec3cf82b65e76760e7cb47c3 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Wed, 22 Aug 2018 16:33:44 -0700 Subject: [PATCH 076/120] Passes comprehensive test --- .../test/utils/match_order_tester.ts | 332 ++++++++---------- 1 file changed, 141 insertions(+), 191 deletions(-) diff --git a/packages/contracts/test/utils/match_order_tester.ts b/packages/contracts/test/utils/match_order_tester.ts index 15915e511b..c412595f50 100644 --- a/packages/contracts/test/utils/match_order_tester.ts +++ b/packages/contracts/test/utils/match_order_tester.ts @@ -8,7 +8,7 @@ import { chaiSetup } from './chai_setup'; import { ERC20Wrapper } from './erc20_wrapper'; import { ERC721Wrapper } from './erc721_wrapper'; import { ExchangeWrapper } from './exchange_wrapper'; -import { ERC20BalancesByOwner, ERC721TokenIdsByOwner, TransferAmountsByMatchOrders as TransferAmounts , OrderStatus} from './types'; +import { ERC20BalancesByOwner, ERC721TokenIdsByOwner, TransferAmountsByMatchOrders as TransferAmounts, OrderInfo, OrderStatus} from './types'; import { TransactionReceiptWithDecodedLogs } from '../../../../node_modules/ethereum-types'; chaiSetup.configure(); @@ -20,23 +20,109 @@ export class MatchOrderTester { private readonly _erc721Wrapper: ERC721Wrapper; private readonly _feeTokenAddress: string; + private async _verifyBalancesAsync( + signedOrderLeft: SignedOrder, + signedOrderRight: SignedOrder, + initialERC20BalancesByOwner: ERC20BalancesByOwner, + initialERC721TokenIdsByOwner: ERC721TokenIdsByOwner, + finalERC20BalancesByOwner: ERC20BalancesByOwner, + finalERC721TokenIdsByOwner: ERC721TokenIdsByOwner, + expectedTransferAmounts: TransferAmounts, + takerAddress: string + ) + { + let expectedERC20BalancesByOwner: ERC20BalancesByOwner; + let expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner; + [expectedERC20BalancesByOwner, expectedERC721TokenIdsByOwner] = this._calculateExpectedBalances( + signedOrderLeft, + signedOrderRight, + takerAddress, + initialERC20BalancesByOwner, + initialERC721TokenIdsByOwner, + expectedTransferAmounts, + ); + // Verify balances of makers, taker, and fee recipients + await this._verifyMakerTakerAndFeeRecipientBalancesAsync( + signedOrderLeft, + signedOrderRight, + expectedERC20BalancesByOwner, + finalERC20BalancesByOwner, + expectedERC721TokenIdsByOwner, + finalERC721TokenIdsByOwner, + takerAddress + ); + // Verify balances for all known accounts + await this._verifyAllKnownBalancesAsync( + expectedERC20BalancesByOwner, + finalERC20BalancesByOwner, + expectedERC721TokenIdsByOwner, + finalERC721TokenIdsByOwner, + ); + } + + private async _verifyMakerTakerAndFeeRecipientBalancesAsync( + signedOrderLeft: SignedOrder, + signedOrderRight: SignedOrder, + expectedERC20BalancesByOwner: ERC20BalancesByOwner, + realERC20BalancesByOwner: ERC20BalancesByOwner, + expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner, + realERC721TokenIdsByOwner: ERC721TokenIdsByOwner, + takerAddress: string + ) { + // Individual balance comparisons + const makerAssetProxyIdLeft = assetDataUtils.decodeAssetProxyId(signedOrderLeft.makerAssetData); + const makerERC20AssetDataLeft = makerAssetProxyIdLeft == AssetProxyId.ERC20 ? assetDataUtils.decodeERC20AssetData(signedOrderLeft.makerAssetData) : assetDataUtils.decodeERC721AssetData(signedOrderLeft.makerAssetData); + const makerAssetAddressLeft = makerERC20AssetDataLeft.tokenAddress; + const makerAssetProxyIdRight = assetDataUtils.decodeAssetProxyId(signedOrderRight.makerAssetData); + const makerERC20AssetDataRight = makerAssetProxyIdRight == AssetProxyId.ERC20 ? assetDataUtils.decodeERC20AssetData(signedOrderRight.makerAssetData) : assetDataUtils.decodeERC721AssetData(signedOrderRight.makerAssetData); + const makerAssetAddressRight = makerERC20AssetDataRight.tokenAddress; + // describe('asdad', () => { + if(makerAssetProxyIdLeft == AssetProxyId.ERC20) { + expect(realERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft], "Checking left maker egress ERC20 account balance").to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft]); + expect(realERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft], "Checking right maker ingress ERC20 account balance").to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft]); + expect(realERC20BalancesByOwner[takerAddress][makerAssetAddressLeft], "Checking taker ingress ERC20 account balance").to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][makerAssetAddressLeft]); + } else if(makerAssetProxyIdLeft == AssetProxyId.ERC721) { + expect(realERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort(), "Checking left maker egress ERC721 account holdings").to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort()); + expect(realERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort(), "Checking right maker ERC721 account holdings").to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort()); + expect(realERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort(), "Checking taker ingress ERC721 account holdings").to.be.deep.equal(expectedERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort()); + } else { + throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdLeft}`); + } + if(makerAssetProxyIdRight == AssetProxyId.ERC20) { + expect(realERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight], "Checking left maker ingress ERC20 account balance").to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight]); + expect(realERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight], "Checking right maker egress ERC20 account balance").to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]); + } else if(makerAssetProxyIdRight == AssetProxyId.ERC721) { + expect(realERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort(), "Checking left maker ingress ERC721 account holdings").to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort()); + expect(realERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight], "Checking right maker agress ERC721 account holdings").to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]); + } else { + throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdRight}`); + } + // Paid fees + expect(realERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress], "Checking left maker egress ERC20 account fees").to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress]); + expect(realERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress], "Checking right maker egress ERC20 account fees").to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress]); + expect(realERC20BalancesByOwner[takerAddress][this._feeTokenAddress], "Checking taker egress ERC20 account fees").to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][this._feeTokenAddress]); + // Received fees + expect(realERC20BalancesByOwner[signedOrderLeft.feeRecipientAddress][this._feeTokenAddress], "Checking left fee recipient ingress ERC20 account fees").to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.feeRecipientAddress][this._feeTokenAddress]); + expect(realERC20BalancesByOwner[signedOrderRight.feeRecipientAddress][this._feeTokenAddress], "Checking right fee receipient ingress ERC20 account fees").to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.feeRecipientAddress][this._feeTokenAddress]); + } + /// @dev Compares a pair of ERC20 balances and a pair of ERC721 token owners. /// @param expectedNewERC20BalancesByOwner Expected ERC20 balances. /// @param realERC20BalancesByOwner Actual ERC20 balances. /// @param expectedNewERC721TokenIdsByOwner Expected ERC721 token owners. /// @param realERC721TokenIdsByOwner Actual ERC20 token owners. /// @return True only if ERC20 balances match and ERC721 token owners match. - private static _compareExpectedAndRealBalances( + private async _verifyAllKnownBalancesAsync( expectedNewERC20BalancesByOwner: ERC20BalancesByOwner, realERC20BalancesByOwner: ERC20BalancesByOwner, expectedNewERC721TokenIdsByOwner: ERC721TokenIdsByOwner, realERC721TokenIdsByOwner: ERC721TokenIdsByOwner, - ): boolean { + ) { + // ERC20 Balances - const doesErc20BalancesMatch = _.isEqual(expectedNewERC20BalancesByOwner, realERC20BalancesByOwner); - if (!doesErc20BalancesMatch) { - return false; - } + const erc20BalancesMatch = _.isEqual(expectedNewERC20BalancesByOwner, realERC20BalancesByOwner); + expect(erc20BalancesMatch, "Checking all known ERC20 account balances").to.be.true(); + // ERC721 Token Ids const sortedExpectedNewERC721TokenIdsByOwner = _.mapValues( expectedNewERC721TokenIdsByOwner, @@ -51,11 +137,11 @@ export class MatchOrderTester { _.sortBy(tokenIds); }); }); - const doesErc721TokenIdsMatch = _.isEqual( + const erc721TokenIdsMatch = _.isEqual( sortedExpectedNewERC721TokenIdsByOwner, sortedNewERC721TokenIdsByOwner, ); - return doesErc721TokenIdsMatch; + expect(erc721TokenIdsMatch, "Checking all known ERC721 account balances").to.be.true(); } private async _verifyInitialOrderStates( @@ -134,8 +220,8 @@ export class MatchOrderTester { const transactionReceipt = await this._exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress); const newERC20BalancesByOwner = await this._erc20Wrapper.getBalancesAsync(); const newERC721TokenIdsByOwner = await this._erc721Wrapper.getBalancesAsync(); - // Verify logs & return values - this._verifyLogsAsync( + // Verify logs + await this._verifyLogsAsync( signedOrderLeft, signedOrderRight, transactionReceipt, @@ -143,189 +229,26 @@ export class MatchOrderTester { expectedTransferAmounts ); // Verify exchange state - - // Verify balances - - - - console.log(JSON.stringify(transactionReceipt, null, 4)); - - // Verify logs (and return values) - - // Verify exchange state - - // Verify balances - - - // Calculate expected balance changes - /* - const expectedTransferAmounts = await this._calculateExpectedTransferAmountsAsync( + await this._verifyExchangeStateAsync( signedOrderLeft, signedOrderRight, orderTakerAssetFilledAmountLeft, orderTakerAssetFilledAmountRight, - transactionReceipt, - takerAddress - );*/ - let expectedERC20BalancesByOwner: ERC20BalancesByOwner; - let expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner; - [expectedERC20BalancesByOwner, expectedERC721TokenIdsByOwner] = this._calculateExpectedBalances( + expectedTransferAmounts + ); + // Verify balances of makers, taker, and fee recipients + await this._verifyBalancesAsync( signedOrderLeft, signedOrderRight, - takerAddress, erc20BalancesByOwner, erc721TokenIdsByOwner, - expectedTransferAmounts, - ); - // Assert our expected balances are equal to the actual balances - const didExpectedBalancesMatchRealBalances = MatchOrderTester._compareExpectedAndRealBalances( - expectedERC20BalancesByOwner, newERC20BalancesByOwner, - expectedERC721TokenIdsByOwner, newERC721TokenIdsByOwner, + expectedTransferAmounts, + takerAddress ); - - // Individual balance comparisons - const makerAssetProxyIdLeft = assetDataUtils.decodeAssetProxyId(signedOrderLeft.makerAssetData); - const makerERC20AssetDataLeft = makerAssetProxyIdLeft == AssetProxyId.ERC20 ? assetDataUtils.decodeERC20AssetData(signedOrderLeft.makerAssetData) : assetDataUtils.decodeERC721AssetData(signedOrderLeft.makerAssetData); - const makerAssetAddressLeft = makerERC20AssetDataLeft.tokenAddress; - const makerAssetProxyIdRight = assetDataUtils.decodeAssetProxyId(signedOrderRight.makerAssetData); - const makerERC20AssetDataRight = makerAssetProxyIdRight == AssetProxyId.ERC20 ? assetDataUtils.decodeERC20AssetData(signedOrderRight.makerAssetData) : assetDataUtils.decodeERC721AssetData(signedOrderRight.makerAssetData); - const makerAssetAddressRight = makerERC20AssetDataRight.tokenAddress; - - console.log("Left Maker: Sell Amount"); - // describe('asdad', () => { - if(makerAssetProxyIdLeft == AssetProxyId.ERC20) { - expect(newERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft]).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft]); - } else if(makerAssetProxyIdLeft == AssetProxyId.ERC721) { - expect(newERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort()).to.be.deep.equal(newERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort()); - } else { - throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdLeft}`); - } - - // }); - - console.log("Left Maker: Buy Amount"); - if(makerAssetProxyIdRight == AssetProxyId.ERC20) { - expect(newERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight]).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight]); - } else if(makerAssetProxyIdRight == AssetProxyId.ERC721) { - expect(newERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort()).to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort()); - } else { - throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdRight}`); - } - - console.log("Left Maker: Fees"); - expect(newERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress]).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress]); - - console.log("Right Maker: Sell Amount"); - if(makerAssetProxyIdRight == AssetProxyId.ERC20) { - expect(newERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]); - } else if(makerAssetProxyIdRight == AssetProxyId.ERC721) { - expect(newERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]).to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]); - } else { - throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdRight}`); - } - - console.log("Right Maker: Buy Amount"); - if(makerAssetProxyIdLeft == AssetProxyId.ERC20) { - expect(newERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft]).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft]); - } else if(makerAssetProxyIdLeft == AssetProxyId.ERC721) { - expect(newERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort()).to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort()); - } else { - throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdLeft}`); - } - console.log("Right Maker: Fees"); - expect(newERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress]).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress]); - console.log("Taker: Receive Amount"); - if(makerAssetProxyIdLeft == AssetProxyId.ERC20) { - expect(newERC20BalancesByOwner[takerAddress][makerAssetAddressLeft]).to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][makerAssetAddressLeft]); - } else if(makerAssetProxyIdLeft == AssetProxyId.ERC721) { - expect(newERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort()).to.be.deep.equal(expectedERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort()); - } else { - throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdLeft}`); - } - console.log("Taker: Fees"); - expect(newERC20BalancesByOwner[takerAddress][this._feeTokenAddress]).to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][this._feeTokenAddress]); - console.log("Balance catch-all"); - expect(didExpectedBalancesMatchRealBalances).to.be.true(); - - /* - // Compute actual transfer amounts - let actualTransferAmounts = {}; - const makerAssetProxyIdLeft = assetDataUtils.decodeAssetProxyId(signedOrderLeft.makerAssetData); - if (makerAssetProxyIdLeft === AssetProxyId.ERC20) { - const erc20AssetData = assetDataUtils.decodeERC20AssetData(signedOrderLeft.makerAssetData); - const makerAssetAddressLeft = erc20AssetData.tokenAddress; - actualTransferAmounts.amountSoldByLeftMaker = erc20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sub(newERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft]); - actualTransferAmounts.amountBoughtByRightMaker = newERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sub(erc20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft]); - actualTransferAmounts.amountReceivedByRightMaker = actualTransferAmounts.amountBoughtByRightMaker; - actualTransferAmounts.amountReceivedByTaker = newERC20BalancesByOwner[takerAddress][makerAssetAddressLeft].sub(erc20BalancesByOwner[takerAddress][makerAssetAddressLeft]); - } else if(makerAssetProxyIdLeft === AssetProxyId.ERC721) { - } - const makerAssetProxyIdRight = assetDataUtils.decodeAssetProxyId(signedOrderRight.makerAssetData); - if (makerAssetProxyIdRight === AssetProxyId.ERC20) { - const erc20AssetData = assetDataUtils.decodeERC20AssetData(signedOrderRight.makerAssetData); - const makerAssetAddressRight = erc20AssetData.tokenAddress; - actualTransferAmounts.amountSoldByRightMaker = erc20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight].sub(newERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]); - actualTransferAmounts.amountBoughtByLeftMaker = newERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sub(erc20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight]); - actualTransferAmounts.amountReceivedByLeftMaker = actualTransferAmounts.amountBoughtByLeftMaker; - } else if(makerAssetProxyIdRight === AssetProxyId.ERC721) { - } - // Fees - actualTransferAmounts.feePaidByLeftMaker = erc20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress].sub(newERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress]); - actualTransferAmounts.feePaidByRightMaker = erc20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress].sub(newERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress]); - actualTransferAmounts.totalFeePaidByTaker = erc20BalancesByOwner[takerAddress][this._feeTokenAddress].sub(newERC20BalancesByOwner[takerAddress][this._feeTokenAddress]); - - console.log("amountBoughtByLeftMaker"); - // expect(expectedTransferAmounts.amountBoughtByLeftMaker).to.be.bignumber.equal(actualTransferAmounts.amountBoughtByLeftMaker); - console.log("amountSoldByLeftMaker"); - // expect(expectedTransferAmounts.amountSoldByLeftMaker).to.be.bignumber.equal(actualTransferAmounts.amountSoldByLeftMaker); - console.log("amountBoughtByRightMaker"); - // expect(expectedTransferAmounts.amountBoughtByRightMaker).to.be.bignumber.equal(actualTransferAmounts.amountBoughtByRightMaker); - console.log("amountSoldByRightMaker"); - //expect(expectedTransferAmounts.amountSoldByRightMaker).to.be.bignumber.equal(actualTransferAmounts.amountSoldByRightMaker); - console.log("amountReceivedByTaker"); - //expect(expectedTransferAmounts.amountReceivedByTaker).to.be.bignumber.equal(actualTransferAmounts.amountReceivedByTaker); - console.log("feePaidByLeftMaker"); - // expect(expectedTransferAmounts.feePaidByLeftMaker).to.be.bignumber.equal(actualTransferAmounts.feePaidByLeftMaker); - console.log("feePaidByRightMaker"); - //expect(expectedTransferAmounts.feePaidByRightMaker).to.be.bignumber.equal(actualTransferAmounts.feePaidByRightMaker); - console.log("totalFeePaidByTaker"); - // expect(expectedTransferAmounts.totalFeePaidByTaker).to.be.bignumber.equal(actualTransferAmounts.totalFeePaidByTaker); - - - -/* - const actualTransferAmounts = { - // Left Maker - amountBoughtByLeftMaker, - amountSoldByLeftMaker, - amountReceivedByLeftMaker, - feePaidByLeftMaker, - // Right Maker - amountBoughtByRightMaker, - amountSoldByRightMaker, - amountReceivedByRightMaker, - feePaidByRightMaker, - // Taker - amountReceivedByTaker, - feePaidByTakerLeft, - feePaidByTakerRight, - totalFeePaidByTaker, - // Fee Recipients - feeReceivedLeft, - feeReceivedRight, - }; - - // This is a catch-all to ensure that no other balances changed - console.log("Catch-all"); - expect(didExpectedBalancesMatchRealBalances).to.be.true(); - - -*/ return [newERC20BalancesByOwner, newERC721TokenIdsByOwner]; } - /// @dev Calculates expected transfer amounts between order makers, fee recipients, and /// the taker when two orders are matched. /// @param signedOrderLeft First matched order. @@ -370,13 +293,47 @@ export class MatchOrderTester { expect(expectedTransferAmounts.amountSoldByRightMaker, "Checking logged amount sold by right maker").to.be.bignumber.equal(amountSoldByRightMaker); expect(expectedTransferAmounts.feePaidByRightMaker, "Checking logged fee paid by right maker").to.be.bignumber.equal(feePaidByRightMaker); expect(expectedTransferAmounts.feePaidByTakerRight, "Checking logged fee paid on right order by taker").to.be.bignumber.equal(feePaidByTakerRight); - // Verify deriv ed amount received by taker + // Verify derived amount received by taker expect(expectedTransferAmounts.amountReceivedByTaker, "Checking logged amount received by taker").to.be.bignumber.equal(amountReceivedByTaker); - return expectedTransferAmounts; + } + /// @dev Calculates expected transfer amounts between order makers, fee recipients, and + /// the taker when two orders are matched. + /// @param signedOrderLeft First matched order. + /// @param signedOrderRight Second matched order. + /// @param orderTakerAssetFilledAmountLeft How much left order has been filled, prior to matching orders. + /// @param orderTakerAssetFilledAmountRight How much the right order has been filled, prior to matching orders. + /// @return TransferAmounts A struct containing the expected transfer amounts. + private async _verifyExchangeStateAsync( + signedOrderLeft: SignedOrder, + signedOrderRight: SignedOrder, + orderTakerAssetFilledAmountLeft: BigNumber, + orderTakerAssetFilledAmountRight: BigNumber, + expectedTransferAmounts: TransferAmounts + ) { + // Verify state for left order: amount bought by left maker + let amountBoughtByLeftMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( + orderHashUtils.getOrderHashHex(signedOrderLeft), + ); + amountBoughtByLeftMaker = amountBoughtByLeftMaker.minus(orderTakerAssetFilledAmountLeft); + expect(expectedTransferAmounts.amountBoughtByLeftMaker, "Checking exchange state for left order").to.be.bignumber.equal(amountBoughtByLeftMaker); + // Verify state for right order: amount bought by right maker + let amountBoughtByRightMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( + orderHashUtils.getOrderHashHex(signedOrderRight), + ); + amountBoughtByRightMaker = amountBoughtByRightMaker.minus(orderTakerAssetFilledAmountRight); + expect(expectedTransferAmounts.amountBoughtByRightMaker, "Checking exchange state for right order").to.be.bignumber.equal(amountBoughtByRightMaker); + // Verify left order status + const leftOrderInfo: OrderInfo = await this._exchangeWrapper.getOrderInfoAsync(signedOrderLeft); + const leftExpectedStatus = (expectedTransferAmounts.amountBoughtByLeftMaker.equals(signedOrderLeft.takerAssetAmount)) ? OrderStatus.FULLY_FILLED : OrderStatus.FILLABLE; + expect(leftOrderInfo.orderStatus as OrderStatus, "Checking exchange status for left order").to.be.equal(leftExpectedStatus); + // Verify right order status + const rightOrderInfo: OrderInfo = await this._exchangeWrapper.getOrderInfoAsync(signedOrderRight); + const rightExpectedStatus = (expectedTransferAmounts.amountBoughtByRightMaker.equals(signedOrderRight.takerAssetAmount)) ? OrderStatus.FULLY_FILLED : OrderStatus.FILLABLE; + expect(rightOrderInfo.orderStatus as OrderStatus, "Checking exchange status for right order").to.be.equal(rightExpectedStatus); } /// @dev Calculates the expected balances of order makers, fee recipients, and the taker, /// as a result of matching two orders. - /// @param signedOrderLeft First matched order. + /// @param signedOrderRight First matched order. /// @param signedOrderRight Second matched order. /// @param takerAddress Address of taker (the address who matched the two orders) /// @param erc20BalancesByOwner Current ERC20 balances. @@ -430,13 +387,6 @@ export class MatchOrderTester { _.remove(expectedNewERC721TokenIdsByOwner[makerAddressLeft][makerAssetAddressLeft], makerAssetIdLeft); // Right Maker expectedNewERC721TokenIdsByOwner[makerAddressRight][takerAssetAddressRight].push(takerAssetIdRight); - console.log("*** TRANSFERINF: " + JSON.stringify(makerAssetIdLeft)); - console.log("****"); - console.log(JSON.stringify(expectedNewERC721TokenIdsByOwner[makerAddressLeft][makerAssetAddressLeft])); - console.log("****"); - console.log(JSON.stringify(expectedNewERC721TokenIdsByOwner[makerAddressRight][takerAssetAddressRight])); - console.log("****"); - // Taker: Since there is only 1 asset transferred, the taker does not receive any of the left maker asset. } // Left Taker Asset (Right Maker Asset) From 5a1dce15be60fa88d6e317cd6dfa7b993c90c257 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Wed, 22 Aug 2018 20:17:23 -0700 Subject: [PATCH 077/120] Updated all existing match order tests to use new format --- .../contracts/test/exchange/match_orders.ts | 409 ++++++++++++------ .../test/utils/match_order_tester.ts | 20 +- 2 files changed, 301 insertions(+), 128 deletions(-) diff --git a/packages/contracts/test/exchange/match_orders.ts b/packages/contracts/test/exchange/match_orders.ts index 3cffef7ad9..eb2644ba68 100644 --- a/packages/contracts/test/exchange/match_orders.ts +++ b/packages/contracts/test/exchange/match_orders.ts @@ -21,7 +21,13 @@ import { ERC721Wrapper } from '../utils/erc721_wrapper'; import { ExchangeWrapper } from '../utils/exchange_wrapper'; import { MatchOrderTester } from '../utils/match_order_tester'; import { OrderFactory } from '../utils/order_factory'; -import { ERC20BalancesByOwner, ERC721TokenIdsByOwner, OrderInfo, TransferAmountsByMatchOrders as TransferAmounts, OrderStatus } from '../utils/types'; +import { + ERC20BalancesByOwner, + ERC721TokenIdsByOwner, + OrderInfo, + TransferAmountsByMatchOrders as TransferAmounts, + OrderStatus, +} from '../utils/types'; import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; chaiSetup.configure(); @@ -177,7 +183,6 @@ describe.only('matchOrders', () => { erc20BalancesByOwner = await erc20Wrapper.getBalancesAsync(); erc721TokenIdsByOwner = await erc721Wrapper.getBalancesAsync(); }); - /* it.only('should transfer the correct amounts when orders completely fill each other', async () => { @@ -213,7 +218,7 @@ describe.only('matchOrders', () => { }); */ - it.only('Jacobs Example', async () => { + it('Jacobs Example', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ makerAddress: makerAddressLeft, @@ -244,8 +249,6 @@ describe.only('matchOrders', () => { feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), // 100% feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 17), // 50% }; - const expectedEndStateLeft = OrderStatus.FILLABLE; - const expectedEndStateRight = OrderStatus.FULLY_FILLED; // Match signedOrderLeft with signedOrderRight await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, @@ -254,44 +257,8 @@ describe.only('matchOrders', () => { erc20BalancesByOwner, erc721TokenIdsByOwner, expectedTransferAmounts, - expectedEndStateLeft, - expectedEndStateRight ); }); - - - /* - it.only('Jacobs Example', async () => { - // Create orders to match - const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ - makerAddress: makerAddressLeft, - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 0), - feeRecipientAddress: feeRecipientAddressLeft, - }); - const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ - makerAddress: makerAddressRight, - makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), - takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), - makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 0), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0), - feeRecipientAddress: feeRecipientAddressRight, - }); - // Match signedOrderLeft with signedOrderRight - await matchOrderTester.matchOrdersAndVerifyBalancesAsync( - signedOrderLeft, - signedOrderRight, - takerAddress, - erc20BalancesByOwner, - erc721TokenIdsByOwner, - ); - // // Verify left order was fully filled - // const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft); - // expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); - // Verify right order was fully filled - // const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight); - // expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); - });*/ const reentrancyTest = (functionNames: string[]) => { _.forEach(functionNames, async (functionName: string, functionId: number) => { @@ -333,19 +300,28 @@ describe.only('matchOrders', () => { takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), }); // Match signedOrderLeft with signedOrderRight + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Right Maker + amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Taker + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + }; await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, signedOrderRight, takerAddress, erc20BalancesByOwner, erc721TokenIdsByOwner, + expectedTransferAmounts, ); - // Verify left order was fully filled - const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft); - expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); - // Verify right order was fully filled - const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight); - expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); }); it('should transfer the correct amounts when orders completely fill each other and taker doesnt take a profit', async () => { @@ -358,32 +334,29 @@ describe.only('matchOrders', () => { makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), }); - // Store original taker balance - const takerInitialBalances = _.cloneDeep(erc20BalancesByOwner[takerAddress][defaultERC20MakerAssetAddress]); // Match signedOrderLeft with signedOrderRight - let newERC20BalancesByOwner: ERC20BalancesByOwner; - let newERC721TokenIdsByOwner: ERC721TokenIdsByOwner; - // prettier-ignore - [ - newERC20BalancesByOwner, - // tslint:disable-next-line:trailing-comma - newERC721TokenIdsByOwner - ] = await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Right Maker + amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Taker + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + }; + // Match signedOrderLeft with signedOrderRight + await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, signedOrderRight, takerAddress, erc20BalancesByOwner, erc721TokenIdsByOwner, - ); - // Verify left order was fully filled - const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft); - expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); - // Verify right order was fully filled - const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight); - expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); - // Verify taker did not take a profit - expect(takerInitialBalances).to.be.deep.equal( - newERC20BalancesByOwner[takerAddress][defaultERC20MakerAssetAddress], + expectedTransferAmounts, ); }); @@ -397,20 +370,30 @@ describe.only('matchOrders', () => { makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18), }); - // Match orders + // Match signedOrderLeft with signedOrderRight + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Right Maker + amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 16), // 50% + // Taker + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 40% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 16), // 100% + }; + // Match signedOrderLeft with signedOrderRight await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, signedOrderRight, takerAddress, erc20BalancesByOwner, erc721TokenIdsByOwner, + expectedTransferAmounts, ); - // Verify left order was fully filled - const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft); - expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); - // Verify right order was partially filled - const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight); - expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FILLABLE); }); it('should transfer the correct amounts when right order is completely filled and left order is partially filled', async () => { @@ -423,20 +406,30 @@ describe.only('matchOrders', () => { makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), }); - // Match orders + // Match signedOrderLeft with signedOrderRight + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 10% + // Right Maker + amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Taker + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 100% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 50% + }; + // Match signedOrderLeft with signedOrderRight await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, signedOrderRight, takerAddress, erc20BalancesByOwner, erc721TokenIdsByOwner, + expectedTransferAmounts, ); - // Verify left order was partially filled - const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft); - expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FILLABLE); - // Verify right order was fully filled - const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight); - expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); }); it('should transfer the correct amounts when consecutive calls are used to completely fill the left order', async () => { @@ -452,6 +445,20 @@ describe.only('matchOrders', () => { // Match orders let newERC20BalancesByOwner: ERC20BalancesByOwner; let newERC721TokenIdsByOwner: ERC721TokenIdsByOwner; + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 10% + // Right Maker + amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Taker + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 100% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 50% + }; // prettier-ignore [ newERC20BalancesByOwner, @@ -463,13 +470,8 @@ describe.only('matchOrders', () => { takerAddress, erc20BalancesByOwner, erc721TokenIdsByOwner, + expectedTransferAmounts ); - // Verify left order was partially filled - const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft); - expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FILLABLE); - // Verify right order was fully filled - const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight); - expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); // Construct second right order // Note: This order needs makerAssetAmount=90/takerAssetAmount=[anything <= 45] to fully fill the right order. // However, we use 100/50 to ensure a partial fill as we want to go down the "left fill" @@ -478,24 +480,34 @@ describe.only('matchOrders', () => { makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18), }); + // Match signedOrderLeft with signedOrderRight2 const leftTakerAssetFilledAmount = signedOrderRight.makerAssetAmount; const rightTakerAssetFilledAmount = new BigNumber(0); + const expectedTransferAmounts2 = { + // Left Maker + amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(45), 18), + amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 18), + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90% (10% paid earlier) + // Right Maker + amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 18), + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(45), 18), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90% + // Taker + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90% (10% paid earlier) + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90% + }; await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, signedOrderRight2, takerAddress, newERC20BalancesByOwner, - erc721TokenIdsByOwner, + newERC721TokenIdsByOwner, + expectedTransferAmounts2, leftTakerAssetFilledAmount, rightTakerAssetFilledAmount, ); - // Verify left order was fully filled - const leftOrderInfo2: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft); - expect(leftOrderInfo2.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); - // Verify second right order was partially filled - const rightOrderInfo2: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight2); - expect(rightOrderInfo2.orderStatus as OrderStatus).to.be.equal(OrderStatus.FILLABLE); }); it('should transfer the correct amounts when consecutive calls are used to completely fill the right order', async () => { @@ -512,6 +524,20 @@ describe.only('matchOrders', () => { // Match orders let newERC20BalancesByOwner: ERC20BalancesByOwner; let newERC721TokenIdsByOwner: ERC721TokenIdsByOwner; + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Right Maker + amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 16), // 4% + // Taker + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(6), 18), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 16), // 4% + }; // prettier-ignore [ newERC20BalancesByOwner, @@ -523,13 +549,9 @@ describe.only('matchOrders', () => { takerAddress, erc20BalancesByOwner, erc721TokenIdsByOwner, + expectedTransferAmounts ); - // Verify left order was partially filled - const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft); - expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); - // Verify right order was fully filled - const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight); - expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FILLABLE); + // Create second left order // Note: This order needs makerAssetAmount=96/takerAssetAmount=48 to fully fill the right order. // However, we use 100/50 to ensure a partial fill as we want to go down the "right fill" @@ -544,23 +566,58 @@ describe.only('matchOrders', () => { erc20BalancesByOwner[takerAddress][defaultERC20MakerAssetAddress], ); const rightTakerAssetFilledAmount = signedOrderLeft.makerAssetAmount.minus(takerAmountReceived); + const expectedTransferAmounts2 = { + // Left Maker + amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 18), + amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(48), 18), + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96% + // Right Maker + amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(48), 18), + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 18), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96% + // Taker + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96% + }; await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft2, signedOrderRight, takerAddress, newERC20BalancesByOwner, - erc721TokenIdsByOwner, + newERC721TokenIdsByOwner, + expectedTransferAmounts2, leftTakerAssetFilledAmount, rightTakerAssetFilledAmount, ); - // Verify second left order was partially filled - const leftOrderInfo2: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft2); - expect(leftOrderInfo2.orderStatus as OrderStatus).to.be.equal(OrderStatus.FILLABLE); - // Verify right order was fully filled - const rightOrderInfo2: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight); - expect(rightOrderInfo2.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); }); + /* + // Match signedOrderLeft with signedOrderRight + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(), 18), + amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(), 18), + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(), 16), // 10% + // Right Maker + amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(), 18), + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(), 18), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(), 16), // 100% + // Taker + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(), 18), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(), 16), // 100% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(), 16), // 50% + }; + await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + signedOrderLeft, + signedOrderRight, + takerAddress, + erc20BalancesByOwner, + erc721TokenIdsByOwner, + expectedTransferAmounts + ); + + */ it('should transfer the correct amounts if fee recipient is the same across both matched orders', async () => { const feeRecipientAddress = feeRecipientAddressLeft; const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ @@ -574,12 +631,27 @@ describe.only('matchOrders', () => { feeRecipientAddress, }); // Match orders + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Right Maker + amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Taker + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + }; await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, signedOrderRight, takerAddress, erc20BalancesByOwner, erc721TokenIdsByOwner, + expectedTransferAmounts, ); }); @@ -595,12 +667,27 @@ describe.only('matchOrders', () => { }); // Match orders takerAddress = signedOrderLeft.makerAddress; + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Right Maker + amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Taker + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + }; await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, signedOrderRight, takerAddress, erc20BalancesByOwner, erc721TokenIdsByOwner, + expectedTransferAmounts, ); }); @@ -616,12 +703,27 @@ describe.only('matchOrders', () => { }); // Match orders takerAddress = signedOrderRight.makerAddress; + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Right Maker + amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Taker + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + }; await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, signedOrderRight, takerAddress, erc20BalancesByOwner, erc721TokenIdsByOwner, + expectedTransferAmounts, ); }); @@ -637,12 +739,27 @@ describe.only('matchOrders', () => { }); // Match orders takerAddress = feeRecipientAddressLeft; + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Right Maker + amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Taker + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + }; await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, signedOrderRight, takerAddress, erc20BalancesByOwner, erc721TokenIdsByOwner, + expectedTransferAmounts, ); }); @@ -658,12 +775,27 @@ describe.only('matchOrders', () => { }); // Match orders takerAddress = feeRecipientAddressRight; + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Right Maker + amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Taker + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + }; await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, signedOrderRight, takerAddress, erc20BalancesByOwner, erc721TokenIdsByOwner, + expectedTransferAmounts, ); }); @@ -678,12 +810,27 @@ describe.only('matchOrders', () => { takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), }); // Match orders + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18), + amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Right Maker + amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Taker + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + }; await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, signedOrderRight, takerAddress, erc20BalancesByOwner, erc721TokenIdsByOwner, + expectedTransferAmounts, ); }); @@ -796,22 +943,31 @@ describe.only('matchOrders', () => { takerAssetAmount: new BigNumber(1), }); // Match orders + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0), + amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Right Maker + amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Taker + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 50% + }; await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, signedOrderRight, takerAddress, erc20BalancesByOwner, erc721TokenIdsByOwner, + expectedTransferAmounts, ); - // Verify left order was fully filled - const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft); - expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); - // Verify right order was fully filled - const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight); - expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); }); - it('should transfer correct amounts when right order maker asset is an ERC721 token', async () => { + it.only('should transfer correct amounts when right order maker asset is an ERC721 token', async () => { // Create orders to match const erc721TokenToTransfer = erc721RightMakerAssetIds[0]; const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ @@ -822,22 +978,31 @@ describe.only('matchOrders', () => { const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ makerAssetData: assetDataUtils.encodeERC721AssetData(defaultERC721AssetAddress, erc721TokenToTransfer), makerAssetAmount: new BigNumber(1), - takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(8), 18), }); // Match orders + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18), + amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0), + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Right Maker + amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0), + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(8), 18), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Taker + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 50% + }; await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, signedOrderRight, takerAddress, erc20BalancesByOwner, erc721TokenIdsByOwner, + expectedTransferAmounts, ); - // Verify left order was fully filled - const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft); - expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); - // Verify right order was fully filled - const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight); - expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); - });*/ + }); }); }); // tslint:disable-line:max-file-line-count diff --git a/packages/contracts/test/utils/match_order_tester.ts b/packages/contracts/test/utils/match_order_tester.ts index c412595f50..00816e7d46 100644 --- a/packages/contracts/test/utils/match_order_tester.ts +++ b/packages/contracts/test/utils/match_order_tester.ts @@ -202,8 +202,6 @@ export class MatchOrderTester { erc20BalancesByOwner: ERC20BalancesByOwner, erc721TokenIdsByOwner: ERC721TokenIdsByOwner, expectedTransferAmounts: TransferAmounts, - leftOrderEndState: OrderStatus, - rightOrderEndState: OrderStatus, initialTakerAssetFilledAmountLeft?: BigNumber, initialTakerAssetFilledAmountRight?: BigNumber, ): Promise<[ERC20BalancesByOwner, ERC721TokenIdsByOwner]> { @@ -234,7 +232,9 @@ export class MatchOrderTester { signedOrderRight, orderTakerAssetFilledAmountLeft, orderTakerAssetFilledAmountRight, - expectedTransferAmounts + expectedTransferAmounts, + initialTakerAssetFilledAmountLeft, + initialTakerAssetFilledAmountRight ); // Verify balances of makers, taker, and fee recipients await this._verifyBalancesAsync( @@ -308,7 +308,9 @@ export class MatchOrderTester { signedOrderRight: SignedOrder, orderTakerAssetFilledAmountLeft: BigNumber, orderTakerAssetFilledAmountRight: BigNumber, - expectedTransferAmounts: TransferAmounts + expectedTransferAmounts: TransferAmounts, + initialTakerAssetFilledAmountLeft?: BigNumber, + initialTakerAssetFilledAmountRight?: BigNumber ) { // Verify state for left order: amount bought by left maker let amountBoughtByLeftMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( @@ -323,12 +325,18 @@ export class MatchOrderTester { amountBoughtByRightMaker = amountBoughtByRightMaker.minus(orderTakerAssetFilledAmountRight); expect(expectedTransferAmounts.amountBoughtByRightMaker, "Checking exchange state for right order").to.be.bignumber.equal(amountBoughtByRightMaker); // Verify left order status + const maxAmountBoughtByLeftMaker = initialTakerAssetFilledAmountLeft + ? signedOrderLeft.takerAssetAmount.sub(initialTakerAssetFilledAmountLeft) + : signedOrderLeft.takerAssetAmount; const leftOrderInfo: OrderInfo = await this._exchangeWrapper.getOrderInfoAsync(signedOrderLeft); - const leftExpectedStatus = (expectedTransferAmounts.amountBoughtByLeftMaker.equals(signedOrderLeft.takerAssetAmount)) ? OrderStatus.FULLY_FILLED : OrderStatus.FILLABLE; + const leftExpectedStatus = (expectedTransferAmounts.amountBoughtByLeftMaker.equals(maxAmountBoughtByLeftMaker)) ? OrderStatus.FULLY_FILLED : OrderStatus.FILLABLE; expect(leftOrderInfo.orderStatus as OrderStatus, "Checking exchange status for left order").to.be.equal(leftExpectedStatus); // Verify right order status + const maxAmountBoughtByRightMaker = initialTakerAssetFilledAmountRight + ? signedOrderRight.takerAssetAmount.sub(initialTakerAssetFilledAmountRight) + : signedOrderRight.takerAssetAmount; const rightOrderInfo: OrderInfo = await this._exchangeWrapper.getOrderInfoAsync(signedOrderRight); - const rightExpectedStatus = (expectedTransferAmounts.amountBoughtByRightMaker.equals(signedOrderRight.takerAssetAmount)) ? OrderStatus.FULLY_FILLED : OrderStatus.FILLABLE; + const rightExpectedStatus = (expectedTransferAmounts.amountBoughtByRightMaker.equals(maxAmountBoughtByRightMaker)) ? OrderStatus.FULLY_FILLED : OrderStatus.FILLABLE; expect(rightOrderInfo.orderStatus as OrderStatus, "Checking exchange status for right order").to.be.equal(rightExpectedStatus); } /// @dev Calculates the expected balances of order makers, fee recipients, and the taker, From 70863cca085c060d55932e5e173fc2023bda9df5 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 23 Aug 2018 10:31:06 -0700 Subject: [PATCH 078/120] Ran prettier and linter --- .../contracts/test/exchange/match_orders.ts | 44 +- .../test/utils/match_order_tester.ts | 487 +++++++++++------- packages/contracts/test/utils/types.ts | 10 +- 3 files changed, 317 insertions(+), 224 deletions(-) diff --git a/packages/contracts/test/exchange/match_orders.ts b/packages/contracts/test/exchange/match_orders.ts index eb2644ba68..7e9776d52f 100644 --- a/packages/contracts/test/exchange/match_orders.ts +++ b/packages/contracts/test/exchange/match_orders.ts @@ -3,7 +3,6 @@ import { assetDataUtils } from '@0xproject/order-utils'; import { RevertReason } from '@0xproject/types'; import { BigNumber } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; -import * as chai from 'chai'; import * as _ from 'lodash'; import { DummyERC20TokenContract } from '../../generated_contract_wrappers/dummy_erc20_token'; @@ -14,25 +13,15 @@ import { ExchangeContract } from '../../generated_contract_wrappers/exchange'; import { ReentrantERC20TokenContract } from '../../generated_contract_wrappers/reentrant_erc20_token'; import { artifacts } from '../utils/artifacts'; import { expectTransactionFailedAsync } from '../utils/assertions'; -import { chaiSetup } from '../utils/chai_setup'; import { constants } from '../utils/constants'; import { ERC20Wrapper } from '../utils/erc20_wrapper'; import { ERC721Wrapper } from '../utils/erc721_wrapper'; import { ExchangeWrapper } from '../utils/exchange_wrapper'; import { MatchOrderTester } from '../utils/match_order_tester'; import { OrderFactory } from '../utils/order_factory'; -import { - ERC20BalancesByOwner, - ERC721TokenIdsByOwner, - OrderInfo, - TransferAmountsByMatchOrders as TransferAmounts, - OrderStatus, -} from '../utils/types'; +import { ERC20BalancesByOwner, ERC721TokenIdsByOwner } from '../utils/types'; import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; -chaiSetup.configure(); - -const expect = chai.expect; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); describe.only('matchOrders', () => { @@ -470,7 +459,7 @@ describe.only('matchOrders', () => { takerAddress, erc20BalancesByOwner, erc721TokenIdsByOwner, - expectedTransferAmounts + expectedTransferAmounts, ); // Construct second right order // Note: This order needs makerAssetAmount=90/takerAssetAmount=[anything <= 45] to fully fill the right order. @@ -480,7 +469,6 @@ describe.only('matchOrders', () => { makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18), takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 18), }); - // Match signedOrderLeft with signedOrderRight2 const leftTakerAssetFilledAmount = signedOrderRight.makerAssetAmount; const rightTakerAssetFilledAmount = new BigNumber(0); @@ -549,7 +537,7 @@ describe.only('matchOrders', () => { takerAddress, erc20BalancesByOwner, erc721TokenIdsByOwner, - expectedTransferAmounts + expectedTransferAmounts, ); // Create second left order @@ -592,32 +580,6 @@ describe.only('matchOrders', () => { ); }); - /* - // Match signedOrderLeft with signedOrderRight - const expectedTransferAmounts = { - // Left Maker - amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(), 18), - amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(), 18), - feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(), 16), // 10% - // Right Maker - amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(), 18), - amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(), 18), - feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(), 16), // 100% - // Taker - amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(), 18), - feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(), 16), // 100% - feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(), 16), // 50% - }; - await matchOrderTester.matchOrdersAndVerifyBalancesAsync( - signedOrderLeft, - signedOrderRight, - takerAddress, - erc20BalancesByOwner, - erc721TokenIdsByOwner, - expectedTransferAmounts - ); - - */ it('should transfer the correct amounts if fee recipient is the same across both matched orders', async () => { const feeRecipientAddress = feeRecipientAddressLeft; const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ diff --git a/packages/contracts/test/utils/match_order_tester.ts b/packages/contracts/test/utils/match_order_tester.ts index 00816e7d46..300073eb04 100644 --- a/packages/contracts/test/utils/match_order_tester.ts +++ b/packages/contracts/test/utils/match_order_tester.ts @@ -4,12 +4,19 @@ import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import * as _ from 'lodash'; +import { TransactionReceiptWithDecodedLogs } from '../../../../node_modules/ethereum-types'; + import { chaiSetup } from './chai_setup'; import { ERC20Wrapper } from './erc20_wrapper'; import { ERC721Wrapper } from './erc721_wrapper'; import { ExchangeWrapper } from './exchange_wrapper'; -import { ERC20BalancesByOwner, ERC721TokenIdsByOwner, TransferAmountsByMatchOrders as TransferAmounts, OrderInfo, OrderStatus} from './types'; -import { TransactionReceiptWithDecodedLogs } from '../../../../node_modules/ethereum-types'; +import { + ERC20BalancesByOwner, + ERC721TokenIdsByOwner, + OrderInfo, + OrderStatus, + TransferAmountsByMatchOrders as TransferAmounts, +} from './types'; chaiSetup.configure(); const expect = chai.expect; @@ -19,110 +26,117 @@ export class MatchOrderTester { private readonly _erc20Wrapper: ERC20Wrapper; private readonly _erc721Wrapper: ERC721Wrapper; private readonly _feeTokenAddress: string; - - private async _verifyBalancesAsync( + /// @dev Calculates expected transfer amounts between order makers, fee recipients, and + /// the taker when two orders are matched. + /// @param signedOrderLeft First matched order. + /// @param signedOrderRight Second matched order. + /// @param orderTakerAssetFilledAmountLeft How much left order has been filled, prior to matching orders. + /// @param orderTakerAssetFilledAmountRight How much the right order has been filled, prior to matching orders. + /// @return TransferAmounts A struct containing the expected transfer amounts. + private static async _verifyLogsAsync( signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder, - initialERC20BalancesByOwner: ERC20BalancesByOwner, - initialERC721TokenIdsByOwner: ERC721TokenIdsByOwner, - finalERC20BalancesByOwner: ERC20BalancesByOwner, - finalERC721TokenIdsByOwner: ERC721TokenIdsByOwner, + transactionReceipt: TransactionReceiptWithDecodedLogs, + takerAddress: string, expectedTransferAmounts: TransferAmounts, - takerAddress: string - ) - { - let expectedERC20BalancesByOwner: ERC20BalancesByOwner; - let expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner; - [expectedERC20BalancesByOwner, expectedERC721TokenIdsByOwner] = this._calculateExpectedBalances( - signedOrderLeft, - signedOrderRight, - takerAddress, - initialERC20BalancesByOwner, - initialERC721TokenIdsByOwner, - expectedTransferAmounts, + ): Promise { + // Parse logs + expect(transactionReceipt.logs.length, 'Checking number of logs').to.be.equal(2); + // First log is for left fill + const leftLog = (transactionReceipt.logs[0] as any) as { + args: { + makerAddress: string; + takerAddress: string; + makerAssetFilledAmount: string; + takerAssetFilledAmount: string; + makerFeePaid: string; + takerFeePaid: string; + }; + }; + expect(leftLog.args.makerAddress, 'Checking logged maker address of left order').to.be.equal( + signedOrderLeft.makerAddress, ); - // Verify balances of makers, taker, and fee recipients - await this._verifyMakerTakerAndFeeRecipientBalancesAsync( - signedOrderLeft, - signedOrderRight, - expectedERC20BalancesByOwner, - finalERC20BalancesByOwner, - expectedERC721TokenIdsByOwner, - finalERC721TokenIdsByOwner, - takerAddress - ); - // Verify balances for all known accounts - await this._verifyAllKnownBalancesAsync( - expectedERC20BalancesByOwner, - finalERC20BalancesByOwner, - expectedERC721TokenIdsByOwner, - finalERC721TokenIdsByOwner, + expect(leftLog.args.takerAddress, 'Checking logged taker address of right order').to.be.equal(takerAddress); + const amountBoughtByLeftMaker = new BigNumber(leftLog.args.takerAssetFilledAmount); + const amountSoldByLeftMaker = new BigNumber(leftLog.args.makerAssetFilledAmount); + const feePaidByLeftMaker = new BigNumber(leftLog.args.makerFeePaid); + const feePaidByTakerLeft = new BigNumber(leftLog.args.takerFeePaid); + // Second log is for right fill + const rightLog = (transactionReceipt.logs[1] as any) as { + args: { + makerAddress: string; + takerAddress: string; + makerAssetFilledAmount: string; + takerAssetFilledAmount: string; + makerFeePaid: string; + takerFeePaid: string; + }; + }; + expect(rightLog.args.makerAddress, 'Checking logged maker address of right order').to.be.equal( + signedOrderRight.makerAddress, ); + expect(rightLog.args.takerAddress, 'Checking loggerd taker address of right order').to.be.equal(takerAddress); + const amountBoughtByRightMaker = new BigNumber(rightLog.args.takerAssetFilledAmount); + const amountSoldByRightMaker = new BigNumber(rightLog.args.makerAssetFilledAmount); + const feePaidByRightMaker = new BigNumber(rightLog.args.makerFeePaid); + const feePaidByTakerRight = new BigNumber(rightLog.args.takerFeePaid); + // Derive amount received by taker + const amountReceivedByTaker = amountSoldByLeftMaker.sub(amountBoughtByRightMaker); + // Verify log values - left order + expect( + expectedTransferAmounts.amountBoughtByLeftMaker, + 'Checking logged amount bought by left maker', + ).to.be.bignumber.equal(amountBoughtByLeftMaker); + expect( + expectedTransferAmounts.amountSoldByLeftMaker, + 'Checking logged amount sold by left maker', + ).to.be.bignumber.equal(amountSoldByLeftMaker); + expect( + expectedTransferAmounts.feePaidByLeftMaker, + 'Checking logged fee paid by left maker', + ).to.be.bignumber.equal(feePaidByLeftMaker); + expect( + expectedTransferAmounts.feePaidByTakerLeft, + 'Checking logged fee paid on left order by taker', + ).to.be.bignumber.equal(feePaidByTakerLeft); + // Verify log values - right order + expect( + expectedTransferAmounts.amountBoughtByRightMaker, + 'Checking logged amount bought by right maker', + ).to.be.bignumber.equal(amountBoughtByRightMaker); + expect( + expectedTransferAmounts.amountSoldByRightMaker, + 'Checking logged amount sold by right maker', + ).to.be.bignumber.equal(amountSoldByRightMaker); + expect( + expectedTransferAmounts.feePaidByRightMaker, + 'Checking logged fee paid by right maker', + ).to.be.bignumber.equal(feePaidByRightMaker); + expect( + expectedTransferAmounts.feePaidByTakerRight, + 'Checking logged fee paid on right order by taker', + ).to.be.bignumber.equal(feePaidByTakerRight); + // Verify derived amount received by taker + expect( + expectedTransferAmounts.amountReceivedByTaker, + 'Checking logged amount received by taker', + ).to.be.bignumber.equal(amountReceivedByTaker); } - - private async _verifyMakerTakerAndFeeRecipientBalancesAsync( - signedOrderLeft: SignedOrder, - signedOrderRight: SignedOrder, - expectedERC20BalancesByOwner: ERC20BalancesByOwner, - realERC20BalancesByOwner: ERC20BalancesByOwner, - expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner, - realERC721TokenIdsByOwner: ERC721TokenIdsByOwner, - takerAddress: string - ) { - // Individual balance comparisons - const makerAssetProxyIdLeft = assetDataUtils.decodeAssetProxyId(signedOrderLeft.makerAssetData); - const makerERC20AssetDataLeft = makerAssetProxyIdLeft == AssetProxyId.ERC20 ? assetDataUtils.decodeERC20AssetData(signedOrderLeft.makerAssetData) : assetDataUtils.decodeERC721AssetData(signedOrderLeft.makerAssetData); - const makerAssetAddressLeft = makerERC20AssetDataLeft.tokenAddress; - const makerAssetProxyIdRight = assetDataUtils.decodeAssetProxyId(signedOrderRight.makerAssetData); - const makerERC20AssetDataRight = makerAssetProxyIdRight == AssetProxyId.ERC20 ? assetDataUtils.decodeERC20AssetData(signedOrderRight.makerAssetData) : assetDataUtils.decodeERC721AssetData(signedOrderRight.makerAssetData); - const makerAssetAddressRight = makerERC20AssetDataRight.tokenAddress; - // describe('asdad', () => { - if(makerAssetProxyIdLeft == AssetProxyId.ERC20) { - expect(realERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft], "Checking left maker egress ERC20 account balance").to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft]); - expect(realERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft], "Checking right maker ingress ERC20 account balance").to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft]); - expect(realERC20BalancesByOwner[takerAddress][makerAssetAddressLeft], "Checking taker ingress ERC20 account balance").to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][makerAssetAddressLeft]); - } else if(makerAssetProxyIdLeft == AssetProxyId.ERC721) { - expect(realERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort(), "Checking left maker egress ERC721 account holdings").to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort()); - expect(realERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort(), "Checking right maker ERC721 account holdings").to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort()); - expect(realERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort(), "Checking taker ingress ERC721 account holdings").to.be.deep.equal(expectedERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort()); - } else { - throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdLeft}`); - } - if(makerAssetProxyIdRight == AssetProxyId.ERC20) { - expect(realERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight], "Checking left maker ingress ERC20 account balance").to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight]); - expect(realERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight], "Checking right maker egress ERC20 account balance").to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]); - } else if(makerAssetProxyIdRight == AssetProxyId.ERC721) { - expect(realERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort(), "Checking left maker ingress ERC721 account holdings").to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort()); - expect(realERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight], "Checking right maker agress ERC721 account holdings").to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]); - } else { - throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdRight}`); - } - // Paid fees - expect(realERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress], "Checking left maker egress ERC20 account fees").to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress]); - expect(realERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress], "Checking right maker egress ERC20 account fees").to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress]); - expect(realERC20BalancesByOwner[takerAddress][this._feeTokenAddress], "Checking taker egress ERC20 account fees").to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][this._feeTokenAddress]); - // Received fees - expect(realERC20BalancesByOwner[signedOrderLeft.feeRecipientAddress][this._feeTokenAddress], "Checking left fee recipient ingress ERC20 account fees").to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.feeRecipientAddress][this._feeTokenAddress]); - expect(realERC20BalancesByOwner[signedOrderRight.feeRecipientAddress][this._feeTokenAddress], "Checking right fee receipient ingress ERC20 account fees").to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.feeRecipientAddress][this._feeTokenAddress]); - } - /// @dev Compares a pair of ERC20 balances and a pair of ERC721 token owners. /// @param expectedNewERC20BalancesByOwner Expected ERC20 balances. /// @param realERC20BalancesByOwner Actual ERC20 balances. /// @param expectedNewERC721TokenIdsByOwner Expected ERC721 token owners. /// @param realERC721TokenIdsByOwner Actual ERC20 token owners. /// @return True only if ERC20 balances match and ERC721 token owners match. - private async _verifyAllKnownBalancesAsync( + private static async _verifyAllKnownBalancesAsync( expectedNewERC20BalancesByOwner: ERC20BalancesByOwner, realERC20BalancesByOwner: ERC20BalancesByOwner, expectedNewERC721TokenIdsByOwner: ERC721TokenIdsByOwner, realERC721TokenIdsByOwner: ERC721TokenIdsByOwner, - ) { - + ): Promise { // ERC20 Balances - const erc20BalancesMatch = _.isEqual(expectedNewERC20BalancesByOwner, realERC20BalancesByOwner); - expect(erc20BalancesMatch, "Checking all known ERC20 account balances").to.be.true(); - + const areERC20BalancesEqual = _.isEqual(expectedNewERC20BalancesByOwner, realERC20BalancesByOwner); + expect(areERC20BalancesEqual, 'Checking all known ERC20 account balances').to.be.true(); // ERC721 Token Ids const sortedExpectedNewERC721TokenIdsByOwner = _.mapValues( expectedNewERC721TokenIdsByOwner, @@ -137,38 +151,12 @@ export class MatchOrderTester { _.sortBy(tokenIds); }); }); - const erc721TokenIdsMatch = _.isEqual( + const areERC721TokenIdsEqual = _.isEqual( sortedExpectedNewERC721TokenIdsByOwner, sortedNewERC721TokenIdsByOwner, ); - expect(erc721TokenIdsMatch, "Checking all known ERC721 account balances").to.be.true(); + expect(areERC721TokenIdsEqual, 'Checking all known ERC721 account balances').to.be.true(); } - - private async _verifyInitialOrderStates( - signedOrderLeft: SignedOrder, - signedOrderRight: SignedOrder, - initialTakerAssetFilledAmountLeft?: BigNumber, - initialTakerAssetFilledAmountRight?: BigNumber, - ): Promise<[BigNumber, BigNumber]> { - // Verify Left order preconditions - const orderTakerAssetFilledAmountLeft = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( - orderHashUtils.getOrderHashHex(signedOrderLeft), - ); - const expectedOrderFilledAmountLeft = initialTakerAssetFilledAmountLeft - ? initialTakerAssetFilledAmountLeft - : new BigNumber(0); - expect(expectedOrderFilledAmountLeft).to.be.bignumber.equal(orderTakerAssetFilledAmountLeft); - // Verify Right order preconditions - const orderTakerAssetFilledAmountRight = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( - orderHashUtils.getOrderHashHex(signedOrderRight), - ); - const expectedOrderFilledAmountRight = initialTakerAssetFilledAmountRight - ? initialTakerAssetFilledAmountRight - : new BigNumber(0); - expect(expectedOrderFilledAmountRight).to.be.bignumber.equal(orderTakerAssetFilledAmountRight); - return [orderTakerAssetFilledAmountLeft, orderTakerAssetFilledAmountRight]; - } - /// @dev Constructs new MatchOrderTester. /// @param exchangeWrapper Used to call to the Exchange. /// @param erc20Wrapper Used to fetch ERC20 balances. @@ -208,23 +196,27 @@ export class MatchOrderTester { // Verify initial order states let orderTakerAssetFilledAmountLeft: BigNumber; let orderTakerAssetFilledAmountRight: BigNumber; - [orderTakerAssetFilledAmountLeft, orderTakerAssetFilledAmountRight] = await this._verifyInitialOrderStates( + [orderTakerAssetFilledAmountLeft, orderTakerAssetFilledAmountRight] = await this._verifyInitialOrderStatesAsync( signedOrderLeft, signedOrderRight, initialTakerAssetFilledAmountLeft, - initialTakerAssetFilledAmountRight + initialTakerAssetFilledAmountRight, ); // Match left & right orders - const transactionReceipt = await this._exchangeWrapper.matchOrdersAsync(signedOrderLeft, signedOrderRight, takerAddress); + const transactionReceipt = await this._exchangeWrapper.matchOrdersAsync( + signedOrderLeft, + signedOrderRight, + takerAddress, + ); const newERC20BalancesByOwner = await this._erc20Wrapper.getBalancesAsync(); const newERC721TokenIdsByOwner = await this._erc721Wrapper.getBalancesAsync(); // Verify logs - await this._verifyLogsAsync( + await MatchOrderTester._verifyLogsAsync( signedOrderLeft, signedOrderRight, transactionReceipt, takerAddress, - expectedTransferAmounts + expectedTransferAmounts, ); // Verify exchange state await this._verifyExchangeStateAsync( @@ -234,7 +226,7 @@ export class MatchOrderTester { orderTakerAssetFilledAmountRight, expectedTransferAmounts, initialTakerAssetFilledAmountLeft, - initialTakerAssetFilledAmountRight + initialTakerAssetFilledAmountRight, ); // Verify balances of makers, taker, and fee recipients await this._verifyBalancesAsync( @@ -245,57 +237,35 @@ export class MatchOrderTester { newERC20BalancesByOwner, newERC721TokenIdsByOwner, expectedTransferAmounts, - takerAddress + takerAddress, ); return [newERC20BalancesByOwner, newERC721TokenIdsByOwner]; } - /// @dev Calculates expected transfer amounts between order makers, fee recipients, and - /// the taker when two orders are matched. - /// @param signedOrderLeft First matched order. - /// @param signedOrderRight Second matched order. - /// @param orderTakerAssetFilledAmountLeft How much left order has been filled, prior to matching orders. - /// @param orderTakerAssetFilledAmountRight How much the right order has been filled, prior to matching orders. - /// @return TransferAmounts A struct containing the expected transfer amounts. - private async _verifyLogsAsync( + private async _verifyInitialOrderStatesAsync( signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder, - transactionReceipt: TransactionReceiptWithDecodedLogs, - takerAddress: string, - expectedTransferAmounts: TransferAmounts - ) { - // Parse logs - expect(transactionReceipt.logs.length, "Checking number of logs").to.be.equal(2); - // First log is for left fill - const leftLog = ((transactionReceipt.logs[0] as any) as {args: { makerAddress: string, takerAddress: string, makerAssetFilledAmount: string, takerAssetFilledAmount: string, makerFeePaid: string, takerFeePaid: string}}); - expect(leftLog.args.makerAddress, "Checking logged maker address of left order").to.be.equal(signedOrderLeft.makerAddress); - expect(leftLog.args.takerAddress, "Checking logged taker address of right order").to.be.equal(takerAddress); - const amountBoughtByLeftMaker = new BigNumber(leftLog.args.takerAssetFilledAmount); - const amountSoldByLeftMaker = new BigNumber(leftLog.args.makerAssetFilledAmount); - const feePaidByLeftMaker = new BigNumber(leftLog.args.makerFeePaid); - const feePaidByTakerLeft = new BigNumber(leftLog.args.takerFeePaid); - // Second log is for right fill - const rightLog = ((transactionReceipt.logs[1] as any) as {args: { makerAddress: string, takerAddress: string, makerAssetFilledAmount: string, takerAssetFilledAmount: string, makerFeePaid: string, takerFeePaid: string}}); - expect(rightLog.args.makerAddress, "Checking logged maker address of right order").to.be.equal(signedOrderRight.makerAddress); - expect(rightLog.args.takerAddress, "Checking loggerd taker address of right order").to.be.equal(takerAddress); - const amountBoughtByRightMaker = new BigNumber(rightLog.args.takerAssetFilledAmount); - const amountSoldByRightMaker = new BigNumber(rightLog.args.makerAssetFilledAmount); - const feePaidByRightMaker = new BigNumber(rightLog.args.makerFeePaid); - const feePaidByTakerRight = new BigNumber(rightLog.args.takerFeePaid); - // Derive amount received by taker - const amountReceivedByTaker = amountSoldByLeftMaker.sub(amountBoughtByRightMaker); - // Verify log values - left order - expect(expectedTransferAmounts.amountBoughtByLeftMaker, "Checking logged amount bought by left maker").to.be.bignumber.equal(amountBoughtByLeftMaker); - expect(expectedTransferAmounts.amountSoldByLeftMaker, "Checking logged amount sold by left maker").to.be.bignumber.equal(amountSoldByLeftMaker); - expect(expectedTransferAmounts.feePaidByLeftMaker, "Checking logged fee paid by left maker").to.be.bignumber.equal(feePaidByLeftMaker); - expect(expectedTransferAmounts.feePaidByTakerLeft, "Checking logged fee paid on left order by taker").to.be.bignumber.equal(feePaidByTakerLeft); - // Verify log values - right order - expect(expectedTransferAmounts.amountBoughtByRightMaker, "Checking logged amount bought by right maker").to.be.bignumber.equal(amountBoughtByRightMaker); - expect(expectedTransferAmounts.amountSoldByRightMaker, "Checking logged amount sold by right maker").to.be.bignumber.equal(amountSoldByRightMaker); - expect(expectedTransferAmounts.feePaidByRightMaker, "Checking logged fee paid by right maker").to.be.bignumber.equal(feePaidByRightMaker); - expect(expectedTransferAmounts.feePaidByTakerRight, "Checking logged fee paid on right order by taker").to.be.bignumber.equal(feePaidByTakerRight); - // Verify derived amount received by taker - expect(expectedTransferAmounts.amountReceivedByTaker, "Checking logged amount received by taker").to.be.bignumber.equal(amountReceivedByTaker); + initialTakerAssetFilledAmountLeft?: BigNumber, + initialTakerAssetFilledAmountRight?: BigNumber, + ): Promise<[BigNumber, BigNumber]> { + // Verify Left order preconditions + const orderTakerAssetFilledAmountLeft = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( + orderHashUtils.getOrderHashHex(signedOrderLeft), + ); + const expectedOrderFilledAmountLeft = initialTakerAssetFilledAmountLeft + ? initialTakerAssetFilledAmountLeft + : new BigNumber(0); + expect(expectedOrderFilledAmountLeft).to.be.bignumber.equal(orderTakerAssetFilledAmountLeft); + // Verify Right order preconditions + const orderTakerAssetFilledAmountRight = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( + orderHashUtils.getOrderHashHex(signedOrderRight), + ); + const expectedOrderFilledAmountRight = initialTakerAssetFilledAmountRight + ? initialTakerAssetFilledAmountRight + : new BigNumber(0); + expect(expectedOrderFilledAmountRight).to.be.bignumber.equal(orderTakerAssetFilledAmountRight); + return [orderTakerAssetFilledAmountLeft, orderTakerAssetFilledAmountRight]; } + /// @dev Calculates expected transfer amounts between order makers, fee recipients, and /// the taker when two orders are matched. /// @param signedOrderLeft First matched order. @@ -310,34 +280,193 @@ export class MatchOrderTester { orderTakerAssetFilledAmountRight: BigNumber, expectedTransferAmounts: TransferAmounts, initialTakerAssetFilledAmountLeft?: BigNumber, - initialTakerAssetFilledAmountRight?: BigNumber - ) { + initialTakerAssetFilledAmountRight?: BigNumber, + ): Promise { // Verify state for left order: amount bought by left maker let amountBoughtByLeftMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( orderHashUtils.getOrderHashHex(signedOrderLeft), ); amountBoughtByLeftMaker = amountBoughtByLeftMaker.minus(orderTakerAssetFilledAmountLeft); - expect(expectedTransferAmounts.amountBoughtByLeftMaker, "Checking exchange state for left order").to.be.bignumber.equal(amountBoughtByLeftMaker); + expect( + expectedTransferAmounts.amountBoughtByLeftMaker, + 'Checking exchange state for left order', + ).to.be.bignumber.equal(amountBoughtByLeftMaker); // Verify state for right order: amount bought by right maker let amountBoughtByRightMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( orderHashUtils.getOrderHashHex(signedOrderRight), ); amountBoughtByRightMaker = amountBoughtByRightMaker.minus(orderTakerAssetFilledAmountRight); - expect(expectedTransferAmounts.amountBoughtByRightMaker, "Checking exchange state for right order").to.be.bignumber.equal(amountBoughtByRightMaker); + expect( + expectedTransferAmounts.amountBoughtByRightMaker, + 'Checking exchange state for right order', + ).to.be.bignumber.equal(amountBoughtByRightMaker); // Verify left order status const maxAmountBoughtByLeftMaker = initialTakerAssetFilledAmountLeft ? signedOrderLeft.takerAssetAmount.sub(initialTakerAssetFilledAmountLeft) : signedOrderLeft.takerAssetAmount; const leftOrderInfo: OrderInfo = await this._exchangeWrapper.getOrderInfoAsync(signedOrderLeft); - const leftExpectedStatus = (expectedTransferAmounts.amountBoughtByLeftMaker.equals(maxAmountBoughtByLeftMaker)) ? OrderStatus.FULLY_FILLED : OrderStatus.FILLABLE; - expect(leftOrderInfo.orderStatus as OrderStatus, "Checking exchange status for left order").to.be.equal(leftExpectedStatus); + const leftExpectedStatus = expectedTransferAmounts.amountBoughtByLeftMaker.equals(maxAmountBoughtByLeftMaker) + ? OrderStatus.FULLY_FILLED + : OrderStatus.FILLABLE; + expect(leftOrderInfo.orderStatus as OrderStatus, 'Checking exchange status for left order').to.be.equal( + leftExpectedStatus, + ); // Verify right order status const maxAmountBoughtByRightMaker = initialTakerAssetFilledAmountRight ? signedOrderRight.takerAssetAmount.sub(initialTakerAssetFilledAmountRight) : signedOrderRight.takerAssetAmount; const rightOrderInfo: OrderInfo = await this._exchangeWrapper.getOrderInfoAsync(signedOrderRight); - const rightExpectedStatus = (expectedTransferAmounts.amountBoughtByRightMaker.equals(maxAmountBoughtByRightMaker)) ? OrderStatus.FULLY_FILLED : OrderStatus.FILLABLE; - expect(rightOrderInfo.orderStatus as OrderStatus, "Checking exchange status for right order").to.be.equal(rightExpectedStatus); + const rightExpectedStatus = expectedTransferAmounts.amountBoughtByRightMaker.equals(maxAmountBoughtByRightMaker) + ? OrderStatus.FULLY_FILLED + : OrderStatus.FILLABLE; + expect(rightOrderInfo.orderStatus as OrderStatus, 'Checking exchange status for right order').to.be.equal( + rightExpectedStatus, + ); + } + private async _verifyBalancesAsync( + signedOrderLeft: SignedOrder, + signedOrderRight: SignedOrder, + initialERC20BalancesByOwner: ERC20BalancesByOwner, + initialERC721TokenIdsByOwner: ERC721TokenIdsByOwner, + finalERC20BalancesByOwner: ERC20BalancesByOwner, + finalERC721TokenIdsByOwner: ERC721TokenIdsByOwner, + expectedTransferAmounts: TransferAmounts, + takerAddress: string, + ): Promise { + let expectedERC20BalancesByOwner: ERC20BalancesByOwner; + let expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner; + [expectedERC20BalancesByOwner, expectedERC721TokenIdsByOwner] = this._calculateExpectedBalances( + signedOrderLeft, + signedOrderRight, + takerAddress, + initialERC20BalancesByOwner, + initialERC721TokenIdsByOwner, + expectedTransferAmounts, + ); + // Verify balances of makers, taker, and fee recipients + await this._verifyMakerTakerAndFeeRecipientBalancesAsync( + signedOrderLeft, + signedOrderRight, + expectedERC20BalancesByOwner, + finalERC20BalancesByOwner, + expectedERC721TokenIdsByOwner, + finalERC721TokenIdsByOwner, + takerAddress, + ); + // Verify balances for all known accounts + await MatchOrderTester._verifyAllKnownBalancesAsync( + expectedERC20BalancesByOwner, + finalERC20BalancesByOwner, + expectedERC721TokenIdsByOwner, + finalERC721TokenIdsByOwner, + ); + } + private async _verifyMakerTakerAndFeeRecipientBalancesAsync( + signedOrderLeft: SignedOrder, + signedOrderRight: SignedOrder, + expectedERC20BalancesByOwner: ERC20BalancesByOwner, + realERC20BalancesByOwner: ERC20BalancesByOwner, + expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner, + realERC721TokenIdsByOwner: ERC721TokenIdsByOwner, + takerAddress: string, + ): Promise { + // Individual balance comparisons + const makerAssetProxyIdLeft = assetDataUtils.decodeAssetProxyId(signedOrderLeft.makerAssetData); + const makerERC20AssetDataLeft = + makerAssetProxyIdLeft === AssetProxyId.ERC20 + ? assetDataUtils.decodeERC20AssetData(signedOrderLeft.makerAssetData) + : assetDataUtils.decodeERC721AssetData(signedOrderLeft.makerAssetData); + const makerAssetAddressLeft = makerERC20AssetDataLeft.tokenAddress; + const makerAssetProxyIdRight = assetDataUtils.decodeAssetProxyId(signedOrderRight.makerAssetData); + const makerERC20AssetDataRight = + makerAssetProxyIdRight === AssetProxyId.ERC20 + ? assetDataUtils.decodeERC20AssetData(signedOrderRight.makerAssetData) + : assetDataUtils.decodeERC721AssetData(signedOrderRight.makerAssetData); + const makerAssetAddressRight = makerERC20AssetDataRight.tokenAddress; + if (makerAssetProxyIdLeft === AssetProxyId.ERC20) { + expect( + realERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft], + 'Checking left maker egress ERC20 account balance', + ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft]); + expect( + realERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft], + 'Checking right maker ingress ERC20 account balance', + ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft]); + expect( + realERC20BalancesByOwner[takerAddress][makerAssetAddressLeft], + 'Checking taker ingress ERC20 account balance', + ).to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][makerAssetAddressLeft]); + } else if (makerAssetProxyIdLeft === AssetProxyId.ERC721) { + expect( + realERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort(), + 'Checking left maker egress ERC721 account holdings', + ).to.be.deep.equal( + expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort(), + ); + expect( + realERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort(), + 'Checking right maker ERC721 account holdings', + ).to.be.deep.equal( + expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort(), + ); + expect( + realERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort(), + 'Checking taker ingress ERC721 account holdings', + ).to.be.deep.equal(expectedERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort()); + } else { + throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdLeft}`); + } + if (makerAssetProxyIdRight === AssetProxyId.ERC20) { + expect( + realERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight], + 'Checking left maker ingress ERC20 account balance', + ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight]); + expect( + realERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight], + 'Checking right maker egress ERC20 account balance', + ).to.be.bignumber.equal( + expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight], + ); + } else if (makerAssetProxyIdRight === AssetProxyId.ERC721) { + expect( + realERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort(), + 'Checking left maker ingress ERC721 account holdings', + ).to.be.deep.equal( + expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort(), + ); + expect( + realERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight], + 'Checking right maker agress ERC721 account holdings', + ).to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]); + } else { + throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdRight}`); + } + // Paid fees + expect( + realERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress], + 'Checking left maker egress ERC20 account fees', + ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress]); + expect( + realERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress], + 'Checking right maker egress ERC20 account fees', + ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress]); + expect( + realERC20BalancesByOwner[takerAddress][this._feeTokenAddress], + 'Checking taker egress ERC20 account fees', + ).to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][this._feeTokenAddress]); + // Received fees + expect( + realERC20BalancesByOwner[signedOrderLeft.feeRecipientAddress][this._feeTokenAddress], + 'Checking left fee recipient ingress ERC20 account fees', + ).to.be.bignumber.equal( + expectedERC20BalancesByOwner[signedOrderLeft.feeRecipientAddress][this._feeTokenAddress], + ); + expect( + realERC20BalancesByOwner[signedOrderRight.feeRecipientAddress][this._feeTokenAddress], + 'Checking right fee receipient ingress ERC20 account fees', + ).to.be.bignumber.equal( + expectedERC20BalancesByOwner[signedOrderRight.feeRecipientAddress][this._feeTokenAddress], + ); } /// @dev Calculates the expected balances of order makers, fee recipients, and the taker, /// as a result of matching two orders. @@ -438,7 +567,9 @@ export class MatchOrderTester { // Taker Fees expectedNewERC20BalancesByOwner[takerAddress][this._feeTokenAddress] = expectedNewERC20BalancesByOwner[ takerAddress - ][this._feeTokenAddress].minus(expectedTransferAmounts.feePaidByTakerLeft.add(expectedTransferAmounts.feePaidByTakerRight)); + ][this._feeTokenAddress].minus( + expectedTransferAmounts.feePaidByTakerLeft.add(expectedTransferAmounts.feePaidByTakerRight), + ); // Left Fee Recipient Fees expectedNewERC20BalancesByOwner[feeRecipientAddressLeft][ this._feeTokenAddress @@ -454,4 +585,4 @@ export class MatchOrderTester { return [expectedNewERC20BalancesByOwner, expectedNewERC721TokenIdsByOwner]; } -} +} // tslint:disable-line:max-file-line-count diff --git a/packages/contracts/test/utils/types.ts b/packages/contracts/test/utils/types.ts index 481ee87d69..1726227776 100644 --- a/packages/contracts/test/utils/types.ts +++ b/packages/contracts/test/utils/types.ts @@ -117,21 +117,21 @@ export interface TransferAmountsByMatchOrders { // Left Maker amountBoughtByLeftMaker: BigNumber; amountSoldByLeftMaker: BigNumber; - amountReceivedByLeftMaker: BigNumber; + // amountReceivedByLeftMaker: BigNumber; feePaidByLeftMaker: BigNumber; // Right Maker amountBoughtByRightMaker: BigNumber; amountSoldByRightMaker: BigNumber; - amountReceivedByRightMaker: BigNumber; + // amountReceivedByRightMaker: BigNumber; feePaidByRightMaker: BigNumber; // Taker amountReceivedByTaker: BigNumber; feePaidByTakerLeft: BigNumber; feePaidByTakerRight: BigNumber; - totalFeePaidByTaker: BigNumber; + // totalFeePaidByTaker: BigNumber; // Fee Recipients - feeReceivedLeft: BigNumber; - feeReceivedRight: BigNumber; + // feeReceivedLeft: BigNumber; + // feeReceivedRight: BigNumber; } export interface OrderInfo { From ac872e518197573fddaded73745e58b4235f8af3 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 23 Aug 2018 10:40:02 -0700 Subject: [PATCH 079/120] Added `expect` messages for checking left/right order states --- packages/contracts/test/utils/match_order_tester.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/contracts/test/utils/match_order_tester.ts b/packages/contracts/test/utils/match_order_tester.ts index 300073eb04..98bf800113 100644 --- a/packages/contracts/test/utils/match_order_tester.ts +++ b/packages/contracts/test/utils/match_order_tester.ts @@ -254,7 +254,9 @@ export class MatchOrderTester { const expectedOrderFilledAmountLeft = initialTakerAssetFilledAmountLeft ? initialTakerAssetFilledAmountLeft : new BigNumber(0); - expect(expectedOrderFilledAmountLeft).to.be.bignumber.equal(orderTakerAssetFilledAmountLeft); + expect(expectedOrderFilledAmountLeft, 'Checking inital state of left order').to.be.bignumber.equal( + orderTakerAssetFilledAmountLeft, + ); // Verify Right order preconditions const orderTakerAssetFilledAmountRight = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( orderHashUtils.getOrderHashHex(signedOrderRight), @@ -262,7 +264,9 @@ export class MatchOrderTester { const expectedOrderFilledAmountRight = initialTakerAssetFilledAmountRight ? initialTakerAssetFilledAmountRight : new BigNumber(0); - expect(expectedOrderFilledAmountRight).to.be.bignumber.equal(orderTakerAssetFilledAmountRight); + expect(expectedOrderFilledAmountRight, 'Checking inital state of right order').to.be.bignumber.equal( + orderTakerAssetFilledAmountRight, + ); return [orderTakerAssetFilledAmountLeft, orderTakerAssetFilledAmountRight]; } From 9a5ec8d030c9e9b08018abac54a8d16933affabc Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 23 Aug 2018 11:38:27 -0700 Subject: [PATCH 080/120] Added function signature comments --- .../contracts/test/exchange/match_orders.ts | 54 +-- .../test/utils/match_order_tester.ts | 403 +++++++++--------- packages/contracts/test/utils/types.ts | 15 +- 3 files changed, 233 insertions(+), 239 deletions(-) diff --git a/packages/contracts/test/exchange/match_orders.ts b/packages/contracts/test/exchange/match_orders.ts index 7e9776d52f..58b8250ab5 100644 --- a/packages/contracts/test/exchange/match_orders.ts +++ b/packages/contracts/test/exchange/match_orders.ts @@ -228,15 +228,15 @@ describe.only('matchOrders', () => { // Left Maker amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 0), amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 0), - feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), // 100% + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% // Right Maker amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 0), amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0), feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 16), // 75% // Taker amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(9), 0), - feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18), // 100% - feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 17), // 50% + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 16), // 50% }; // Match signedOrderLeft with signedOrderRight await matchOrderTester.matchOrdersAndVerifyBalancesAsync( @@ -300,8 +300,8 @@ describe.only('matchOrders', () => { feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% // Taker amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18), - feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), - feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, @@ -335,8 +335,8 @@ describe.only('matchOrders', () => { feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% // Taker amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(0), 18), - feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), - feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; // Match signedOrderLeft with signedOrderRight await matchOrderTester.matchOrdersAndVerifyBalancesAsync( @@ -371,8 +371,8 @@ describe.only('matchOrders', () => { feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 16), // 50% // Taker amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18), - feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 40% - feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 16), // 100% + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 16), // 50% }; // Match signedOrderLeft with signedOrderRight await matchOrderTester.matchOrdersAndVerifyBalancesAsync( @@ -407,8 +407,8 @@ describe.only('matchOrders', () => { feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% // Taker amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18), - feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 100% - feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 50% + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 10% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; // Match signedOrderLeft with signedOrderRight await matchOrderTester.matchOrdersAndVerifyBalancesAsync( @@ -445,8 +445,8 @@ describe.only('matchOrders', () => { feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% // Taker amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18), - feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 100% - feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 50% + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // 10% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; // prettier-ignore [ @@ -604,8 +604,8 @@ describe.only('matchOrders', () => { feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% // Taker amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18), - feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), - feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, @@ -640,8 +640,8 @@ describe.only('matchOrders', () => { feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% // Taker amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18), - feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), - feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, @@ -676,8 +676,8 @@ describe.only('matchOrders', () => { feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% // Taker amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18), - feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), - feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, @@ -712,8 +712,8 @@ describe.only('matchOrders', () => { feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% // Taker amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18), - feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), - feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, @@ -748,8 +748,8 @@ describe.only('matchOrders', () => { feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% // Taker amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18), - feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), - feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, @@ -783,8 +783,8 @@ describe.only('matchOrders', () => { feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% // Taker amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 18), - feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), - feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, @@ -929,7 +929,7 @@ describe.only('matchOrders', () => { ); }); - it.only('should transfer correct amounts when right order maker asset is an ERC721 token', async () => { + it('should transfer correct amounts when right order maker asset is an ERC721 token', async () => { // Create orders to match const erc721TokenToTransfer = erc721RightMakerAssetIds[0]; const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ @@ -955,7 +955,7 @@ describe.only('matchOrders', () => { // Taker amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18), feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% - feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 50% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; await matchOrderTester.matchOrdersAndVerifyBalancesAsync( signedOrderLeft, diff --git a/packages/contracts/test/utils/match_order_tester.ts b/packages/contracts/test/utils/match_order_tester.ts index 98bf800113..7d763c6df6 100644 --- a/packages/contracts/test/utils/match_order_tester.ts +++ b/packages/contracts/test/utils/match_order_tester.ts @@ -16,6 +16,7 @@ import { OrderInfo, OrderStatus, TransferAmountsByMatchOrders as TransferAmounts, + TransferAmountsLoggedByMatchOrders as LoggedTransferAmounts, } from './types'; chaiSetup.configure(); @@ -26,13 +27,14 @@ export class MatchOrderTester { private readonly _erc20Wrapper: ERC20Wrapper; private readonly _erc721Wrapper: ERC721Wrapper; private readonly _feeTokenAddress: string; - /// @dev Calculates expected transfer amounts between order makers, fee recipients, and - /// the taker when two orders are matched. + /// @dev Checks values from the logs produced by Exchange.matchOrders against the expected transfer amounts. + /// Values include the amounts transferred from the left/right makers and taker, along with + /// the fees paid on each matched order. These are also the return values of MatchOrders. /// @param signedOrderLeft First matched order. /// @param signedOrderRight Second matched order. - /// @param orderTakerAssetFilledAmountLeft How much left order has been filled, prior to matching orders. - /// @param orderTakerAssetFilledAmountRight How much the right order has been filled, prior to matching orders. - /// @return TransferAmounts A struct containing the expected transfer amounts. + /// @param transactionReceipt Transaction receipt and logs produced by Exchange.matchOrders. + /// @param takerAddress Address of taker (account that called Exchange.matchOrders) + /// @param expectedTransferAmounts Expected amounts transferred as a result of order matching. private static async _verifyLogsAsync( signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder, @@ -40,46 +42,28 @@ export class MatchOrderTester { takerAddress: string, expectedTransferAmounts: TransferAmounts, ): Promise { - // Parse logs + // Should have two logs -- one for each order. expect(transactionReceipt.logs.length, 'Checking number of logs').to.be.equal(2); // First log is for left fill - const leftLog = (transactionReceipt.logs[0] as any) as { - args: { - makerAddress: string; - takerAddress: string; - makerAssetFilledAmount: string; - takerAssetFilledAmount: string; - makerFeePaid: string; - takerFeePaid: string; - }; - }; - expect(leftLog.args.makerAddress, 'Checking logged maker address of left order').to.be.equal( + const leftLog = (transactionReceipt.logs[0] as any).args as LoggedTransferAmounts; + expect(leftLog.makerAddress, 'Checking logged maker address of left order').to.be.equal( signedOrderLeft.makerAddress, ); - expect(leftLog.args.takerAddress, 'Checking logged taker address of right order').to.be.equal(takerAddress); - const amountBoughtByLeftMaker = new BigNumber(leftLog.args.takerAssetFilledAmount); - const amountSoldByLeftMaker = new BigNumber(leftLog.args.makerAssetFilledAmount); - const feePaidByLeftMaker = new BigNumber(leftLog.args.makerFeePaid); - const feePaidByTakerLeft = new BigNumber(leftLog.args.takerFeePaid); + expect(leftLog.takerAddress, 'Checking logged taker address of right order').to.be.equal(takerAddress); + const amountBoughtByLeftMaker = new BigNumber(leftLog.takerAssetFilledAmount); + const amountSoldByLeftMaker = new BigNumber(leftLog.makerAssetFilledAmount); + const feePaidByLeftMaker = new BigNumber(leftLog.makerFeePaid); + const feePaidByTakerLeft = new BigNumber(leftLog.takerFeePaid); // Second log is for right fill - const rightLog = (transactionReceipt.logs[1] as any) as { - args: { - makerAddress: string; - takerAddress: string; - makerAssetFilledAmount: string; - takerAssetFilledAmount: string; - makerFeePaid: string; - takerFeePaid: string; - }; - }; - expect(rightLog.args.makerAddress, 'Checking logged maker address of right order').to.be.equal( + const rightLog = (transactionReceipt.logs[1] as any).args as LoggedTransferAmounts; + expect(rightLog.makerAddress, 'Checking logged maker address of right order').to.be.equal( signedOrderRight.makerAddress, ); - expect(rightLog.args.takerAddress, 'Checking loggerd taker address of right order').to.be.equal(takerAddress); - const amountBoughtByRightMaker = new BigNumber(rightLog.args.takerAssetFilledAmount); - const amountSoldByRightMaker = new BigNumber(rightLog.args.makerAssetFilledAmount); - const feePaidByRightMaker = new BigNumber(rightLog.args.makerFeePaid); - const feePaidByTakerRight = new BigNumber(rightLog.args.takerFeePaid); + expect(rightLog.takerAddress, 'Checking loggerd taker address of right order').to.be.equal(takerAddress); + const amountBoughtByRightMaker = new BigNumber(rightLog.takerAssetFilledAmount); + const amountSoldByRightMaker = new BigNumber(rightLog.makerAssetFilledAmount); + const feePaidByRightMaker = new BigNumber(rightLog.makerFeePaid); + const feePaidByTakerRight = new BigNumber(rightLog.takerFeePaid); // Derive amount received by taker const amountReceivedByTaker = amountSoldByLeftMaker.sub(amountBoughtByRightMaker); // Verify log values - left order @@ -122,30 +106,26 @@ export class MatchOrderTester { 'Checking logged amount received by taker', ).to.be.bignumber.equal(amountReceivedByTaker); } - /// @dev Compares a pair of ERC20 balances and a pair of ERC721 token owners. - /// @param expectedNewERC20BalancesByOwner Expected ERC20 balances. - /// @param realERC20BalancesByOwner Actual ERC20 balances. - /// @param expectedNewERC721TokenIdsByOwner Expected ERC721 token owners. - /// @param realERC721TokenIdsByOwner Actual ERC20 token owners. - /// @return True only if ERC20 balances match and ERC721 token owners match. + /// @dev Verifies all expected ERC20 and ERC721 account holdings match the real holdings. + /// @param expectedERC20BalancesByOwner Expected ERC20 balances. + /// @param realERC20BalancesByOwner Real ERC20 balances. + /// @param expectedERC721TokenIdsByOwner Expected ERC721 token owners. + /// @param realERC721TokenIdsByOwner Real ERC20 token owners. private static async _verifyAllKnownBalancesAsync( - expectedNewERC20BalancesByOwner: ERC20BalancesByOwner, + expectedERC20BalancesByOwner: ERC20BalancesByOwner, realERC20BalancesByOwner: ERC20BalancesByOwner, - expectedNewERC721TokenIdsByOwner: ERC721TokenIdsByOwner, + expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner, realERC721TokenIdsByOwner: ERC721TokenIdsByOwner, ): Promise { // ERC20 Balances - const areERC20BalancesEqual = _.isEqual(expectedNewERC20BalancesByOwner, realERC20BalancesByOwner); + const areERC20BalancesEqual = _.isEqual(expectedERC20BalancesByOwner, realERC20BalancesByOwner); expect(areERC20BalancesEqual, 'Checking all known ERC20 account balances').to.be.true(); // ERC721 Token Ids - const sortedExpectedNewERC721TokenIdsByOwner = _.mapValues( - expectedNewERC721TokenIdsByOwner, - tokenIdsByOwner => { - _.mapValues(tokenIdsByOwner, tokenIds => { - _.sortBy(tokenIds); - }); - }, - ); + const sortedExpectedNewERC721TokenIdsByOwner = _.mapValues(expectedERC721TokenIdsByOwner, tokenIdsByOwner => { + _.mapValues(tokenIdsByOwner, tokenIds => { + _.sortBy(tokenIds); + }); + }); const sortedNewERC721TokenIdsByOwner = _.mapValues(realERC721TokenIdsByOwner, tokenIdsByOwner => { _.mapValues(tokenIdsByOwner, tokenIds => { _.sortBy(tokenIds); @@ -173,15 +153,16 @@ export class MatchOrderTester { this._erc721Wrapper = erc721Wrapper; this._feeTokenAddress = feeTokenAddress; } - /// @dev Matches two complementary orders and validates results. + /// @dev Matches two complementary orders and verifies results. /// Validation either succeeds or throws. /// @param signedOrderLeft First matched order. /// @param signedOrderRight Second matched order. /// @param takerAddress Address of taker (the address who matched the two orders) /// @param erc20BalancesByOwner Current ERC20 balances. /// @param erc721TokenIdsByOwner Current ERC721 token owners. - /// @param initialTakerAssetFilledAmountLeft Current amount the left order has been filled. - /// @param initialTakerAssetFilledAmountRight Current amount the right order has been filled. + /// @param expectedTransferAmounts Expected amounts transferred as a result of order matching. + /// @param initialLeftOrderFilledAmount How much left order has been filled, prior to matching orders. + /// @param initialRightOrderFilledAmount How much the right order has been filled, prior to matching orders. /// @return New ERC20 balances & ERC721 token owners. public async matchOrdersAndVerifyBalancesAsync( signedOrderLeft: SignedOrder, @@ -190,17 +171,22 @@ export class MatchOrderTester { erc20BalancesByOwner: ERC20BalancesByOwner, erc721TokenIdsByOwner: ERC721TokenIdsByOwner, expectedTransferAmounts: TransferAmounts, - initialTakerAssetFilledAmountLeft?: BigNumber, - initialTakerAssetFilledAmountRight?: BigNumber, + initialLeftOrderFilledAmount?: BigNumber, + initialRightOrderFilledAmount?: BigNumber, ): Promise<[ERC20BalancesByOwner, ERC721TokenIdsByOwner]> { + // Assign default values to optional parameters if undefined + if (initialLeftOrderFilledAmount === undefined) { + initialLeftOrderFilledAmount = new BigNumber(0); + } + if (initialRightOrderFilledAmount === undefined) { + initialRightOrderFilledAmount = new BigNumber(0); + } // Verify initial order states - let orderTakerAssetFilledAmountLeft: BigNumber; - let orderTakerAssetFilledAmountRight: BigNumber; - [orderTakerAssetFilledAmountLeft, orderTakerAssetFilledAmountRight] = await this._verifyInitialOrderStatesAsync( + await this._verifyInitialOrderStatesAsync( signedOrderLeft, signedOrderRight, - initialTakerAssetFilledAmountLeft, - initialTakerAssetFilledAmountRight, + initialLeftOrderFilledAmount, + initialRightOrderFilledAmount, ); // Match left & right orders const transactionReceipt = await this._exchangeWrapper.matchOrdersAsync( @@ -222,11 +208,9 @@ export class MatchOrderTester { await this._verifyExchangeStateAsync( signedOrderLeft, signedOrderRight, - orderTakerAssetFilledAmountLeft, - orderTakerAssetFilledAmountRight, + initialLeftOrderFilledAmount, + initialRightOrderFilledAmount, expectedTransferAmounts, - initialTakerAssetFilledAmountLeft, - initialTakerAssetFilledAmountRight, ); // Verify balances of makers, taker, and fee recipients await this._verifyBalancesAsync( @@ -241,56 +225,50 @@ export class MatchOrderTester { ); return [newERC20BalancesByOwner, newERC721TokenIdsByOwner]; } + /// @dev Verifies initial exchange state for the left and right orders. + /// @param signedOrderLeft First matched order. + /// @param signedOrderRight Second matched order. + /// @param expectedOrderFilledAmountLeft How much left order has been filled, prior to matching orders. + /// @param expectedOrderFilledAmountRight How much the right order has been filled, prior to matching orders. private async _verifyInitialOrderStatesAsync( signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder, - initialTakerAssetFilledAmountLeft?: BigNumber, - initialTakerAssetFilledAmountRight?: BigNumber, - ): Promise<[BigNumber, BigNumber]> { - // Verify Left order preconditions + expectedOrderFilledAmountLeft: BigNumber, + expectedOrderFilledAmountRight: BigNumber, + ): Promise { + // Verify left order initial state const orderTakerAssetFilledAmountLeft = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( orderHashUtils.getOrderHashHex(signedOrderLeft), ); - const expectedOrderFilledAmountLeft = initialTakerAssetFilledAmountLeft - ? initialTakerAssetFilledAmountLeft - : new BigNumber(0); expect(expectedOrderFilledAmountLeft, 'Checking inital state of left order').to.be.bignumber.equal( orderTakerAssetFilledAmountLeft, ); - // Verify Right order preconditions + // Verify right order initial state const orderTakerAssetFilledAmountRight = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( orderHashUtils.getOrderHashHex(signedOrderRight), ); - const expectedOrderFilledAmountRight = initialTakerAssetFilledAmountRight - ? initialTakerAssetFilledAmountRight - : new BigNumber(0); expect(expectedOrderFilledAmountRight, 'Checking inital state of right order').to.be.bignumber.equal( orderTakerAssetFilledAmountRight, ); - return [orderTakerAssetFilledAmountLeft, orderTakerAssetFilledAmountRight]; } - - /// @dev Calculates expected transfer amounts between order makers, fee recipients, and - /// the taker when two orders are matched. + /// @dev Verifies the exchange state against the expected amounts transferred by from matching orders. /// @param signedOrderLeft First matched order. /// @param signedOrderRight Second matched order. - /// @param orderTakerAssetFilledAmountLeft How much left order has been filled, prior to matching orders. - /// @param orderTakerAssetFilledAmountRight How much the right order has been filled, prior to matching orders. + /// @param initialLeftOrderFilledAmount How much left order has been filled, prior to matching orders. + /// @param initialRightOrderFilledAmount How much the right order has been filled, prior to matching orders. /// @return TransferAmounts A struct containing the expected transfer amounts. private async _verifyExchangeStateAsync( signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder, - orderTakerAssetFilledAmountLeft: BigNumber, - orderTakerAssetFilledAmountRight: BigNumber, + initialLeftOrderFilledAmount: BigNumber, + initialRightOrderFilledAmount: BigNumber, expectedTransferAmounts: TransferAmounts, - initialTakerAssetFilledAmountLeft?: BigNumber, - initialTakerAssetFilledAmountRight?: BigNumber, ): Promise { // Verify state for left order: amount bought by left maker let amountBoughtByLeftMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( orderHashUtils.getOrderHashHex(signedOrderLeft), ); - amountBoughtByLeftMaker = amountBoughtByLeftMaker.minus(orderTakerAssetFilledAmountLeft); + amountBoughtByLeftMaker = amountBoughtByLeftMaker.minus(initialLeftOrderFilledAmount); expect( expectedTransferAmounts.amountBoughtByLeftMaker, 'Checking exchange state for left order', @@ -299,15 +277,13 @@ export class MatchOrderTester { let amountBoughtByRightMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( orderHashUtils.getOrderHashHex(signedOrderRight), ); - amountBoughtByRightMaker = amountBoughtByRightMaker.minus(orderTakerAssetFilledAmountRight); + amountBoughtByRightMaker = amountBoughtByRightMaker.minus(initialRightOrderFilledAmount); expect( expectedTransferAmounts.amountBoughtByRightMaker, 'Checking exchange state for right order', ).to.be.bignumber.equal(amountBoughtByRightMaker); // Verify left order status - const maxAmountBoughtByLeftMaker = initialTakerAssetFilledAmountLeft - ? signedOrderLeft.takerAssetAmount.sub(initialTakerAssetFilledAmountLeft) - : signedOrderLeft.takerAssetAmount; + const maxAmountBoughtByLeftMaker = signedOrderLeft.takerAssetAmount.minus(initialLeftOrderFilledAmount); const leftOrderInfo: OrderInfo = await this._exchangeWrapper.getOrderInfoAsync(signedOrderLeft); const leftExpectedStatus = expectedTransferAmounts.amountBoughtByLeftMaker.equals(maxAmountBoughtByLeftMaker) ? OrderStatus.FULLY_FILLED @@ -316,9 +292,7 @@ export class MatchOrderTester { leftExpectedStatus, ); // Verify right order status - const maxAmountBoughtByRightMaker = initialTakerAssetFilledAmountRight - ? signedOrderRight.takerAssetAmount.sub(initialTakerAssetFilledAmountRight) - : signedOrderRight.takerAssetAmount; + const maxAmountBoughtByRightMaker = signedOrderRight.takerAssetAmount.minus(initialRightOrderFilledAmount); const rightOrderInfo: OrderInfo = await this._exchangeWrapper.getOrderInfoAsync(signedOrderRight); const rightExpectedStatus = expectedTransferAmounts.amountBoughtByRightMaker.equals(maxAmountBoughtByRightMaker) ? OrderStatus.FULLY_FILLED @@ -327,6 +301,15 @@ export class MatchOrderTester { rightExpectedStatus, ); } + /// @dev Verifies account balances after matching orders. + /// @param signedOrderLeft First matched order. + /// @param signedOrderRight Second matched order. + /// @param initialERC20BalancesByOwner ERC20 balances prior to order matching. + /// @param initialERC721TokenIdsByOwner ERC721 token owners prior to order matching. + /// @param finalERC20BalancesByOwner ERC20 balances after order matching. + /// @param finalERC721TokenIdsByOwner ERC721 token owners after order matching. + /// @param expectedTransferAmounts Expected amounts transferred as a result of order matching. + /// @param takerAddress Address of taker (account that called Exchange.matchOrders). private async _verifyBalancesAsync( signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder, @@ -365,113 +348,6 @@ export class MatchOrderTester { finalERC721TokenIdsByOwner, ); } - private async _verifyMakerTakerAndFeeRecipientBalancesAsync( - signedOrderLeft: SignedOrder, - signedOrderRight: SignedOrder, - expectedERC20BalancesByOwner: ERC20BalancesByOwner, - realERC20BalancesByOwner: ERC20BalancesByOwner, - expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner, - realERC721TokenIdsByOwner: ERC721TokenIdsByOwner, - takerAddress: string, - ): Promise { - // Individual balance comparisons - const makerAssetProxyIdLeft = assetDataUtils.decodeAssetProxyId(signedOrderLeft.makerAssetData); - const makerERC20AssetDataLeft = - makerAssetProxyIdLeft === AssetProxyId.ERC20 - ? assetDataUtils.decodeERC20AssetData(signedOrderLeft.makerAssetData) - : assetDataUtils.decodeERC721AssetData(signedOrderLeft.makerAssetData); - const makerAssetAddressLeft = makerERC20AssetDataLeft.tokenAddress; - const makerAssetProxyIdRight = assetDataUtils.decodeAssetProxyId(signedOrderRight.makerAssetData); - const makerERC20AssetDataRight = - makerAssetProxyIdRight === AssetProxyId.ERC20 - ? assetDataUtils.decodeERC20AssetData(signedOrderRight.makerAssetData) - : assetDataUtils.decodeERC721AssetData(signedOrderRight.makerAssetData); - const makerAssetAddressRight = makerERC20AssetDataRight.tokenAddress; - if (makerAssetProxyIdLeft === AssetProxyId.ERC20) { - expect( - realERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft], - 'Checking left maker egress ERC20 account balance', - ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft]); - expect( - realERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft], - 'Checking right maker ingress ERC20 account balance', - ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft]); - expect( - realERC20BalancesByOwner[takerAddress][makerAssetAddressLeft], - 'Checking taker ingress ERC20 account balance', - ).to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][makerAssetAddressLeft]); - } else if (makerAssetProxyIdLeft === AssetProxyId.ERC721) { - expect( - realERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort(), - 'Checking left maker egress ERC721 account holdings', - ).to.be.deep.equal( - expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort(), - ); - expect( - realERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort(), - 'Checking right maker ERC721 account holdings', - ).to.be.deep.equal( - expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort(), - ); - expect( - realERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort(), - 'Checking taker ingress ERC721 account holdings', - ).to.be.deep.equal(expectedERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort()); - } else { - throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdLeft}`); - } - if (makerAssetProxyIdRight === AssetProxyId.ERC20) { - expect( - realERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight], - 'Checking left maker ingress ERC20 account balance', - ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight]); - expect( - realERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight], - 'Checking right maker egress ERC20 account balance', - ).to.be.bignumber.equal( - expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight], - ); - } else if (makerAssetProxyIdRight === AssetProxyId.ERC721) { - expect( - realERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort(), - 'Checking left maker ingress ERC721 account holdings', - ).to.be.deep.equal( - expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort(), - ); - expect( - realERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight], - 'Checking right maker agress ERC721 account holdings', - ).to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]); - } else { - throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdRight}`); - } - // Paid fees - expect( - realERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress], - 'Checking left maker egress ERC20 account fees', - ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress]); - expect( - realERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress], - 'Checking right maker egress ERC20 account fees', - ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress]); - expect( - realERC20BalancesByOwner[takerAddress][this._feeTokenAddress], - 'Checking taker egress ERC20 account fees', - ).to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][this._feeTokenAddress]); - // Received fees - expect( - realERC20BalancesByOwner[signedOrderLeft.feeRecipientAddress][this._feeTokenAddress], - 'Checking left fee recipient ingress ERC20 account fees', - ).to.be.bignumber.equal( - expectedERC20BalancesByOwner[signedOrderLeft.feeRecipientAddress][this._feeTokenAddress], - ); - expect( - realERC20BalancesByOwner[signedOrderRight.feeRecipientAddress][this._feeTokenAddress], - 'Checking right fee receipient ingress ERC20 account fees', - ).to.be.bignumber.equal( - expectedERC20BalancesByOwner[signedOrderRight.feeRecipientAddress][this._feeTokenAddress], - ); - } /// @dev Calculates the expected balances of order makers, fee recipients, and the taker, /// as a result of matching two orders. /// @param signedOrderRight First matched order. @@ -479,7 +355,7 @@ export class MatchOrderTester { /// @param takerAddress Address of taker (the address who matched the two orders) /// @param erc20BalancesByOwner Current ERC20 balances. /// @param erc721TokenIdsByOwner Current ERC721 token owners. - /// @param expectedTransferAmounts A struct containing the expected transfer amounts. + /// @param expectedTransferAmounts Expected amounts transferred as a result of order matching. /// @return Expected ERC20 balances & ERC721 token owners after orders have been matched. private _calculateExpectedBalances( signedOrderLeft: SignedOrder, @@ -589,4 +465,119 @@ export class MatchOrderTester { return [expectedNewERC20BalancesByOwner, expectedNewERC721TokenIdsByOwner]; } + /// @dev + /// @param signedOrderLeft First matched order. + /// @param signedOrderRight Second matched order. + /// @param expectedERC20BalancesByOwner Expected ERC20 balances. + /// @param realERC20BalancesByOwner Real ERC20 balances. + /// @param expectedERC721TokenIdsByOwner Expected ERC721 token owners. + /// @param realERC721TokenIdsByOwner Real ERC20 token owners. + /// @param takerAddress Address of taker (account that called Exchange.matchOrders). + private async _verifyMakerTakerAndFeeRecipientBalancesAsync( + signedOrderLeft: SignedOrder, + signedOrderRight: SignedOrder, + expectedERC20BalancesByOwner: ERC20BalancesByOwner, + realERC20BalancesByOwner: ERC20BalancesByOwner, + expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner, + realERC721TokenIdsByOwner: ERC721TokenIdsByOwner, + takerAddress: string, + ): Promise { + // Individual balance comparisons + const makerAssetProxyIdLeft = assetDataUtils.decodeAssetProxyId(signedOrderLeft.makerAssetData); + const makerERC20AssetDataLeft = + makerAssetProxyIdLeft === AssetProxyId.ERC20 + ? assetDataUtils.decodeERC20AssetData(signedOrderLeft.makerAssetData) + : assetDataUtils.decodeERC721AssetData(signedOrderLeft.makerAssetData); + const makerAssetAddressLeft = makerERC20AssetDataLeft.tokenAddress; + const makerAssetProxyIdRight = assetDataUtils.decodeAssetProxyId(signedOrderRight.makerAssetData); + const makerERC20AssetDataRight = + makerAssetProxyIdRight === AssetProxyId.ERC20 + ? assetDataUtils.decodeERC20AssetData(signedOrderRight.makerAssetData) + : assetDataUtils.decodeERC721AssetData(signedOrderRight.makerAssetData); + const makerAssetAddressRight = makerERC20AssetDataRight.tokenAddress; + if (makerAssetProxyIdLeft === AssetProxyId.ERC20) { + expect( + realERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft], + 'Checking left maker egress ERC20 account balance', + ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft]); + expect( + realERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft], + 'Checking right maker ingress ERC20 account balance', + ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft]); + expect( + realERC20BalancesByOwner[takerAddress][makerAssetAddressLeft], + 'Checking taker ingress ERC20 account balance', + ).to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][makerAssetAddressLeft]); + } else if (makerAssetProxyIdLeft === AssetProxyId.ERC721) { + expect( + realERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort(), + 'Checking left maker egress ERC721 account holdings', + ).to.be.deep.equal( + expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressLeft].sort(), + ); + expect( + realERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort(), + 'Checking right maker ERC721 account holdings', + ).to.be.deep.equal( + expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressLeft].sort(), + ); + expect( + realERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort(), + 'Checking taker ingress ERC721 account holdings', + ).to.be.deep.equal(expectedERC721TokenIdsByOwner[takerAddress][makerAssetAddressLeft].sort()); + } else { + throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdLeft}`); + } + if (makerAssetProxyIdRight === AssetProxyId.ERC20) { + expect( + realERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight], + 'Checking left maker ingress ERC20 account balance', + ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight]); + expect( + realERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight], + 'Checking right maker egress ERC20 account balance', + ).to.be.bignumber.equal( + expectedERC20BalancesByOwner[signedOrderRight.makerAddress][makerAssetAddressRight], + ); + } else if (makerAssetProxyIdRight === AssetProxyId.ERC721) { + expect( + realERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort(), + 'Checking left maker ingress ERC721 account holdings', + ).to.be.deep.equal( + expectedERC721TokenIdsByOwner[signedOrderLeft.makerAddress][makerAssetAddressRight].sort(), + ); + expect( + realERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight], + 'Checking right maker agress ERC721 account holdings', + ).to.be.deep.equal(expectedERC721TokenIdsByOwner[signedOrderRight.makerAddress][makerAssetAddressRight]); + } else { + throw new Error(`Unhandled Asset Proxy ID: ${makerAssetProxyIdRight}`); + } + // Paid fees + expect( + realERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress], + 'Checking left maker egress ERC20 account fees', + ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderLeft.makerAddress][this._feeTokenAddress]); + expect( + realERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress], + 'Checking right maker egress ERC20 account fees', + ).to.be.bignumber.equal(expectedERC20BalancesByOwner[signedOrderRight.makerAddress][this._feeTokenAddress]); + expect( + realERC20BalancesByOwner[takerAddress][this._feeTokenAddress], + 'Checking taker egress ERC20 account fees', + ).to.be.bignumber.equal(expectedERC20BalancesByOwner[takerAddress][this._feeTokenAddress]); + // Received fees + expect( + realERC20BalancesByOwner[signedOrderLeft.feeRecipientAddress][this._feeTokenAddress], + 'Checking left fee recipient ingress ERC20 account fees', + ).to.be.bignumber.equal( + expectedERC20BalancesByOwner[signedOrderLeft.feeRecipientAddress][this._feeTokenAddress], + ); + expect( + realERC20BalancesByOwner[signedOrderRight.feeRecipientAddress][this._feeTokenAddress], + 'Checking right fee receipient ingress ERC20 account fees', + ).to.be.bignumber.equal( + expectedERC20BalancesByOwner[signedOrderRight.feeRecipientAddress][this._feeTokenAddress], + ); + } } // tslint:disable-line:max-file-line-count diff --git a/packages/contracts/test/utils/types.ts b/packages/contracts/test/utils/types.ts index 1726227776..598fb53930 100644 --- a/packages/contracts/test/utils/types.ts +++ b/packages/contracts/test/utils/types.ts @@ -117,21 +117,24 @@ export interface TransferAmountsByMatchOrders { // Left Maker amountBoughtByLeftMaker: BigNumber; amountSoldByLeftMaker: BigNumber; - // amountReceivedByLeftMaker: BigNumber; feePaidByLeftMaker: BigNumber; // Right Maker amountBoughtByRightMaker: BigNumber; amountSoldByRightMaker: BigNumber; - // amountReceivedByRightMaker: BigNumber; feePaidByRightMaker: BigNumber; // Taker amountReceivedByTaker: BigNumber; feePaidByTakerLeft: BigNumber; feePaidByTakerRight: BigNumber; - // totalFeePaidByTaker: BigNumber; - // Fee Recipients - // feeReceivedLeft: BigNumber; - // feeReceivedRight: BigNumber; +} + +export interface TransferAmountsLoggedByMatchOrders { + makerAddress: string; + takerAddress: string; + makerAssetFilledAmount: string; + takerAssetFilledAmount: string; + makerFeePaid: string; + takerFeePaid: string; } export interface OrderInfo { From 9fcb2dda73ed7fbcf772364029b987fb147d7387 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 23 Aug 2018 11:39:59 -0700 Subject: [PATCH 081/120] Fixed a function comment --- packages/contracts/test/utils/match_order_tester.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/contracts/test/utils/match_order_tester.ts b/packages/contracts/test/utils/match_order_tester.ts index 7d763c6df6..ee298097dc 100644 --- a/packages/contracts/test/utils/match_order_tester.ts +++ b/packages/contracts/test/utils/match_order_tester.ts @@ -465,7 +465,8 @@ export class MatchOrderTester { return [expectedNewERC20BalancesByOwner, expectedNewERC721TokenIdsByOwner]; } - /// @dev + /// @dev Verifies ERC20 account balances and ERC721 token holdings that result from order matching. + /// Specifically checks balances of makers, taker and fee recipients. /// @param signedOrderLeft First matched order. /// @param signedOrderRight Second matched order. /// @param expectedERC20BalancesByOwner Expected ERC20 balances. From 1e6b83719a6de17f4501b13afe3e8bef82087def Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 23 Aug 2018 11:45:20 -0700 Subject: [PATCH 082/120] Renaming verify -> assert in order matching --- .../contracts/test/exchange/match_orders.ts | 36 +++++----- .../test/utils/match_order_tester.ts | 69 +++++++++---------- 2 files changed, 52 insertions(+), 53 deletions(-) diff --git a/packages/contracts/test/exchange/match_orders.ts b/packages/contracts/test/exchange/match_orders.ts index 58b8250ab5..95d4b75023 100644 --- a/packages/contracts/test/exchange/match_orders.ts +++ b/packages/contracts/test/exchange/match_orders.ts @@ -191,7 +191,7 @@ describe.only('matchOrders', () => { feeRecipientAddress: feeRecipientAddressRight, }); // Match signedOrderLeft with signedOrderRight - await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + await matchOrderTester.matchOrdersAndAssertEffectsAsync( signedOrderLeft, signedOrderRight, takerAddress, @@ -239,7 +239,7 @@ describe.only('matchOrders', () => { feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 16), // 50% }; // Match signedOrderLeft with signedOrderRight - await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + await matchOrderTester.matchOrdersAndAssertEffectsAsync( signedOrderLeft, signedOrderRight, takerAddress, @@ -303,7 +303,7 @@ describe.only('matchOrders', () => { feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; - await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + await matchOrderTester.matchOrdersAndAssertEffectsAsync( signedOrderLeft, signedOrderRight, takerAddress, @@ -339,7 +339,7 @@ describe.only('matchOrders', () => { feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; // Match signedOrderLeft with signedOrderRight - await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + await matchOrderTester.matchOrdersAndAssertEffectsAsync( signedOrderLeft, signedOrderRight, takerAddress, @@ -375,7 +375,7 @@ describe.only('matchOrders', () => { feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 16), // 50% }; // Match signedOrderLeft with signedOrderRight - await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + await matchOrderTester.matchOrdersAndAssertEffectsAsync( signedOrderLeft, signedOrderRight, takerAddress, @@ -411,7 +411,7 @@ describe.only('matchOrders', () => { feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; // Match signedOrderLeft with signedOrderRight - await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + await matchOrderTester.matchOrdersAndAssertEffectsAsync( signedOrderLeft, signedOrderRight, takerAddress, @@ -453,7 +453,7 @@ describe.only('matchOrders', () => { newERC20BalancesByOwner, // tslint:disable-next-line:trailing-comma newERC721TokenIdsByOwner - ] = await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + ] = await matchOrderTester.matchOrdersAndAssertEffectsAsync( signedOrderLeft, signedOrderRight, takerAddress, @@ -486,7 +486,7 @@ describe.only('matchOrders', () => { feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90% (10% paid earlier) feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(90), 16), // 90% }; - await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + await matchOrderTester.matchOrdersAndAssertEffectsAsync( signedOrderLeft, signedOrderRight2, takerAddress, @@ -531,7 +531,7 @@ describe.only('matchOrders', () => { newERC20BalancesByOwner, // tslint:disable-next-line:trailing-comma newERC721TokenIdsByOwner - ] = await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + ] = await matchOrderTester.matchOrdersAndAssertEffectsAsync( signedOrderLeft, signedOrderRight, takerAddress, @@ -568,7 +568,7 @@ describe.only('matchOrders', () => { feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96% feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(96), 16), // 96% }; - await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + await matchOrderTester.matchOrdersAndAssertEffectsAsync( signedOrderLeft2, signedOrderRight, takerAddress, @@ -607,7 +607,7 @@ describe.only('matchOrders', () => { feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; - await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + await matchOrderTester.matchOrdersAndAssertEffectsAsync( signedOrderLeft, signedOrderRight, takerAddress, @@ -643,7 +643,7 @@ describe.only('matchOrders', () => { feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; - await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + await matchOrderTester.matchOrdersAndAssertEffectsAsync( signedOrderLeft, signedOrderRight, takerAddress, @@ -679,7 +679,7 @@ describe.only('matchOrders', () => { feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; - await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + await matchOrderTester.matchOrdersAndAssertEffectsAsync( signedOrderLeft, signedOrderRight, takerAddress, @@ -715,7 +715,7 @@ describe.only('matchOrders', () => { feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; - await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + await matchOrderTester.matchOrdersAndAssertEffectsAsync( signedOrderLeft, signedOrderRight, takerAddress, @@ -751,7 +751,7 @@ describe.only('matchOrders', () => { feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; - await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + await matchOrderTester.matchOrdersAndAssertEffectsAsync( signedOrderLeft, signedOrderRight, takerAddress, @@ -786,7 +786,7 @@ describe.only('matchOrders', () => { feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; - await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + await matchOrderTester.matchOrdersAndAssertEffectsAsync( signedOrderLeft, signedOrderRight, takerAddress, @@ -919,7 +919,7 @@ describe.only('matchOrders', () => { feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 50% }; - await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + await matchOrderTester.matchOrdersAndAssertEffectsAsync( signedOrderLeft, signedOrderRight, takerAddress, @@ -957,7 +957,7 @@ describe.only('matchOrders', () => { feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; - await matchOrderTester.matchOrdersAndVerifyBalancesAsync( + await matchOrderTester.matchOrdersAndAssertEffectsAsync( signedOrderLeft, signedOrderRight, takerAddress, diff --git a/packages/contracts/test/utils/match_order_tester.ts b/packages/contracts/test/utils/match_order_tester.ts index ee298097dc..7f2110e0f3 100644 --- a/packages/contracts/test/utils/match_order_tester.ts +++ b/packages/contracts/test/utils/match_order_tester.ts @@ -35,7 +35,7 @@ export class MatchOrderTester { /// @param transactionReceipt Transaction receipt and logs produced by Exchange.matchOrders. /// @param takerAddress Address of taker (account that called Exchange.matchOrders) /// @param expectedTransferAmounts Expected amounts transferred as a result of order matching. - private static async _verifyLogsAsync( + private static async _assertLogsAsync( signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder, transactionReceipt: TransactionReceiptWithDecodedLogs, @@ -66,7 +66,7 @@ export class MatchOrderTester { const feePaidByTakerRight = new BigNumber(rightLog.takerFeePaid); // Derive amount received by taker const amountReceivedByTaker = amountSoldByLeftMaker.sub(amountBoughtByRightMaker); - // Verify log values - left order + // Assert log values - left order expect( expectedTransferAmounts.amountBoughtByLeftMaker, 'Checking logged amount bought by left maker', @@ -83,7 +83,7 @@ export class MatchOrderTester { expectedTransferAmounts.feePaidByTakerLeft, 'Checking logged fee paid on left order by taker', ).to.be.bignumber.equal(feePaidByTakerLeft); - // Verify log values - right order + // Assert log values - right order expect( expectedTransferAmounts.amountBoughtByRightMaker, 'Checking logged amount bought by right maker', @@ -100,18 +100,18 @@ export class MatchOrderTester { expectedTransferAmounts.feePaidByTakerRight, 'Checking logged fee paid on right order by taker', ).to.be.bignumber.equal(feePaidByTakerRight); - // Verify derived amount received by taker + // Assert derived amount received by taker expect( expectedTransferAmounts.amountReceivedByTaker, 'Checking logged amount received by taker', ).to.be.bignumber.equal(amountReceivedByTaker); } - /// @dev Verifies all expected ERC20 and ERC721 account holdings match the real holdings. + /// @dev Asserts all expected ERC20 and ERC721 account holdings match the real holdings. /// @param expectedERC20BalancesByOwner Expected ERC20 balances. /// @param realERC20BalancesByOwner Real ERC20 balances. /// @param expectedERC721TokenIdsByOwner Expected ERC721 token owners. /// @param realERC721TokenIdsByOwner Real ERC20 token owners. - private static async _verifyAllKnownBalancesAsync( + private static async _assertAllKnownBalancesAsync( expectedERC20BalancesByOwner: ERC20BalancesByOwner, realERC20BalancesByOwner: ERC20BalancesByOwner, expectedERC721TokenIdsByOwner: ERC721TokenIdsByOwner, @@ -153,8 +153,7 @@ export class MatchOrderTester { this._erc721Wrapper = erc721Wrapper; this._feeTokenAddress = feeTokenAddress; } - /// @dev Matches two complementary orders and verifies results. - /// Validation either succeeds or throws. + /// @dev Matches two complementary orders and asserts results. /// @param signedOrderLeft First matched order. /// @param signedOrderRight Second matched order. /// @param takerAddress Address of taker (the address who matched the two orders) @@ -164,7 +163,7 @@ export class MatchOrderTester { /// @param initialLeftOrderFilledAmount How much left order has been filled, prior to matching orders. /// @param initialRightOrderFilledAmount How much the right order has been filled, prior to matching orders. /// @return New ERC20 balances & ERC721 token owners. - public async matchOrdersAndVerifyBalancesAsync( + public async matchOrdersAndAssertEffectsAsync( signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder, takerAddress: string, @@ -181,8 +180,8 @@ export class MatchOrderTester { if (initialRightOrderFilledAmount === undefined) { initialRightOrderFilledAmount = new BigNumber(0); } - // Verify initial order states - await this._verifyInitialOrderStatesAsync( + // Assert initial order states + await this._assertInitialOrderStatesAsync( signedOrderLeft, signedOrderRight, initialLeftOrderFilledAmount, @@ -196,24 +195,24 @@ export class MatchOrderTester { ); const newERC20BalancesByOwner = await this._erc20Wrapper.getBalancesAsync(); const newERC721TokenIdsByOwner = await this._erc721Wrapper.getBalancesAsync(); - // Verify logs - await MatchOrderTester._verifyLogsAsync( + // Assert logs + await MatchOrderTester._assertLogsAsync( signedOrderLeft, signedOrderRight, transactionReceipt, takerAddress, expectedTransferAmounts, ); - // Verify exchange state - await this._verifyExchangeStateAsync( + // Assert exchange state + await this._assertExchangeStateAsync( signedOrderLeft, signedOrderRight, initialLeftOrderFilledAmount, initialRightOrderFilledAmount, expectedTransferAmounts, ); - // Verify balances of makers, taker, and fee recipients - await this._verifyBalancesAsync( + // Assert balances of makers, taker, and fee recipients + await this._assertBalancesAsync( signedOrderLeft, signedOrderRight, erc20BalancesByOwner, @@ -225,25 +224,25 @@ export class MatchOrderTester { ); return [newERC20BalancesByOwner, newERC721TokenIdsByOwner]; } - /// @dev Verifies initial exchange state for the left and right orders. + /// @dev Asserts initial exchange state for the left and right orders. /// @param signedOrderLeft First matched order. /// @param signedOrderRight Second matched order. /// @param expectedOrderFilledAmountLeft How much left order has been filled, prior to matching orders. /// @param expectedOrderFilledAmountRight How much the right order has been filled, prior to matching orders. - private async _verifyInitialOrderStatesAsync( + private async _assertInitialOrderStatesAsync( signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder, expectedOrderFilledAmountLeft: BigNumber, expectedOrderFilledAmountRight: BigNumber, ): Promise { - // Verify left order initial state + // Assert left order initial state const orderTakerAssetFilledAmountLeft = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( orderHashUtils.getOrderHashHex(signedOrderLeft), ); expect(expectedOrderFilledAmountLeft, 'Checking inital state of left order').to.be.bignumber.equal( orderTakerAssetFilledAmountLeft, ); - // Verify right order initial state + // Assert right order initial state const orderTakerAssetFilledAmountRight = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( orderHashUtils.getOrderHashHex(signedOrderRight), ); @@ -251,20 +250,20 @@ export class MatchOrderTester { orderTakerAssetFilledAmountRight, ); } - /// @dev Verifies the exchange state against the expected amounts transferred by from matching orders. + /// @dev Asserts the exchange state against the expected amounts transferred by from matching orders. /// @param signedOrderLeft First matched order. /// @param signedOrderRight Second matched order. /// @param initialLeftOrderFilledAmount How much left order has been filled, prior to matching orders. /// @param initialRightOrderFilledAmount How much the right order has been filled, prior to matching orders. /// @return TransferAmounts A struct containing the expected transfer amounts. - private async _verifyExchangeStateAsync( + private async _assertExchangeStateAsync( signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder, initialLeftOrderFilledAmount: BigNumber, initialRightOrderFilledAmount: BigNumber, expectedTransferAmounts: TransferAmounts, ): Promise { - // Verify state for left order: amount bought by left maker + // Assert state for left order: amount bought by left maker let amountBoughtByLeftMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( orderHashUtils.getOrderHashHex(signedOrderLeft), ); @@ -273,7 +272,7 @@ export class MatchOrderTester { expectedTransferAmounts.amountBoughtByLeftMaker, 'Checking exchange state for left order', ).to.be.bignumber.equal(amountBoughtByLeftMaker); - // Verify state for right order: amount bought by right maker + // Assert state for right order: amount bought by right maker let amountBoughtByRightMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( orderHashUtils.getOrderHashHex(signedOrderRight), ); @@ -282,7 +281,7 @@ export class MatchOrderTester { expectedTransferAmounts.amountBoughtByRightMaker, 'Checking exchange state for right order', ).to.be.bignumber.equal(amountBoughtByRightMaker); - // Verify left order status + // Assert left order status const maxAmountBoughtByLeftMaker = signedOrderLeft.takerAssetAmount.minus(initialLeftOrderFilledAmount); const leftOrderInfo: OrderInfo = await this._exchangeWrapper.getOrderInfoAsync(signedOrderLeft); const leftExpectedStatus = expectedTransferAmounts.amountBoughtByLeftMaker.equals(maxAmountBoughtByLeftMaker) @@ -291,7 +290,7 @@ export class MatchOrderTester { expect(leftOrderInfo.orderStatus as OrderStatus, 'Checking exchange status for left order').to.be.equal( leftExpectedStatus, ); - // Verify right order status + // Assert right order status const maxAmountBoughtByRightMaker = signedOrderRight.takerAssetAmount.minus(initialRightOrderFilledAmount); const rightOrderInfo: OrderInfo = await this._exchangeWrapper.getOrderInfoAsync(signedOrderRight); const rightExpectedStatus = expectedTransferAmounts.amountBoughtByRightMaker.equals(maxAmountBoughtByRightMaker) @@ -301,7 +300,7 @@ export class MatchOrderTester { rightExpectedStatus, ); } - /// @dev Verifies account balances after matching orders. + /// @dev Asserts account balances after matching orders. /// @param signedOrderLeft First matched order. /// @param signedOrderRight Second matched order. /// @param initialERC20BalancesByOwner ERC20 balances prior to order matching. @@ -310,7 +309,7 @@ export class MatchOrderTester { /// @param finalERC721TokenIdsByOwner ERC721 token owners after order matching. /// @param expectedTransferAmounts Expected amounts transferred as a result of order matching. /// @param takerAddress Address of taker (account that called Exchange.matchOrders). - private async _verifyBalancesAsync( + private async _assertBalancesAsync( signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder, initialERC20BalancesByOwner: ERC20BalancesByOwner, @@ -330,8 +329,8 @@ export class MatchOrderTester { initialERC721TokenIdsByOwner, expectedTransferAmounts, ); - // Verify balances of makers, taker, and fee recipients - await this._verifyMakerTakerAndFeeRecipientBalancesAsync( + // Assert balances of makers, taker, and fee recipients + await this._assertMakerTakerAndFeeRecipientBalancesAsync( signedOrderLeft, signedOrderRight, expectedERC20BalancesByOwner, @@ -340,8 +339,8 @@ export class MatchOrderTester { finalERC721TokenIdsByOwner, takerAddress, ); - // Verify balances for all known accounts - await MatchOrderTester._verifyAllKnownBalancesAsync( + // Assert balances for all known accounts + await MatchOrderTester._assertAllKnownBalancesAsync( expectedERC20BalancesByOwner, finalERC20BalancesByOwner, expectedERC721TokenIdsByOwner, @@ -465,7 +464,7 @@ export class MatchOrderTester { return [expectedNewERC20BalancesByOwner, expectedNewERC721TokenIdsByOwner]; } - /// @dev Verifies ERC20 account balances and ERC721 token holdings that result from order matching. + /// @dev Asserts ERC20 account balances and ERC721 token holdings that result from order matching. /// Specifically checks balances of makers, taker and fee recipients. /// @param signedOrderLeft First matched order. /// @param signedOrderRight Second matched order. @@ -474,7 +473,7 @@ export class MatchOrderTester { /// @param expectedERC721TokenIdsByOwner Expected ERC721 token owners. /// @param realERC721TokenIdsByOwner Real ERC20 token owners. /// @param takerAddress Address of taker (account that called Exchange.matchOrders). - private async _verifyMakerTakerAndFeeRecipientBalancesAsync( + private async _assertMakerTakerAndFeeRecipientBalancesAsync( signedOrderLeft: SignedOrder, signedOrderRight: SignedOrder, expectedERC20BalancesByOwner: ERC20BalancesByOwner, From ba15fb6a06b3c924ec3662a706c99f143fcef0f9 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 23 Aug 2018 13:27:59 -0700 Subject: [PATCH 083/120] Swapped direction of `expect` values to match output in failure cases --- .../test/utils/match_order_tester.ts | 63 ++++++++----------- 1 file changed, 26 insertions(+), 37 deletions(-) diff --git a/packages/contracts/test/utils/match_order_tester.ts b/packages/contracts/test/utils/match_order_tester.ts index 7f2110e0f3..e6347a962a 100644 --- a/packages/contracts/test/utils/match_order_tester.ts +++ b/packages/contracts/test/utils/match_order_tester.ts @@ -67,44 +67,35 @@ export class MatchOrderTester { // Derive amount received by taker const amountReceivedByTaker = amountSoldByLeftMaker.sub(amountBoughtByRightMaker); // Assert log values - left order - expect( + expect(amountBoughtByLeftMaker, 'Checking logged amount bought by left maker').to.be.bignumber.equal( expectedTransferAmounts.amountBoughtByLeftMaker, - 'Checking logged amount bought by left maker', - ).to.be.bignumber.equal(amountBoughtByLeftMaker); - expect( + ); + expect(amountSoldByLeftMaker, 'Checking logged amount sold by left maker').to.be.bignumber.equal( expectedTransferAmounts.amountSoldByLeftMaker, - 'Checking logged amount sold by left maker', - ).to.be.bignumber.equal(amountSoldByLeftMaker); - expect( + ); + expect(feePaidByLeftMaker, 'Checking logged fee paid by left maker').to.be.bignumber.equal( expectedTransferAmounts.feePaidByLeftMaker, - 'Checking logged fee paid by left maker', - ).to.be.bignumber.equal(feePaidByLeftMaker); - expect( + ); + expect(feePaidByTakerLeft, 'Checking logged fee paid on left order by taker').to.be.bignumber.equal( expectedTransferAmounts.feePaidByTakerLeft, - 'Checking logged fee paid on left order by taker', - ).to.be.bignumber.equal(feePaidByTakerLeft); + ); // Assert log values - right order - expect( + expect(amountBoughtByRightMaker, 'Checking logged amount bought by right maker').to.be.bignumber.equal( expectedTransferAmounts.amountBoughtByRightMaker, - 'Checking logged amount bought by right maker', - ).to.be.bignumber.equal(amountBoughtByRightMaker); - expect( + ); + expect(amountSoldByRightMaker, 'Checking logged amount sold by right maker').to.be.bignumber.equal( expectedTransferAmounts.amountSoldByRightMaker, - 'Checking logged amount sold by right maker', - ).to.be.bignumber.equal(amountSoldByRightMaker); - expect( + ); + expect(feePaidByRightMaker, 'Checking logged fee paid by right maker').to.be.bignumber.equal( expectedTransferAmounts.feePaidByRightMaker, - 'Checking logged fee paid by right maker', - ).to.be.bignumber.equal(feePaidByRightMaker); - expect( + ); + expect(feePaidByTakerRight, 'Checking logged fee paid on right order by taker').to.be.bignumber.equal( expectedTransferAmounts.feePaidByTakerRight, - 'Checking logged fee paid on right order by taker', - ).to.be.bignumber.equal(feePaidByTakerRight); + ); // Assert derived amount received by taker - expect( + expect(amountReceivedByTaker, 'Checking logged amount received by taker').to.be.bignumber.equal( expectedTransferAmounts.amountReceivedByTaker, - 'Checking logged amount received by taker', - ).to.be.bignumber.equal(amountReceivedByTaker); + ); } /// @dev Asserts all expected ERC20 and ERC721 account holdings match the real holdings. /// @param expectedERC20BalancesByOwner Expected ERC20 balances. @@ -239,15 +230,15 @@ export class MatchOrderTester { const orderTakerAssetFilledAmountLeft = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( orderHashUtils.getOrderHashHex(signedOrderLeft), ); - expect(expectedOrderFilledAmountLeft, 'Checking inital state of left order').to.be.bignumber.equal( - orderTakerAssetFilledAmountLeft, + expect(orderTakerAssetFilledAmountLeft, 'Checking inital state of left order').to.be.bignumber.equal( + expectedOrderFilledAmountLeft, ); // Assert right order initial state const orderTakerAssetFilledAmountRight = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( orderHashUtils.getOrderHashHex(signedOrderRight), ); - expect(expectedOrderFilledAmountRight, 'Checking inital state of right order').to.be.bignumber.equal( - orderTakerAssetFilledAmountRight, + expect(orderTakerAssetFilledAmountRight, 'Checking inital state of right order').to.be.bignumber.equal( + expectedOrderFilledAmountRight, ); } /// @dev Asserts the exchange state against the expected amounts transferred by from matching orders. @@ -268,19 +259,17 @@ export class MatchOrderTester { orderHashUtils.getOrderHashHex(signedOrderLeft), ); amountBoughtByLeftMaker = amountBoughtByLeftMaker.minus(initialLeftOrderFilledAmount); - expect( + expect(amountBoughtByLeftMaker, 'Checking exchange state for left order').to.be.bignumber.equal( expectedTransferAmounts.amountBoughtByLeftMaker, - 'Checking exchange state for left order', - ).to.be.bignumber.equal(amountBoughtByLeftMaker); + ); // Assert state for right order: amount bought by right maker let amountBoughtByRightMaker = await this._exchangeWrapper.getTakerAssetFilledAmountAsync( orderHashUtils.getOrderHashHex(signedOrderRight), ); amountBoughtByRightMaker = amountBoughtByRightMaker.minus(initialRightOrderFilledAmount); - expect( + expect(amountBoughtByRightMaker, 'Checking exchange state for right order').to.be.bignumber.equal( expectedTransferAmounts.amountBoughtByRightMaker, - 'Checking exchange state for right order', - ).to.be.bignumber.equal(amountBoughtByRightMaker); + ); // Assert left order status const maxAmountBoughtByLeftMaker = signedOrderLeft.takerAssetAmount.minus(initialLeftOrderFilledAmount); const leftOrderInfo: OrderInfo = await this._exchangeWrapper.getOrderInfoAsync(signedOrderLeft); From f8e565bc06b48f4e59b9a246fdf1e4b16245bd83 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 23 Aug 2018 16:07:13 -0700 Subject: [PATCH 084/120] Tests for matchOrders edge cases --- .../contracts/test/exchange/match_orders.ts | 84 ++++++++++++++++--- 1 file changed, 71 insertions(+), 13 deletions(-) diff --git a/packages/contracts/test/exchange/match_orders.ts b/packages/contracts/test/exchange/match_orders.ts index 95d4b75023..95a6fff338 100644 --- a/packages/contracts/test/exchange/match_orders.ts +++ b/packages/contracts/test/exchange/match_orders.ts @@ -173,8 +173,7 @@ describe.only('matchOrders', () => { erc721TokenIdsByOwner = await erc721Wrapper.getBalancesAsync(); }); - /* - it.only('should transfer the correct amounts when orders completely fill each other', async () => { + it('Should give right maker a better price when correct price is not integral', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ makerAddress: makerAddressLeft, @@ -190,6 +189,23 @@ describe.only('matchOrders', () => { takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(3000), 0), feeRecipientAddress: feeRecipientAddressRight, }); + // Note: + // The maker/taker fee percentage paid on the right order differs because + // they received different sale prices. + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2000), 0), + amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1001), 0), + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Right Maker + amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1001), 0), + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(300), 0), // @TODO: Update once rounding up is implemented + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10.01), 16), // @TODO: Update once rounding up is implemented + // Taker + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1700), 0), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // @TODO: Update once rounding up is implemented + }; // Match signedOrderLeft with signedOrderRight await matchOrderTester.matchOrdersAndAssertEffectsAsync( signedOrderLeft, @@ -197,17 +213,55 @@ describe.only('matchOrders', () => { takerAddress, erc20BalancesByOwner, erc721TokenIdsByOwner, + expectedTransferAmounts, ); - // // Verify left order was fully filled - // const leftOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderLeft); - // expect(leftOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); - // Verify right order was fully filled - // const rightOrderInfo: OrderInfo = await exchangeWrapper.getOrderInfoAsync(signedOrderRight); - // expect(rightOrderInfo.orderStatus as OrderStatus).to.be.equal(OrderStatus.FULLY_FILLED); }); - */ - it('Jacobs Example', async () => { + it('Should give left maker a better price when correct price is non-integral', async () => { + // Create orders to match + const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ + makerAddress: makerAddressLeft, + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(12), 0), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(97), 0), + feeRecipientAddress: feeRecipientAddressLeft, + }); + const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({ + makerAddress: makerAddressRight, + makerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress), + takerAssetData: assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress), + makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0), + takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0), + feeRecipientAddress: feeRecipientAddressRight, + }); + // Note: + // The maker/taker fee percentage paid on the left order differs because + // they received different sale prices. + const expectedTransferAmounts = { + // Left Maker + amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(11), 0), + amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0), + feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber('91.6666666666666666'), 16), // 91.6% + // Right Maker + amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(89), 0), + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + // Taker + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 0), + feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber('91.7525773195876288'), 16), // 91.75% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% + }; + // Match signedOrderLeft with signedOrderRight + await matchOrderTester.matchOrdersAndAssertEffectsAsync( + signedOrderLeft, + signedOrderRight, + takerAddress, + erc20BalancesByOwner, + erc721TokenIdsByOwner, + expectedTransferAmounts, + ); + }); + + it('Should transfer correct amounts when right order fill amount deviates from amount derived by `Exchange.fillOrder`', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ makerAddress: makerAddressLeft, @@ -230,13 +284,17 @@ describe.only('matchOrders', () => { amountBoughtByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 0), feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% // Right Maker + // Note: + // For order [4,2] valid fill amounts through `Exchange.fillOrder` would be [2, 1] or [4, 2] + // In this case we have fill amounts of [3, 1] which is attainable through + // `Exchange.matchOrders` but not `Exchange.fillOrder` amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 0), - amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0), - feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 16), // 75% + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0), // @TODO: Update once rounding up is implemented + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 16), // 75% (@TODO: Update once rounding up is implemented) // Taker amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(9), 0), feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% - feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 16), // 50% + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 16), // 50% (@TODO: Update once rounding up is implemented) }; // Match signedOrderLeft with signedOrderRight await matchOrderTester.matchOrdersAndAssertEffectsAsync( From 81dc893d1d07e5a8485fb40aa247428cda79d788 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 23 Aug 2018 16:07:39 -0700 Subject: [PATCH 085/120] Removed a redundant comment from matchOrders --- .../src/2.0.0/protocol/Exchange/MixinMatchOrders.sol | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol index b3f376eb8d..d932c743f6 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol @@ -165,11 +165,6 @@ contract MixinMatchOrders is pure returns (LibFillResults.MatchedFillResults memory matchedFillResults) { - // We settle orders at the exchange rate of the right order. - // The amount saved by the left maker goes to the taker. - // Either the left or right order will be fully filled; possibly both. - // The left order is fully filled iff the right order can sell more than left can buy. - // Derive maker asset amounts for left & right orders, given store taker assert amounts uint256 leftTakerAssetAmountRemaining = safeSub(leftOrder.takerAssetAmount, leftOrderTakerAssetFilledAmount); uint256 leftMakerAssetAmountRemaining = getPartialAmountFloor( @@ -184,6 +179,7 @@ contract MixinMatchOrders is rightTakerAssetAmountRemaining ); + // Calculate fill results for maker and taker assets if (leftTakerAssetAmountRemaining >= rightMakerAssetAmountRemaining) { // Case 1: Right order is fully filled: maximally fill right matchedFillResults.right.makerAssetFilledAmount = rightMakerAssetAmountRemaining; From 6833e243b7b3aa6991f286e07666c6229313a046 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 23 Aug 2018 16:14:51 -0700 Subject: [PATCH 086/120] Addressed linter errors in match order tesster --- packages/contracts/test/utils/match_order_tester.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/packages/contracts/test/utils/match_order_tester.ts b/packages/contracts/test/utils/match_order_tester.ts index e6347a962a..4d27fc6309 100644 --- a/packages/contracts/test/utils/match_order_tester.ts +++ b/packages/contracts/test/utils/match_order_tester.ts @@ -161,16 +161,9 @@ export class MatchOrderTester { erc20BalancesByOwner: ERC20BalancesByOwner, erc721TokenIdsByOwner: ERC721TokenIdsByOwner, expectedTransferAmounts: TransferAmounts, - initialLeftOrderFilledAmount?: BigNumber, - initialRightOrderFilledAmount?: BigNumber, + initialLeftOrderFilledAmount: BigNumber = new BigNumber(0), + initialRightOrderFilledAmount: BigNumber = new BigNumber(0), ): Promise<[ERC20BalancesByOwner, ERC721TokenIdsByOwner]> { - // Assign default values to optional parameters if undefined - if (initialLeftOrderFilledAmount === undefined) { - initialLeftOrderFilledAmount = new BigNumber(0); - } - if (initialRightOrderFilledAmount === undefined) { - initialRightOrderFilledAmount = new BigNumber(0); - } // Assert initial order states await this._assertInitialOrderStatesAsync( signedOrderLeft, From a93f95c55ea43bc89d0633190590865d9723b2f9 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 23 Aug 2018 16:16:01 -0700 Subject: [PATCH 087/120] Wording in MixinMatchOrders --- .../src/2.0.0/protocol/Exchange/MixinMatchOrders.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol index d932c743f6..a0696c6168 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol @@ -181,7 +181,7 @@ contract MixinMatchOrders is // Calculate fill results for maker and taker assets if (leftTakerAssetAmountRemaining >= rightMakerAssetAmountRemaining) { - // Case 1: Right order is fully filled: maximally fill right + // Case 1: Right order is fully filled matchedFillResults.right.makerAssetFilledAmount = rightMakerAssetAmountRemaining; matchedFillResults.right.takerAssetFilledAmount = rightTakerAssetAmountRemaining; matchedFillResults.left.makerAssetFilledAmount = getPartialAmountFloor( @@ -191,7 +191,7 @@ contract MixinMatchOrders is ); matchedFillResults.left.takerAssetFilledAmount = matchedFillResults.right.makerAssetFilledAmount; } else { - // Case 2: Left order is fully filled: maximall fill left + // Case 2: Left order is fully filled matchedFillResults.left.makerAssetFilledAmount = leftMakerAssetAmountRemaining; matchedFillResults.left.takerAssetFilledAmount = leftTakerAssetAmountRemaining; matchedFillResults.right.makerAssetFilledAmount = matchedFillResults.left.takerAssetFilledAmount; From 0a6f107243eb7df309766cc83942e667ce28e858 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Thu, 23 Aug 2018 16:28:03 -0700 Subject: [PATCH 088/120] Added temporary @todo to MixinMatchOrders --- .../src/2.0.0/protocol/Exchange/MixinMatchOrders.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol index a0696c6168..8f289ee85a 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol @@ -209,24 +209,24 @@ contract MixinMatchOrders is ); // Compute fees for left order - matchedFillResults.left.makerFeePaid = getPartialAmount( + matchedFillResults.left.makerFeePaid = getPartialAmountFloor( matchedFillResults.left.makerAssetFilledAmount, leftOrder.makerAssetAmount, leftOrder.makerFee ); - matchedFillResults.left.takerFeePaid = getPartialAmount( + matchedFillResults.left.takerFeePaid = getPartialAmountFloor( matchedFillResults.left.takerAssetFilledAmount, leftOrder.takerAssetAmount, leftOrder.takerFee ); // Compute fees for right order - matchedFillResults.right.makerFeePaid = getPartialAmount( + matchedFillResults.right.makerFeePaid = getPartialAmountFloor( matchedFillResults.right.makerAssetFilledAmount, rightOrder.makerAssetAmount, rightOrder.makerFee ); - matchedFillResults.right.takerFeePaid = getPartialAmount( + matchedFillResults.right.takerFeePaid = getPartialAmountFloor( matchedFillResults.right.takerAssetFilledAmount, rightOrder.takerAssetAmount, rightOrder.takerFee From 1c7ba6a31533b3202be7a464452b14aa58a0337b Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Fri, 24 Aug 2018 17:17:52 -0700 Subject: [PATCH 089/120] Extract only `fill` event logs --- packages/contracts/test/utils/match_order_tester.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/contracts/test/utils/match_order_tester.ts b/packages/contracts/test/utils/match_order_tester.ts index 4d27fc6309..e0c55b8349 100644 --- a/packages/contracts/test/utils/match_order_tester.ts +++ b/packages/contracts/test/utils/match_order_tester.ts @@ -42,10 +42,11 @@ export class MatchOrderTester { takerAddress: string, expectedTransferAmounts: TransferAmounts, ): Promise { - // Should have two logs -- one for each order. - expect(transactionReceipt.logs.length, 'Checking number of logs').to.be.equal(2); + // Should have two fill event logs -- one for each order. + const transactionFillLogs = _.filter(transactionReceipt.logs, ['event', 'Fill']); + expect(transactionFillLogs.length, 'Checking number of logs').to.be.equal(2); // First log is for left fill - const leftLog = (transactionReceipt.logs[0] as any).args as LoggedTransferAmounts; + const leftLog = (transactionFillLogs[0] as any).args as LoggedTransferAmounts; expect(leftLog.makerAddress, 'Checking logged maker address of left order').to.be.equal( signedOrderLeft.makerAddress, ); @@ -55,7 +56,7 @@ export class MatchOrderTester { const feePaidByLeftMaker = new BigNumber(leftLog.makerFeePaid); const feePaidByTakerLeft = new BigNumber(leftLog.takerFeePaid); // Second log is for right fill - const rightLog = (transactionReceipt.logs[1] as any).args as LoggedTransferAmounts; + const rightLog = (transactionFillLogs[1] as any).args as LoggedTransferAmounts; expect(rightLog.makerAddress, 'Checking logged maker address of right order').to.be.equal( signedOrderRight.makerAddress, ); From c7a7ae7e18bb6d0f5f148a37b63dccf2e485cc6f Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Fri, 24 Aug 2018 17:19:28 -0700 Subject: [PATCH 090/120] Give right maker better price when correct value is not integral --- .../contracts/test/exchange/match_orders.ts | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/contracts/test/exchange/match_orders.ts b/packages/contracts/test/exchange/match_orders.ts index 95a6fff338..2e6e9410aa 100644 --- a/packages/contracts/test/exchange/match_orders.ts +++ b/packages/contracts/test/exchange/match_orders.ts @@ -191,7 +191,8 @@ describe.only('matchOrders', () => { }); // Note: // The maker/taker fee percentage paid on the right order differs because - // they received different sale prices. + // they received different sale prices. Similarly, the right maker pays a + // slightly higher lower than the right taker. const expectedTransferAmounts = { // Left Maker amountSoldByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2000), 0), @@ -199,12 +200,12 @@ describe.only('matchOrders', () => { feePaidByLeftMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% // Right Maker amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1001), 0), - amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(300), 0), // @TODO: Update once rounding up is implemented - feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10.01), 16), // @TODO: Update once rounding up is implemented + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(301), 0), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(10.01), 16), // 10.01% // Taker - amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1700), 0), + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1699), 0), feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% - feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 16), // @TODO: Update once rounding up is implemented + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber('10.0333333333333333'), 16), // 10.03% }; // Match signedOrderLeft with signedOrderRight await matchOrderTester.matchOrdersAndAssertEffectsAsync( @@ -217,7 +218,7 @@ describe.only('matchOrders', () => { ); }); - it('Should give left maker a better price when correct price is non-integral', async () => { + it('Should give left maker a better price when correct price is not integral', async () => { // Create orders to match const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({ makerAddress: makerAddressLeft, @@ -288,13 +289,16 @@ describe.only('matchOrders', () => { // For order [4,2] valid fill amounts through `Exchange.fillOrder` would be [2, 1] or [4, 2] // In this case we have fill amounts of [3, 1] which is attainable through // `Exchange.matchOrders` but not `Exchange.fillOrder` + // Note: + // The right maker fee differs from the right taker fee because their exchange rate differs. + // The right maker always receives the better exchange and fee price. amountSoldByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 0), - amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 0), // @TODO: Update once rounding up is implemented - feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 16), // 75% (@TODO: Update once rounding up is implemented) + amountBoughtByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 0), + feePaidByRightMaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(75), 16), // 75% // Taker - amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(9), 0), + amountReceivedByTaker: Web3Wrapper.toBaseUnitAmount(new BigNumber(8), 0), feePaidByTakerLeft: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% - feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), 16), // 50% (@TODO: Update once rounding up is implemented) + feePaidByTakerRight: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 16), // 100% }; // Match signedOrderLeft with signedOrderRight await matchOrderTester.matchOrdersAndAssertEffectsAsync( From 287830d6e01a919bcb4ac4ccec4173cdbdcf9470 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Fri, 24 Aug 2018 17:29:31 -0700 Subject: [PATCH 091/120] Run all tests --- packages/contracts/test/exchange/match_orders.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contracts/test/exchange/match_orders.ts b/packages/contracts/test/exchange/match_orders.ts index 2e6e9410aa..8732e20bae 100644 --- a/packages/contracts/test/exchange/match_orders.ts +++ b/packages/contracts/test/exchange/match_orders.ts @@ -24,7 +24,7 @@ import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper'; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); -describe.only('matchOrders', () => { +describe('matchOrders', () => { let makerAddressLeft: string; let makerAddressRight: string; let owner: string; From ec2e726be0a653465d3c83e640aa4c1556a0f10f Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Fri, 24 Aug 2018 18:09:32 -0700 Subject: [PATCH 092/120] Rephrased some of the math in MixinMatchOrders to improve readability --- .../src/2.0.0/protocol/Exchange/MixinMatchOrders.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol index 8f289ee85a..226a1bfb6b 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol @@ -184,12 +184,12 @@ contract MixinMatchOrders is // Case 1: Right order is fully filled matchedFillResults.right.makerAssetFilledAmount = rightMakerAssetAmountRemaining; matchedFillResults.right.takerAssetFilledAmount = rightTakerAssetAmountRemaining; + matchedFillResults.left.takerAssetFilledAmount = matchedFillResults.right.makerAssetFilledAmount; matchedFillResults.left.makerAssetFilledAmount = getPartialAmountFloor( leftOrder.makerAssetAmount, leftOrder.takerAssetAmount, - matchedFillResults.right.makerAssetFilledAmount + matchedFillResults.left.takerAssetFilledAmount ); - matchedFillResults.left.takerAssetFilledAmount = matchedFillResults.right.makerAssetFilledAmount; } else { // Case 2: Left order is fully filled matchedFillResults.left.makerAssetFilledAmount = leftMakerAssetAmountRemaining; @@ -198,7 +198,7 @@ contract MixinMatchOrders is matchedFillResults.right.takerAssetFilledAmount = getPartialAmountCeil( rightOrder.takerAssetAmount, rightOrder.makerAssetAmount, - matchedFillResults.left.takerAssetFilledAmount + matchedFillResults.right.makerAssetFilledAmount ); } From 878db3b84993d7c9724c0ed8591493a4e2b6cc94 Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Fri, 24 Aug 2018 18:48:29 -0700 Subject: [PATCH 093/120] Added comments to order matching --- .../2.0.0/protocol/Exchange/MixinMatchOrders.sol | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol index 226a1bfb6b..4b8360c235 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinMatchOrders.sol @@ -179,12 +179,22 @@ contract MixinMatchOrders is rightTakerAssetAmountRemaining ); - // Calculate fill results for maker and taker assets + // Calculate fill results for maker and taker assets: at least one order will be fully filled. + // The maximum amount the left maker can buy is `leftTakerAssetAmountRemaining` + // The maximum amount the right maker can sell is `rightMakerAssetAmountRemaining` + // We have two distinct cases for calculating the fill results: + // Case 1. + // If the left maker can buy more than the right maker can sell, then only the right order is fully filled. + // If the left maker can buy exactly what the right maker can sell, then both orders are fully filled. + // Case 2. + // If the left maker cannot buy more than the right maker can sell, then only the left order is fully filled. if (leftTakerAssetAmountRemaining >= rightMakerAssetAmountRemaining) { // Case 1: Right order is fully filled matchedFillResults.right.makerAssetFilledAmount = rightMakerAssetAmountRemaining; matchedFillResults.right.takerAssetFilledAmount = rightTakerAssetAmountRemaining; matchedFillResults.left.takerAssetFilledAmount = matchedFillResults.right.makerAssetFilledAmount; + // Round down to ensure the maker's exchange rate does not exceed the price specified by the order. + // We favor the maker when the exchange rate must be rounded. matchedFillResults.left.makerAssetFilledAmount = getPartialAmountFloor( leftOrder.makerAssetAmount, leftOrder.takerAssetAmount, @@ -195,6 +205,8 @@ contract MixinMatchOrders is matchedFillResults.left.makerAssetFilledAmount = leftMakerAssetAmountRemaining; matchedFillResults.left.takerAssetFilledAmount = leftTakerAssetAmountRemaining; matchedFillResults.right.makerAssetFilledAmount = matchedFillResults.left.takerAssetFilledAmount; + // Round up to ensure the maker's exchange rate does not exceed the price specified by the order. + // We favor the maker when the exchange rate must be rounded. matchedFillResults.right.takerAssetFilledAmount = getPartialAmountCeil( rightOrder.takerAssetAmount, rightOrder.makerAssetAmount, From 3ac182ee914080e513b007758c001642b6d07e3f Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 26 Aug 2018 17:12:13 +0100 Subject: [PATCH 094/120] Fix file path to main and types in package.json --- packages/0x.js/CHANGELOG.json | 9 +++++++++ packages/0x.js/package.json | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/0x.js/CHANGELOG.json b/packages/0x.js/CHANGELOG.json index 3469389589..f242b5496d 100644 --- a/packages/0x.js/CHANGELOG.json +++ b/packages/0x.js/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "1.0.1-rc.5", + "changes": [ + { + "note": + "Fix `main` and `types` package.json entries so that they point to the new location of index.d.ts and index.js" + } + ] + }, { "version": "1.0.1-rc.4", "changes": [ diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json index b5cb6c7e46..4843424228 100644 --- a/packages/0x.js/package.json +++ b/packages/0x.js/package.json @@ -12,8 +12,8 @@ "tokens", "exchange" ], - "main": "lib/src/index.js", - "types": "lib/src/index.d.ts", + "main": "lib/index.js", + "types": "lib/index.d.ts", "scripts": { "watch_without_deps": "tsc -w", "build": "yarn build:all", From 35ba3e6f7c118b0cd199fd062d3923aa215acc6a Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 26 Aug 2018 17:35:17 +0100 Subject: [PATCH 095/120] Bumop 0x.js version --- packages/0x.js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json index 4843424228..5d4a6ed0e7 100644 --- a/packages/0x.js/package.json +++ b/packages/0x.js/package.json @@ -1,6 +1,6 @@ { "name": "0x.js", - "version": "1.0.1-rc.4", + "version": "1.0.1-rc.5", "engines": { "node": ">=6.12" }, From c4dadf4bfd5b955221d5e8cd5e702720efd7873b Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 26 Aug 2018 17:49:06 +0100 Subject: [PATCH 096/120] Combine imports --- .../src/contract_wrappers/contract_wrapper.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts index 490a6c50a0..ba36afea1f 100644 --- a/packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts @@ -1,7 +1,14 @@ import { AbiDecoder, intervalUtils, logUtils } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; -import { ContractArtifact } from 'ethereum-types'; -import { BlockParamLiteral, ContractAbi, FilterObject, LogEntry, LogWithDecodedArgs, RawLog } from 'ethereum-types'; +import { + BlockParamLiteral, + ContractAbi, + ContractArtifact, + FilterObject, + LogEntry, + LogWithDecodedArgs, + RawLog, +} from 'ethereum-types'; import { Block, BlockAndLogStreamer, Log } from 'ethereumjs-blockstream'; import * as _ from 'lodash'; From 09d64961359cb63ff0bf1496b5f30840f030d8db Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 26 Aug 2018 20:53:21 +0100 Subject: [PATCH 097/120] Change exit code to failure --- packages/monorepo-scripts/src/test_installation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/monorepo-scripts/src/test_installation.ts b/packages/monorepo-scripts/src/test_installation.ts index 87c4ad1d79..e626fb8913 100644 --- a/packages/monorepo-scripts/src/test_installation.ts +++ b/packages/monorepo-scripts/src/test_installation.ts @@ -85,7 +85,7 @@ function logIfDefined(x: any): void { logIfDefined(packageError.error.stdout); logIfDefined(packageError.error.stack); }); - process.exit(0); + process.exit(1); } })().catch(err => { utils.log(`Unexpected error: ${err.message}`); From 40cf805e5ec0b49b6b193bad941b97049864ba0b Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 26 Aug 2018 20:54:15 +0100 Subject: [PATCH 098/120] Also use failure exit code if unexpected error occurs --- packages/monorepo-scripts/src/test_installation.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/monorepo-scripts/src/test_installation.ts b/packages/monorepo-scripts/src/test_installation.ts index e626fb8913..10709af252 100644 --- a/packages/monorepo-scripts/src/test_installation.ts +++ b/packages/monorepo-scripts/src/test_installation.ts @@ -86,10 +86,12 @@ function logIfDefined(x: any): void { logIfDefined(packageError.error.stack); }); process.exit(1); + } else { + process.exit(0); } })().catch(err => { utils.log(`Unexpected error: ${err.message}`); - process.exit(0); + process.exit(1); }); async function testInstallPackageAsync( From 52fde551e47c774c115c6b6fae085025dc742196 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 26 Aug 2018 21:16:32 +0100 Subject: [PATCH 099/120] Remove check since this method is now used in multiple places --- packages/monorepo-scripts/src/utils/changelog_utils.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/monorepo-scripts/src/utils/changelog_utils.ts b/packages/monorepo-scripts/src/utils/changelog_utils.ts index 4781b3b7d1..8058d222bd 100644 --- a/packages/monorepo-scripts/src/utils/changelog_utils.ts +++ b/packages/monorepo-scripts/src/utils/changelog_utils.ts @@ -19,11 +19,6 @@ CHANGELOG export const changelogUtils = { getChangelogMdTitle(versionChangelog: VersionChangelog): string { - if (_.isUndefined(versionChangelog.timestamp)) { - throw new Error( - 'All CHANGELOG.json entries must be updated to include a timestamp before generating their MD version', - ); - } const date = moment(`${versionChangelog.timestamp}`, 'X').format('MMMM D, YYYY'); const title = `\n## v${versionChangelog.version} - _${date}_\n\n`; return title; From db54588d055cc2cc6b7f1a99c7438f6fd2053765 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 26 Aug 2018 22:00:51 +0100 Subject: [PATCH 100/120] Add BlockParamLiteral to template --- packages/contract_templates/contract.handlebars | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contract_templates/contract.handlebars b/packages/contract_templates/contract.handlebars index 5c36a765d6..466893aa70 100644 --- a/packages/contract_templates/contract.handlebars +++ b/packages/contract_templates/contract.handlebars @@ -2,7 +2,7 @@ // tslint:disable:no-unused-variable // tslint:disable:no-unbound-method import { BaseContract } from '@0xproject/base-contract'; -import { BlockParam, CallData, ContractAbi, ContractArtifact, DecodedLogArgs, MethodAbi, Provider, TxData, TxDataPayable } from 'ethereum-types'; +import { BlockParam, BlockParamLiteral, CallData, ContractAbi, ContractArtifact, DecodedLogArgs, MethodAbi, Provider, TxData, TxDataPayable } from 'ethereum-types'; import { BigNumber, classUtils, logUtils } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as ethers from 'ethers'; From 3a5c6ed00fb96488897fa95fbf267f71def24fc4 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 26 Aug 2018 23:05:04 +0100 Subject: [PATCH 101/120] Fix sra-spec `main` and `types` in package.json --- packages/sra-spec/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sra-spec/package.json b/packages/sra-spec/package.json index 706f9f0aa6..ccb7ccb717 100644 --- a/packages/sra-spec/package.json +++ b/packages/sra-spec/package.json @@ -5,8 +5,8 @@ "node": ">=6.12" }, "description": "Standard Relayer API Open API Spec", - "main": "lib/src/index.js", - "types": "lib/src/index.d.ts", + "main": "lib/index.js", + "types": "lib/index.d.ts", "scripts": { "serve": "redoc-cli serve lib/api.json --watch", "watch_without_deps": "run-p build-json:watch serve", From 6a6b424c86b507d4dbfe5821ef81e7f76b818ef9 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 26 Aug 2018 23:35:47 +0100 Subject: [PATCH 102/120] Move md files to lib folder during build --- packages/sra-spec/package.json | 4 +++- packages/sra-spec/src/md/index.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/sra-spec/package.json b/packages/sra-spec/package.json index ccb7ccb717..9a192d46f4 100644 --- a/packages/sra-spec/package.json +++ b/packages/sra-spec/package.json @@ -17,9 +17,10 @@ "coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info", "test:circleci": "yarn test:coverage", "clean": "shx rm -rf lib", - "build": "tsc && yarn build-json", + "build": "tsc && copy_md_files && yarn build-json", "build-json": "ts-node build_scripts/buildJson.ts", "build-json:watch": "chokidar 'src/**/*' -c 'yarn build-json' ", + "copy_md_files": "copyfiles -u 2 './src/md/**/*.md' ./lib/md", "deploy-site": "discharge deploy" }, "repository": { @@ -42,6 +43,7 @@ "@types/node": "^10.5.3", "chai": "^4.0.1", "chokidar-cli": "^1.2.0", + "copyfiles": "^2.0.0", "dirty-chai": "^2.0.1", "discharge": "^0.7.1", "mocha": "^4.0.1", diff --git a/packages/sra-spec/src/md/index.ts b/packages/sra-spec/src/md/index.ts index 076c3c45cc..0d1147aa0d 100644 --- a/packages/sra-spec/src/md/index.ts +++ b/packages/sra-spec/src/md/index.ts @@ -1,5 +1,5 @@ import { readFileSync } from 'fs'; export const md = { - introduction: readFileSync('src/md/introduction.md').toString(), + introduction: readFileSync('lib/md/introduction.md').toString(), }; From 41559c39b9b4fac9c512309f3271796bb9fb0fb0 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 26 Aug 2018 23:43:19 +0100 Subject: [PATCH 103/120] Fix command --- packages/sra-spec/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sra-spec/package.json b/packages/sra-spec/package.json index 9a192d46f4..f0820e136a 100644 --- a/packages/sra-spec/package.json +++ b/packages/sra-spec/package.json @@ -17,7 +17,7 @@ "coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info", "test:circleci": "yarn test:coverage", "clean": "shx rm -rf lib", - "build": "tsc && copy_md_files && yarn build-json", + "build": "tsc && yarn copy_md_files && yarn build-json", "build-json": "ts-node build_scripts/buildJson.ts", "build-json:watch": "chokidar 'src/**/*' -c 'yarn build-json' ", "copy_md_files": "copyfiles -u 2 './src/md/**/*.md' ./lib/md", From 7e9ba50502548c6c50ff8a402db416bf1dc9aac3 Mon Sep 17 00:00:00 2001 From: Jacob Evans Date: Mon, 27 Aug 2018 15:59:43 +1000 Subject: [PATCH 104/120] Issue #1025 BlockParam unroll BlockParam unrolls into number | BlockParamLiteral, though BlockParamLiteral does not get imported. This results in type build errors in downstream projects where tslint checks libs --- packages/contract_templates/contract.handlebars | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contract_templates/contract.handlebars b/packages/contract_templates/contract.handlebars index 5c36a765d6..466893aa70 100644 --- a/packages/contract_templates/contract.handlebars +++ b/packages/contract_templates/contract.handlebars @@ -2,7 +2,7 @@ // tslint:disable:no-unused-variable // tslint:disable:no-unbound-method import { BaseContract } from '@0xproject/base-contract'; -import { BlockParam, CallData, ContractAbi, ContractArtifact, DecodedLogArgs, MethodAbi, Provider, TxData, TxDataPayable } from 'ethereum-types'; +import { BlockParam, BlockParamLiteral, CallData, ContractAbi, ContractArtifact, DecodedLogArgs, MethodAbi, Provider, TxData, TxDataPayable } from 'ethereum-types'; import { BigNumber, classUtils, logUtils } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as ethers from 'ethers'; From 9fc8a6e214279cb156fa467fbada2b7d5368d616 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 27 Aug 2018 10:09:51 +0100 Subject: [PATCH 105/120] Try relative path --- packages/sra-spec/src/md/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sra-spec/src/md/index.ts b/packages/sra-spec/src/md/index.ts index 0d1147aa0d..076c3c45cc 100644 --- a/packages/sra-spec/src/md/index.ts +++ b/packages/sra-spec/src/md/index.ts @@ -1,5 +1,5 @@ import { readFileSync } from 'fs'; export const md = { - introduction: readFileSync('lib/md/introduction.md').toString(), + introduction: readFileSync('src/md/introduction.md').toString(), }; From 90c9e3496a6db59c39265d1974f766fed30c7877 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 27 Aug 2018 10:10:07 +0100 Subject: [PATCH 106/120] Actual relative path --- packages/sra-spec/src/md/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sra-spec/src/md/index.ts b/packages/sra-spec/src/md/index.ts index 076c3c45cc..d82e7061fb 100644 --- a/packages/sra-spec/src/md/index.ts +++ b/packages/sra-spec/src/md/index.ts @@ -1,5 +1,5 @@ import { readFileSync } from 'fs'; export const md = { - introduction: readFileSync('src/md/introduction.md').toString(), + introduction: readFileSync('introduction.md').toString(), }; From 38abeaed9cd2bfaad82db367a54fe35337d846ff Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 26 Aug 2018 23:05:04 +0100 Subject: [PATCH 107/120] Fix sra-spec `main` and `types` in package.json --- packages/sra-spec/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/sra-spec/package.json b/packages/sra-spec/package.json index 706f9f0aa6..ccb7ccb717 100644 --- a/packages/sra-spec/package.json +++ b/packages/sra-spec/package.json @@ -5,8 +5,8 @@ "node": ">=6.12" }, "description": "Standard Relayer API Open API Spec", - "main": "lib/src/index.js", - "types": "lib/src/index.d.ts", + "main": "lib/index.js", + "types": "lib/index.d.ts", "scripts": { "serve": "redoc-cli serve lib/api.json --watch", "watch_without_deps": "run-p build-json:watch serve", From e6cb2e0fcd33858d7775871807eb834f78cdc53d Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 26 Aug 2018 20:54:15 +0100 Subject: [PATCH 108/120] Change exit code to failure --- packages/monorepo-scripts/src/test_installation.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/monorepo-scripts/src/test_installation.ts b/packages/monorepo-scripts/src/test_installation.ts index 87c4ad1d79..10709af252 100644 --- a/packages/monorepo-scripts/src/test_installation.ts +++ b/packages/monorepo-scripts/src/test_installation.ts @@ -85,11 +85,13 @@ function logIfDefined(x: any): void { logIfDefined(packageError.error.stdout); logIfDefined(packageError.error.stack); }); + process.exit(1); + } else { process.exit(0); } })().catch(err => { utils.log(`Unexpected error: ${err.message}`); - process.exit(0); + process.exit(1); }); async function testInstallPackageAsync( From fffa96bba75df15965b0be8cc19a8e30a975a39c Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 26 Aug 2018 23:35:47 +0100 Subject: [PATCH 109/120] Move md files to lib folder during build --- packages/sra-spec/package.json | 4 +++- packages/sra-spec/src/md/index.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/sra-spec/package.json b/packages/sra-spec/package.json index ccb7ccb717..9a192d46f4 100644 --- a/packages/sra-spec/package.json +++ b/packages/sra-spec/package.json @@ -17,9 +17,10 @@ "coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info", "test:circleci": "yarn test:coverage", "clean": "shx rm -rf lib", - "build": "tsc && yarn build-json", + "build": "tsc && copy_md_files && yarn build-json", "build-json": "ts-node build_scripts/buildJson.ts", "build-json:watch": "chokidar 'src/**/*' -c 'yarn build-json' ", + "copy_md_files": "copyfiles -u 2 './src/md/**/*.md' ./lib/md", "deploy-site": "discharge deploy" }, "repository": { @@ -42,6 +43,7 @@ "@types/node": "^10.5.3", "chai": "^4.0.1", "chokidar-cli": "^1.2.0", + "copyfiles": "^2.0.0", "dirty-chai": "^2.0.1", "discharge": "^0.7.1", "mocha": "^4.0.1", diff --git a/packages/sra-spec/src/md/index.ts b/packages/sra-spec/src/md/index.ts index 076c3c45cc..0d1147aa0d 100644 --- a/packages/sra-spec/src/md/index.ts +++ b/packages/sra-spec/src/md/index.ts @@ -1,5 +1,5 @@ import { readFileSync } from 'fs'; export const md = { - introduction: readFileSync('src/md/introduction.md').toString(), + introduction: readFileSync('lib/md/introduction.md').toString(), }; From 82e51b878780a8d1001470c5408db0bbea53b59e Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 26 Aug 2018 23:43:19 +0100 Subject: [PATCH 110/120] Fix command --- packages/sra-spec/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sra-spec/package.json b/packages/sra-spec/package.json index 9a192d46f4..f0820e136a 100644 --- a/packages/sra-spec/package.json +++ b/packages/sra-spec/package.json @@ -17,7 +17,7 @@ "coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info", "test:circleci": "yarn test:coverage", "clean": "shx rm -rf lib", - "build": "tsc && copy_md_files && yarn build-json", + "build": "tsc && yarn copy_md_files && yarn build-json", "build-json": "ts-node build_scripts/buildJson.ts", "build-json:watch": "chokidar 'src/**/*' -c 'yarn build-json' ", "copy_md_files": "copyfiles -u 2 './src/md/**/*.md' ./lib/md", From 4ac43a9fd2d3cc75b4f9aed92d85f722f28d34cb Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 27 Aug 2018 10:38:06 +0100 Subject: [PATCH 111/120] Try relative to root dir --- packages/sra-spec/src/md/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/sra-spec/src/md/index.ts b/packages/sra-spec/src/md/index.ts index d82e7061fb..b32cba6f4c 100644 --- a/packages/sra-spec/src/md/index.ts +++ b/packages/sra-spec/src/md/index.ts @@ -1,5 +1,7 @@ import { readFileSync } from 'fs'; +console.log('DIR', __dirname); + export const md = { - introduction: readFileSync('introduction.md').toString(), + introduction: readFileSync('lib/md/introduction.md').toString(), }; From 77290c1efaa8a9e3ded93a4aea4849c16138e457 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 27 Aug 2018 10:51:38 +0100 Subject: [PATCH 112/120] Run yarn a second time if the first fails --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2f139841bd..373745a9f7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -22,7 +22,7 @@ jobs: command: sudo npm install --global yarn@1.9.4 - run: name: yarn - command: yarn --frozen-lockfile install + command: yarn --frozen-lockfile install || yarn --frozen-lockfile install - save_cache: name: Save Yarn Package Cache key: yarn-packages-{{ .Branch }}-{{ checksum "yarn.lock" }} From e4fc8a84145d14084c389f5c4e8307e84ebf0c41 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 27 Aug 2018 12:05:55 +0100 Subject: [PATCH 113/120] Use absolute path --- packages/sra-spec/src/md/index.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/sra-spec/src/md/index.ts b/packages/sra-spec/src/md/index.ts index b32cba6f4c..4e778e0736 100644 --- a/packages/sra-spec/src/md/index.ts +++ b/packages/sra-spec/src/md/index.ts @@ -1,7 +1,5 @@ import { readFileSync } from 'fs'; -console.log('DIR', __dirname); - export const md = { - introduction: readFileSync('lib/md/introduction.md').toString(), + introduction: readFileSync(`${__dirname}/introduction.md`).toString(), }; From 6174d9ebb78b46d98a3e994ae00eea05a92bc84a Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 27 Aug 2018 12:34:34 +0100 Subject: [PATCH 114/120] Fix typo --- packages/monorepo-scripts/src/test_installation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/monorepo-scripts/src/test_installation.ts b/packages/monorepo-scripts/src/test_installation.ts index 10709af252..be39b1878f 100644 --- a/packages/monorepo-scripts/src/test_installation.ts +++ b/packages/monorepo-scripts/src/test_installation.ts @@ -146,7 +146,7 @@ async function testInstallPackageAsync( const transpiledIndexFilePath = path.join(testDirectory, 'index.js'); utils.log(`Running test script with ${packageName} imported`); await execAsync(`node ${transpiledIndexFilePath}`); - utils.log(`Successfilly ran test script with ${packageName} imported`); + utils.log(`Successfully ran test script with ${packageName} imported`); } await rimrafAsync(testDirectory); } From bc4149683e2dda2b36c29cc81fadf1ae4de7d8b1 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 27 Aug 2018 12:39:10 +0100 Subject: [PATCH 115/120] Skip doc generation for local publishes since we test this in a separate CI test --- packages/monorepo-scripts/src/publish.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/monorepo-scripts/src/publish.ts b/packages/monorepo-scripts/src/publish.ts index 7e2e645369..646818c58d 100644 --- a/packages/monorepo-scripts/src/publish.ts +++ b/packages/monorepo-scripts/src/publish.ts @@ -74,9 +74,11 @@ async function confirmAsync(message: string): Promise { }); utils.log(`Calling 'lerna publish'...`); await lernaPublishAsync(packageToNextVersion); - const isStaging = false; - const shouldUploadDocs = !configs.IS_LOCAL_PUBLISH; - await generateAndUploadDocJsonsAsync(packagesWithDocs, isStaging, shouldUploadDocs); + if (!configs.IS_LOCAL_PUBLISH) { + const isStaging = false; + const shouldUploadDocs = true; + await generateAndUploadDocJsonsAsync(packagesWithDocs, isStaging, shouldUploadDocs); + } const isDryRun = configs.IS_LOCAL_PUBLISH; await publishReleaseNotesAsync(updatedPublicPackages, isDryRun); })().catch(err => { From b0c4eb8333930e355685588152ce027b01f014f6 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 27 Aug 2018 13:16:31 +0100 Subject: [PATCH 116/120] Update changelog files for RC packages --- packages/0x.js/CHANGELOG.json | 9 +++++++++ packages/connect/CHANGELOG.json | 9 +++++++++ packages/contract-wrappers/CHANGELOG.json | 9 +++++++++ packages/fill-scenarios/CHANGELOG.json | 9 +++++++++ packages/forwarder-helper/CHANGELOG.json | 9 +++++++++ packages/json-schemas/CHANGELOG.json | 9 +++++++++ packages/order-utils/CHANGELOG.json | 9 +++++++++ packages/order-watcher/CHANGELOG.json | 9 +++++++++ packages/sra-spec/CHANGELOG.json | 12 ++++++++++++ 9 files changed, 84 insertions(+) diff --git a/packages/0x.js/CHANGELOG.json b/packages/0x.js/CHANGELOG.json index f242b5496d..08075f70e4 100644 --- a/packages/0x.js/CHANGELOG.json +++ b/packages/0x.js/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "1.0.1-rc.6", + "changes": [ + { + "note": + "Fix missing `BlockParamLiteral` type import issue" + } + ] + }, { "version": "1.0.1-rc.5", "changes": [ diff --git a/packages/connect/CHANGELOG.json b/packages/connect/CHANGELOG.json index 6cf679b34a..89b1fb7284 100644 --- a/packages/connect/CHANGELOG.json +++ b/packages/connect/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "2.0.0-rc.2", + "changes": [ + { + "note": + "Dependencies updated" + } + ] + }, { "version": "2.0.0-rc.1", "changes": [ diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index 3809ad098e..02d28e68a1 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "1.0.1-rc.5", + "changes": [ + { + "note": + "Fix missing `BlockParamLiteral` type import issue" + } + ] + }, { "version": "1.0.1-rc.4", "changes": [ diff --git a/packages/fill-scenarios/CHANGELOG.json b/packages/fill-scenarios/CHANGELOG.json index 481273fc4c..be739873e1 100644 --- a/packages/fill-scenarios/CHANGELOG.json +++ b/packages/fill-scenarios/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "1.0.1-rc.5", + "changes": [ + { + "note": + "Dependencies updated" + } + ] + }, { "version": "1.0.1-rc.4", "changes": [ diff --git a/packages/forwarder-helper/CHANGELOG.json b/packages/forwarder-helper/CHANGELOG.json index b99a98b931..6c73051461 100644 --- a/packages/forwarder-helper/CHANGELOG.json +++ b/packages/forwarder-helper/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "1.0.1-rc.2", + "changes": [ + { + "note": + "Dependencies updated" + } + ] + }, { "version": "1.0.1-rc.1", "changes": [ diff --git a/packages/json-schemas/CHANGELOG.json b/packages/json-schemas/CHANGELOG.json index b17267414f..caaf881871 100644 --- a/packages/json-schemas/CHANGELOG.json +++ b/packages/json-schemas/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "1.0.1-rc.6", + "changes": [ + { + "note": + "Dependencies updated" + } + ] + }, { "version": "1.0.1-rc.5", "changes": [ diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json index d18bf51edb..a25a6a82ac 100644 --- a/packages/order-utils/CHANGELOG.json +++ b/packages/order-utils/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "1.0.1-rc.6", + "changes": [ + { + "note": + "Fix missing `BlockParamLiteral` type import issue" + } + ] + }, { "version": "1.0.1-rc.5", "changes": [ diff --git a/packages/order-watcher/CHANGELOG.json b/packages/order-watcher/CHANGELOG.json index fe38e21750..5529bfa9ee 100644 --- a/packages/order-watcher/CHANGELOG.json +++ b/packages/order-watcher/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "version": "1.0.1-rc.5", + "changes": [ + { + "note": + "Fix missing `BlockParamLiteral` type import issue" + } + ] + }, { "version": "1.0.1-rc.4", "changes": [ diff --git a/packages/sra-spec/CHANGELOG.json b/packages/sra-spec/CHANGELOG.json index 8467f3c681..14830eb052 100644 --- a/packages/sra-spec/CHANGELOG.json +++ b/packages/sra-spec/CHANGELOG.json @@ -1,4 +1,16 @@ [ + { + "version": "1.0.1-rc.6", + "changes": [ + { + "note": + "Fix `main` and `types` package.json entries so that they point to the new location of index.d.ts and index.js" + }, + { + "note": "Fix relative path to introduction MD file" + } + ] + }, { "version": "1.0.1-rc.5", "changes": [ From cd08a9c1218fa7c4819e31248e50da2a4f45ee36 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 27 Aug 2018 13:43:29 +0100 Subject: [PATCH 117/120] Fix prettier --- packages/0x.js/CHANGELOG.json | 3 +-- packages/connect/CHANGELOG.json | 3 +-- packages/contract-wrappers/CHANGELOG.json | 3 +-- packages/fill-scenarios/CHANGELOG.json | 3 +-- packages/forwarder-helper/CHANGELOG.json | 3 +-- packages/json-schemas/CHANGELOG.json | 3 +-- packages/order-utils/CHANGELOG.json | 3 +-- packages/order-watcher/CHANGELOG.json | 3 +-- 8 files changed, 8 insertions(+), 16 deletions(-) diff --git a/packages/0x.js/CHANGELOG.json b/packages/0x.js/CHANGELOG.json index 08075f70e4..63ef2fb5cb 100644 --- a/packages/0x.js/CHANGELOG.json +++ b/packages/0x.js/CHANGELOG.json @@ -3,8 +3,7 @@ "version": "1.0.1-rc.6", "changes": [ { - "note": - "Fix missing `BlockParamLiteral` type import issue" + "note": "Fix missing `BlockParamLiteral` type import issue" } ] }, diff --git a/packages/connect/CHANGELOG.json b/packages/connect/CHANGELOG.json index 89b1fb7284..9d2679abf3 100644 --- a/packages/connect/CHANGELOG.json +++ b/packages/connect/CHANGELOG.json @@ -3,8 +3,7 @@ "version": "2.0.0-rc.2", "changes": [ { - "note": - "Dependencies updated" + "note": "Dependencies updated" } ] }, diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index 02d28e68a1..2e159961b3 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -3,8 +3,7 @@ "version": "1.0.1-rc.5", "changes": [ { - "note": - "Fix missing `BlockParamLiteral` type import issue" + "note": "Fix missing `BlockParamLiteral` type import issue" } ] }, diff --git a/packages/fill-scenarios/CHANGELOG.json b/packages/fill-scenarios/CHANGELOG.json index be739873e1..e3dba02967 100644 --- a/packages/fill-scenarios/CHANGELOG.json +++ b/packages/fill-scenarios/CHANGELOG.json @@ -3,8 +3,7 @@ "version": "1.0.1-rc.5", "changes": [ { - "note": - "Dependencies updated" + "note": "Dependencies updated" } ] }, diff --git a/packages/forwarder-helper/CHANGELOG.json b/packages/forwarder-helper/CHANGELOG.json index 6c73051461..e187dc6be2 100644 --- a/packages/forwarder-helper/CHANGELOG.json +++ b/packages/forwarder-helper/CHANGELOG.json @@ -3,8 +3,7 @@ "version": "1.0.1-rc.2", "changes": [ { - "note": - "Dependencies updated" + "note": "Dependencies updated" } ] }, diff --git a/packages/json-schemas/CHANGELOG.json b/packages/json-schemas/CHANGELOG.json index caaf881871..205c663fc4 100644 --- a/packages/json-schemas/CHANGELOG.json +++ b/packages/json-schemas/CHANGELOG.json @@ -3,8 +3,7 @@ "version": "1.0.1-rc.6", "changes": [ { - "note": - "Dependencies updated" + "note": "Dependencies updated" } ] }, diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json index a25a6a82ac..a531dd3ae2 100644 --- a/packages/order-utils/CHANGELOG.json +++ b/packages/order-utils/CHANGELOG.json @@ -3,8 +3,7 @@ "version": "1.0.1-rc.6", "changes": [ { - "note": - "Fix missing `BlockParamLiteral` type import issue" + "note": "Fix missing `BlockParamLiteral` type import issue" } ] }, diff --git a/packages/order-watcher/CHANGELOG.json b/packages/order-watcher/CHANGELOG.json index 5529bfa9ee..445f56e177 100644 --- a/packages/order-watcher/CHANGELOG.json +++ b/packages/order-watcher/CHANGELOG.json @@ -3,8 +3,7 @@ "version": "1.0.1-rc.5", "changes": [ { - "note": - "Fix missing `BlockParamLiteral` type import issue" + "note": "Fix missing `BlockParamLiteral` type import issue" } ] }, From 4475fefd07cac0ca166d31526edf4738cca1f16c Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 27 Aug 2018 14:47:56 +0100 Subject: [PATCH 118/120] Updated CHANGELOGS --- packages/0x.js/CHANGELOG.json | 3 ++- packages/0x.js/CHANGELOG.md | 8 ++++++++ packages/abi-gen/CHANGELOG.json | 9 +++++++++ packages/abi-gen/CHANGELOG.md | 4 ++++ packages/assert/CHANGELOG.json | 9 +++++++++ packages/assert/CHANGELOG.md | 4 ++++ packages/base-contract/CHANGELOG.json | 9 +++++++++ packages/base-contract/CHANGELOG.md | 4 ++++ packages/connect/CHANGELOG.json | 3 ++- packages/connect/CHANGELOG.md | 4 ++++ packages/contract-wrappers/CHANGELOG.json | 3 ++- packages/contract-wrappers/CHANGELOG.md | 4 ++++ packages/dev-utils/CHANGELOG.json | 9 +++++++++ packages/dev-utils/CHANGELOG.md | 4 ++++ packages/fill-scenarios/CHANGELOG.json | 3 ++- packages/fill-scenarios/CHANGELOG.md | 4 ++++ packages/forwarder-helper/CHANGELOG.json | 3 ++- packages/forwarder-helper/CHANGELOG.md | 4 ++++ packages/json-schemas/CHANGELOG.json | 3 ++- packages/json-schemas/CHANGELOG.md | 4 ++++ packages/migrations/CHANGELOG.json | 9 +++++++++ packages/migrations/CHANGELOG.md | 4 ++++ packages/order-utils/CHANGELOG.json | 3 ++- packages/order-utils/CHANGELOG.md | 8 ++++++++ packages/order-watcher/CHANGELOG.json | 3 ++- packages/order-watcher/CHANGELOG.md | 4 ++++ packages/react-docs/CHANGELOG.json | 9 +++++++++ packages/react-docs/CHANGELOG.md | 4 ++++ packages/react-shared/CHANGELOG.json | 9 +++++++++ packages/react-shared/CHANGELOG.md | 4 ++++ packages/sol-compiler/CHANGELOG.json | 9 +++++++++ packages/sol-compiler/CHANGELOG.md | 4 ++++ packages/sol-cov/CHANGELOG.json | 9 +++++++++ packages/sol-cov/CHANGELOG.md | 4 ++++ packages/sol-resolver/CHANGELOG.json | 9 +++++++++ packages/sol-resolver/CHANGELOG.md | 4 ++++ packages/sra-report/CHANGELOG.json | 9 +++++++++ packages/sra-report/CHANGELOG.md | 4 ++++ packages/sra-spec/CHANGELOG.json | 3 ++- packages/sra-spec/CHANGELOG.md | 5 +++++ packages/subproviders/CHANGELOG.json | 9 +++++++++ packages/subproviders/CHANGELOG.md | 4 ++++ packages/types/CHANGELOG.json | 3 ++- packages/types/CHANGELOG.md | 5 +++++ packages/utils/CHANGELOG.json | 9 +++++++++ packages/utils/CHANGELOG.md | 4 ++++ packages/web3-wrapper/CHANGELOG.json | 9 +++++++++ packages/web3-wrapper/CHANGELOG.md | 4 ++++ 48 files changed, 252 insertions(+), 10 deletions(-) diff --git a/packages/0x.js/CHANGELOG.json b/packages/0x.js/CHANGELOG.json index 63ef2fb5cb..0a43abe899 100644 --- a/packages/0x.js/CHANGELOG.json +++ b/packages/0x.js/CHANGELOG.json @@ -5,7 +5,8 @@ { "note": "Fix missing `BlockParamLiteral` type import issue" } - ] + ], + "timestamp": 1535377027 }, { "version": "1.0.1-rc.5", diff --git a/packages/0x.js/CHANGELOG.md b/packages/0x.js/CHANGELOG.md index e949073537..65cbbb8fe0 100644 --- a/packages/0x.js/CHANGELOG.md +++ b/packages/0x.js/CHANGELOG.md @@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.1-rc.6 - _August 27, 2018_ + + * Fix missing `BlockParamLiteral` type import issue + +## v1.0.1-rc.5 - _Invalid date_ + + * Fix `main` and `types` package.json entries so that they point to the new location of index.d.ts and index.js + ## v1.0.1-rc.4 - _August 24, 2018_ * Re-organize the exported interface of 0x.js. Remove the `ZeroEx` class, and instead export the same exports as `0x.js`'s sub-packages: `@0xproject/contract-wrappers`, `@0xproject/order-utils` and `@0xproject/order-watcher` (#963) diff --git a/packages/abi-gen/CHANGELOG.json b/packages/abi-gen/CHANGELOG.json index 0b6a9a052d..46297a778d 100644 --- a/packages/abi-gen/CHANGELOG.json +++ b/packages/abi-gen/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535377027, + "version": "1.0.7", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1535133899, "version": "1.0.6", diff --git a/packages/abi-gen/CHANGELOG.md b/packages/abi-gen/CHANGELOG.md index 477f69e2cb..61f124337e 100644 --- a/packages/abi-gen/CHANGELOG.md +++ b/packages/abi-gen/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.7 - _August 27, 2018_ + + * Dependencies updated + ## v1.0.6 - _August 24, 2018_ * Dependencies updated diff --git a/packages/assert/CHANGELOG.json b/packages/assert/CHANGELOG.json index 01fd4c567e..b624d56fdd 100644 --- a/packages/assert/CHANGELOG.json +++ b/packages/assert/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535377027, + "version": "1.0.7", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1535133899, "version": "1.0.6", diff --git a/packages/assert/CHANGELOG.md b/packages/assert/CHANGELOG.md index ffa34c48c2..fc932cbb3c 100644 --- a/packages/assert/CHANGELOG.md +++ b/packages/assert/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.7 - _August 27, 2018_ + + * Dependencies updated + ## v1.0.6 - _August 24, 2018_ * Dependencies updated diff --git a/packages/base-contract/CHANGELOG.json b/packages/base-contract/CHANGELOG.json index 3f01ab0eb7..6f801694bc 100644 --- a/packages/base-contract/CHANGELOG.json +++ b/packages/base-contract/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535377027, + "version": "2.0.1", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1535133899, "version": "2.0.0", diff --git a/packages/base-contract/CHANGELOG.md b/packages/base-contract/CHANGELOG.md index 634b3f5a72..530e10ab86 100644 --- a/packages/base-contract/CHANGELOG.md +++ b/packages/base-contract/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.1 - _August 27, 2018_ + + * Dependencies updated + ## v2.0.0 - _August 24, 2018_ * Dependencies updated diff --git a/packages/connect/CHANGELOG.json b/packages/connect/CHANGELOG.json index 9d2679abf3..8ccb6afe24 100644 --- a/packages/connect/CHANGELOG.json +++ b/packages/connect/CHANGELOG.json @@ -5,7 +5,8 @@ { "note": "Dependencies updated" } - ] + ], + "timestamp": 1535377027 }, { "version": "2.0.0-rc.1", diff --git a/packages/connect/CHANGELOG.md b/packages/connect/CHANGELOG.md index a6821f064b..a83d318692 100644 --- a/packages/connect/CHANGELOG.md +++ b/packages/connect/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.0-rc.2 - _August 27, 2018_ + + * Dependencies updated + ## v2.0.0-rc.1 - _August 24, 2018_ * Updated for SRA v2 (#974) diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index 2e159961b3..b3c9b0fb34 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -5,7 +5,8 @@ { "note": "Fix missing `BlockParamLiteral` type import issue" } - ] + ], + "timestamp": 1535377027 }, { "version": "1.0.1-rc.4", diff --git a/packages/contract-wrappers/CHANGELOG.md b/packages/contract-wrappers/CHANGELOG.md index b1003edfdb..fb92ea8581 100644 --- a/packages/contract-wrappers/CHANGELOG.md +++ b/packages/contract-wrappers/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.1-rc.5 - _August 27, 2018_ + + * Fix missing `BlockParamLiteral` type import issue + ## v1.0.1-rc.4 - _August 24, 2018_ * Export missing types: `TransactionEncoder`, `ContractAbi`, `JSONRPCRequestPayload`, `JSONRPCResponsePayload`, `JSONRPCErrorCallback`, `AbiDefinition`, `FunctionAbi`, `EventAbi`, `EventParameter`, `DecodedLogArgs`, `MethodAbi`, `ConstructorAbi`, `FallbackAbi`, `DataItem`, `ConstructorStateMutability`, `StateMutability` & `ExchangeSignatureValidatorApprovalEventArgs` (#924) diff --git a/packages/dev-utils/CHANGELOG.json b/packages/dev-utils/CHANGELOG.json index e0f08344b6..61403d3c44 100644 --- a/packages/dev-utils/CHANGELOG.json +++ b/packages/dev-utils/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535377027, + "version": "1.0.6", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1535133899, "version": "1.0.5", diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index 0e39de9264..5a1591c8f8 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.6 - _August 27, 2018_ + + * Dependencies updated + ## v1.0.5 - _August 24, 2018_ * Dependencies updated diff --git a/packages/fill-scenarios/CHANGELOG.json b/packages/fill-scenarios/CHANGELOG.json index e3dba02967..c86770f3ca 100644 --- a/packages/fill-scenarios/CHANGELOG.json +++ b/packages/fill-scenarios/CHANGELOG.json @@ -5,7 +5,8 @@ { "note": "Dependencies updated" } - ] + ], + "timestamp": 1535377027 }, { "version": "1.0.1-rc.4", diff --git a/packages/fill-scenarios/CHANGELOG.md b/packages/fill-scenarios/CHANGELOG.md index 5ae50d1c40..38a57003fe 100644 --- a/packages/fill-scenarios/CHANGELOG.md +++ b/packages/fill-scenarios/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.1-rc.5 - _August 27, 2018_ + + * Dependencies updated + ## v1.0.1-rc.4 - _August 24, 2018_ * Dependencies updated diff --git a/packages/forwarder-helper/CHANGELOG.json b/packages/forwarder-helper/CHANGELOG.json index e187dc6be2..2d68cf7047 100644 --- a/packages/forwarder-helper/CHANGELOG.json +++ b/packages/forwarder-helper/CHANGELOG.json @@ -5,7 +5,8 @@ { "note": "Dependencies updated" } - ] + ], + "timestamp": 1535377027 }, { "version": "1.0.1-rc.1", diff --git a/packages/forwarder-helper/CHANGELOG.md b/packages/forwarder-helper/CHANGELOG.md index 6d48268e6c..5be6a6959b 100644 --- a/packages/forwarder-helper/CHANGELOG.md +++ b/packages/forwarder-helper/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.1-rc.2 - _August 27, 2018_ + + * Dependencies updated + ## v1.0.1-rc.1 - _August 24, 2018_ * Add initial forwarderHelperFactory (#997) diff --git a/packages/json-schemas/CHANGELOG.json b/packages/json-schemas/CHANGELOG.json index 205c663fc4..7bc95f6e67 100644 --- a/packages/json-schemas/CHANGELOG.json +++ b/packages/json-schemas/CHANGELOG.json @@ -5,7 +5,8 @@ { "note": "Dependencies updated" } - ] + ], + "timestamp": 1535377027 }, { "version": "1.0.1-rc.5", diff --git a/packages/json-schemas/CHANGELOG.md b/packages/json-schemas/CHANGELOG.md index e3fa8078d1..2a7dcf8db0 100644 --- a/packages/json-schemas/CHANGELOG.md +++ b/packages/json-schemas/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.1-rc.6 - _August 27, 2018_ + + * Dependencies updated + ## v1.0.1-rc.5 - _August 24, 2018_ * Update incorrect relayer api fee recipients response schema (#974) diff --git a/packages/migrations/CHANGELOG.json b/packages/migrations/CHANGELOG.json index 17f185a9d2..b8994f7215 100644 --- a/packages/migrations/CHANGELOG.json +++ b/packages/migrations/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535377027, + "version": "1.0.6", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1535133899, "version": "1.0.5", diff --git a/packages/migrations/CHANGELOG.md b/packages/migrations/CHANGELOG.md index 0ebd03575f..4f378c14c0 100644 --- a/packages/migrations/CHANGELOG.md +++ b/packages/migrations/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.6 - _August 27, 2018_ + + * Dependencies updated + ## v1.0.5 - _August 24, 2018_ * Dependencies updated diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json index a531dd3ae2..f28306f784 100644 --- a/packages/order-utils/CHANGELOG.json +++ b/packages/order-utils/CHANGELOG.json @@ -5,7 +5,8 @@ { "note": "Fix missing `BlockParamLiteral` type import issue" } - ] + ], + "timestamp": 1535377027 }, { "version": "1.0.1-rc.5", diff --git a/packages/order-utils/CHANGELOG.md b/packages/order-utils/CHANGELOG.md index 7af51fc619..c367e4cd86 100644 --- a/packages/order-utils/CHANGELOG.md +++ b/packages/order-utils/CHANGELOG.md @@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.1-rc.6 - _August 27, 2018_ + + * Fix missing `BlockParamLiteral` type import issue + +## v1.0.1-rc.5 - _Invalid date_ + + * Remove Caller and Trezor SignatureTypes (#1015) + ## v1.0.1-rc.4 - _August 24, 2018_ * Remove rounding error being thrown when maker amount is very small (#959) diff --git a/packages/order-watcher/CHANGELOG.json b/packages/order-watcher/CHANGELOG.json index 445f56e177..04ec38fe3a 100644 --- a/packages/order-watcher/CHANGELOG.json +++ b/packages/order-watcher/CHANGELOG.json @@ -5,7 +5,8 @@ { "note": "Fix missing `BlockParamLiteral` type import issue" } - ] + ], + "timestamp": 1535377027 }, { "version": "1.0.1-rc.4", diff --git a/packages/order-watcher/CHANGELOG.md b/packages/order-watcher/CHANGELOG.md index 73bfd51142..5f34ea7267 100644 --- a/packages/order-watcher/CHANGELOG.md +++ b/packages/order-watcher/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## 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) diff --git a/packages/react-docs/CHANGELOG.json b/packages/react-docs/CHANGELOG.json index 5ca4f4d055..0e41576b66 100644 --- a/packages/react-docs/CHANGELOG.json +++ b/packages/react-docs/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535377027, + "version": "1.0.7", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1535133899, "version": "1.0.6", diff --git a/packages/react-docs/CHANGELOG.md b/packages/react-docs/CHANGELOG.md index 09d666d75f..a06e0f4429 100644 --- a/packages/react-docs/CHANGELOG.md +++ b/packages/react-docs/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.7 - _August 27, 2018_ + + * Dependencies updated + ## v1.0.6 - _August 24, 2018_ * Dependencies updated diff --git a/packages/react-shared/CHANGELOG.json b/packages/react-shared/CHANGELOG.json index 01e97f9e75..dc52d8d7f4 100644 --- a/packages/react-shared/CHANGELOG.json +++ b/packages/react-shared/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535377027, + "version": "1.0.8", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1535133899, "version": "1.0.7", diff --git a/packages/react-shared/CHANGELOG.md b/packages/react-shared/CHANGELOG.md index b70db245c8..1c5fb93dd4 100644 --- a/packages/react-shared/CHANGELOG.md +++ b/packages/react-shared/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.8 - _August 27, 2018_ + + * Dependencies updated + ## v1.0.7 - _August 24, 2018_ * Dependencies updated diff --git a/packages/sol-compiler/CHANGELOG.json b/packages/sol-compiler/CHANGELOG.json index b27253b012..b334e49377 100644 --- a/packages/sol-compiler/CHANGELOG.json +++ b/packages/sol-compiler/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535377027, + "version": "1.1.1", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "1.1.0", "changes": [ diff --git a/packages/sol-compiler/CHANGELOG.md b/packages/sol-compiler/CHANGELOG.md index 852015ff99..8243a2cf86 100644 --- a/packages/sol-compiler/CHANGELOG.md +++ b/packages/sol-compiler/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.1.1 - _August 27, 2018_ + + * Dependencies updated + ## v1.1.0 - _August 24, 2018_ * Quicken compilation by sending multiple contracts to the same solcjs invocation, batching them together based on compiler version requirements. (#965) diff --git a/packages/sol-cov/CHANGELOG.json b/packages/sol-cov/CHANGELOG.json index 597ba4875b..3208eafba6 100644 --- a/packages/sol-cov/CHANGELOG.json +++ b/packages/sol-cov/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535377027, + "version": "2.1.1", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.1.0", "changes": [ diff --git a/packages/sol-cov/CHANGELOG.md b/packages/sol-cov/CHANGELOG.md index 819b58c958..72d3a057d6 100644 --- a/packages/sol-cov/CHANGELOG.md +++ b/packages/sol-cov/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.1.1 - _August 27, 2018_ + + * Dependencies updated + ## v2.1.0 - _August 24, 2018_ * Export types: `JSONRPCRequestPayload`, `Provider`, `JSONRPCErrorCallback`, `JSONRPCResponsePayload`, `JSONRPCRequestPayloadWithMethod`, `NextCallback`, `ErrorCallback`, `OnNextCompleted` and `Callback` (#924) diff --git a/packages/sol-resolver/CHANGELOG.json b/packages/sol-resolver/CHANGELOG.json index cd1dcbe018..71b7bf99cf 100644 --- a/packages/sol-resolver/CHANGELOG.json +++ b/packages/sol-resolver/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535377027, + "version": "1.0.7", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1535133899, "version": "1.0.6", diff --git a/packages/sol-resolver/CHANGELOG.md b/packages/sol-resolver/CHANGELOG.md index 64ae2d6735..2fa21be216 100644 --- a/packages/sol-resolver/CHANGELOG.md +++ b/packages/sol-resolver/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.7 - _August 27, 2018_ + + * Dependencies updated + ## v1.0.6 - _August 24, 2018_ * Dependencies updated diff --git a/packages/sra-report/CHANGELOG.json b/packages/sra-report/CHANGELOG.json index eecb81312c..24e219045e 100644 --- a/packages/sra-report/CHANGELOG.json +++ b/packages/sra-report/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535377027, + "version": "1.0.7", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1535133899, "version": "1.0.6", diff --git a/packages/sra-report/CHANGELOG.md b/packages/sra-report/CHANGELOG.md index 3ff6a73aea..e01309f64b 100644 --- a/packages/sra-report/CHANGELOG.md +++ b/packages/sra-report/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.7 - _August 27, 2018_ + + * Dependencies updated + ## v1.0.6 - _August 24, 2018_ * Dependencies updated diff --git a/packages/sra-spec/CHANGELOG.json b/packages/sra-spec/CHANGELOG.json index 14830eb052..e9bac0c4d7 100644 --- a/packages/sra-spec/CHANGELOG.json +++ b/packages/sra-spec/CHANGELOG.json @@ -9,7 +9,8 @@ { "note": "Fix relative path to introduction MD file" } - ] + ], + "timestamp": 1535377027 }, { "version": "1.0.1-rc.5", diff --git a/packages/sra-spec/CHANGELOG.md b/packages/sra-spec/CHANGELOG.md index 1a88b0ce18..60c1cb78fd 100644 --- a/packages/sra-spec/CHANGELOG.md +++ b/packages/sra-spec/CHANGELOG.md @@ -5,6 +5,11 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.1-rc.6 - _August 27, 2018_ + + * Fix `main` and `types` package.json entries so that they point to the new location of index.d.ts and index.js + * Fix relative path to introduction MD file + ## v1.0.1-rc.5 - _August 24, 2018_ * Add takerAddress to /orders parameters (#974) diff --git a/packages/subproviders/CHANGELOG.json b/packages/subproviders/CHANGELOG.json index e11f663e61..03d7764991 100644 --- a/packages/subproviders/CHANGELOG.json +++ b/packages/subproviders/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535377027, + "version": "2.0.1", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.0.0", "changes": [ diff --git a/packages/subproviders/CHANGELOG.md b/packages/subproviders/CHANGELOG.md index 444d1997a8..c747231be2 100644 --- a/packages/subproviders/CHANGELOG.md +++ b/packages/subproviders/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.1 - _August 27, 2018_ + + * Dependencies updated + ## v2.0.0 - _August 24, 2018_ * Export types: `PartialTxParams`, `JSONRPCRequestPayloadWithMethod`, `ECSignatureString`, `AccountFetchingConfigs`, `LedgerEthereumClientFactoryAsync`, `OnNextCompleted`, `MnemonicWalletSubproviderConfigs`, LedgerGetAddressResult, `JSONRPCRequestPayload`, `Provider`, `JSONRPCResponsePayload` and `JSONRPCErrorCallback` (#924) diff --git a/packages/types/CHANGELOG.json b/packages/types/CHANGELOG.json index 1210168d48..e96d2a742c 100644 --- a/packages/types/CHANGELOG.json +++ b/packages/types/CHANGELOG.json @@ -10,7 +10,8 @@ "note": "Remove Caller and Trezor SignatureTypes", "pr": 1015 } - ] + ], + "timestamp": 1535377027 }, { "version": "1.0.1-rc.5", diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index 3bd1d375fe..299dcac88c 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -5,6 +5,11 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.1-rc.6 - _August 27, 2018_ + + * Add WalletError and ValidatorError revert reasons (#1012) + * Remove Caller and Trezor SignatureTypes (#1015) + ## v1.0.1-rc.5 - _August 24, 2018_ * Add revert reasons for ERC721Token (#933) diff --git a/packages/utils/CHANGELOG.json b/packages/utils/CHANGELOG.json index 6edafb946f..446355007c 100644 --- a/packages/utils/CHANGELOG.json +++ b/packages/utils/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535377027, + "version": "1.0.7", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1535133899, "version": "1.0.6", diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md index a2d4d115b2..f7e877a587 100644 --- a/packages/utils/CHANGELOG.md +++ b/packages/utils/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.7 - _August 27, 2018_ + + * Dependencies updated + ## v1.0.6 - _August 24, 2018_ * Dependencies updated diff --git a/packages/web3-wrapper/CHANGELOG.json b/packages/web3-wrapper/CHANGELOG.json index e2bbcaeb8e..decefbfeac 100644 --- a/packages/web3-wrapper/CHANGELOG.json +++ b/packages/web3-wrapper/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1535377027, + "version": "2.0.1", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.0.0", "changes": [ diff --git a/packages/web3-wrapper/CHANGELOG.md b/packages/web3-wrapper/CHANGELOG.md index 3bfe07d3bd..8b95de56f2 100644 --- a/packages/web3-wrapper/CHANGELOG.md +++ b/packages/web3-wrapper/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.1 - _August 27, 2018_ + + * Dependencies updated + ## v2.0.0 - _August 24, 2018_ * Export types: `BlockParam`, `TxData`, `Provider`, `TransactionReceipt`, `Transaction`, `TraceParams`, `TransactionTrace``, BlockWithoutTransactionDat`a, `LogEntry`, `FilterObject`, `CallData`, `TransactionReceiptWithDecodedLogs`, `BlockWithTransactionData``, LogTopi`c, `JSONRPCRequestPayload`, `TransactionReceiptStatus`, `DecodedLogArgs`, `StructLog`, `JSONRPCErrorCallback``, BlockParamLitera`l, `ContractEventArg`, `DecodedLogEntry`, `LogEntryEvent`, `OpCode`, `TxDataPayable`, `JSONRPCResponsePayload``, RawLogEntr`y, `DecodedLogEntryEvent`, `LogWithDecodedArgs`, `AbiDefinition`, `RawLog`, `FunctionAbi`, `EventAbi`, `EventParameter``, MethodAb`i, `ConstructorAbi`, `FallbackAbi`, `DataItem`, `ConstructorStateMutability` and `StateMutability` (#924) From 00a4fa5f7c1da8deae703b36b6bbed024cf9e111 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 27 Aug 2018 14:48:24 +0100 Subject: [PATCH 119/120] Publish - 0x.js@1.0.1-rc.6 - @0xproject/abi-gen@1.0.7 - @0xproject/assert@1.0.7 - @0xproject/base-contract@2.0.1 - @0xproject/connect@2.0.0-rc.2 - @0xproject/contract-wrappers@1.0.1-rc.5 - contracts@2.1.42 - @0xproject/dev-utils@1.0.6 - @0xproject/fill-scenarios@1.0.1-rc.5 - @0xproject/forwarder-helper@1.0.1-rc.2 - @0xproject/json-schemas@1.0.1-rc.6 - @0xproject/metacoin@0.0.17 - @0xproject/migrations@1.0.6 - @0xproject/monorepo-scripts@1.0.7 - @0xproject/order-utils@1.0.1-rc.6 - @0xproject/order-watcher@1.0.1-rc.5 - @0xproject/react-docs@1.0.7 - @0xproject/react-shared@1.0.8 - @0xproject/sol-compiler@1.1.1 - @0xproject/sol-cov@2.1.1 - @0xproject/sol-resolver@1.0.7 - @0xproject/sra-report@1.0.7 - @0xproject/sra-spec@1.0.1-rc.6 - @0xproject/subproviders@2.0.1 - @0xproject/testnet-faucets@1.0.43 - @0xproject/types@1.0.1-rc.6 - @0xproject/utils@1.0.7 - @0xproject/web3-wrapper@2.0.1 - @0xproject/website@0.0.46 --- packages/0x.js/package.json | 28 ++++++++++---------- packages/abi-gen/package.json | 4 +-- packages/assert/package.json | 6 ++--- packages/base-contract/package.json | 6 ++--- packages/connect/package.json | 10 ++++---- packages/contract-wrappers/package.json | 26 +++++++++---------- packages/contracts/package.json | 34 +++++++++++-------------- packages/dev-utils/package.json | 10 ++++---- packages/fill-scenarios/package.json | 14 +++++----- packages/forwarder-helper/package.json | 12 ++++----- packages/json-schemas/package.json | 4 +-- packages/metacoin/package.json | 20 +++++++-------- packages/migrations/package.json | 20 +++++++-------- packages/monorepo-scripts/package.json | 2 +- packages/order-utils/package.json | 16 ++++++------ packages/order-watcher/package.json | 26 +++++++++---------- packages/react-docs/package.json | 8 +++--- packages/react-shared/package.json | 4 +-- packages/sol-compiler/package.json | 16 ++++++------ packages/sol-cov/package.json | 12 ++++----- packages/sol-resolver/package.json | 4 +-- packages/sra-report/package.json | 6 ++--- packages/sra-spec/package.json | 4 +-- packages/subproviders/package.json | 10 ++++---- packages/testnet-faucets/package.json | 8 +++--- packages/types/package.json | 2 +- packages/utils/package.json | 4 +-- packages/web3-wrapper/package.json | 8 +++--- packages/website/package.json | 10 ++++---- 29 files changed, 165 insertions(+), 169 deletions(-) diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json index 5d4a6ed0e7..c3adb496ed 100644 --- a/packages/0x.js/package.json +++ b/packages/0x.js/package.json @@ -1,6 +1,6 @@ { "name": "0x.js", - "version": "1.0.1-rc.5", + "version": "1.0.1-rc.6", "engines": { "node": ">=6.12" }, @@ -42,10 +42,10 @@ }, "license": "Apache-2.0", "devDependencies": { - "@0xproject/abi-gen": "^1.0.6", - "@0xproject/dev-utils": "^1.0.5", - "@0xproject/migrations": "^1.0.5", - "@0xproject/monorepo-scripts": "^1.0.6", + "@0xproject/abi-gen": "^1.0.7", + "@0xproject/dev-utils": "^1.0.6", + "@0xproject/migrations": "^1.0.6", + "@0xproject/monorepo-scripts": "^1.0.7", "@0xproject/tslint-config": "^1.0.6", "@types/lodash": "4.14.104", "@types/mocha": "^2.2.42", @@ -73,16 +73,16 @@ "webpack": "^3.1.0" }, "dependencies": { - "@0xproject/assert": "^1.0.6", - "@0xproject/base-contract": "^2.0.0", - "@0xproject/contract-wrappers": "^1.0.1-rc.4", - "@0xproject/order-utils": "^1.0.1-rc.4", - "@0xproject/order-watcher": "^1.0.1-rc.4", - "@0xproject/subproviders": "^2.0.0", - "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/assert": "^1.0.7", + "@0xproject/base-contract": "^2.0.1", + "@0xproject/contract-wrappers": "^1.0.1-rc.5", + "@0xproject/order-utils": "^1.0.1-rc.6", + "@0xproject/order-watcher": "^1.0.1-rc.5", + "@0xproject/subproviders": "^2.0.1", + "@0xproject/types": "^1.0.1-rc.6", "@0xproject/typescript-typings": "^1.0.5", - "@0xproject/utils": "^1.0.6", - "@0xproject/web3-wrapper": "^2.0.0", + "@0xproject/utils": "^1.0.7", + "@0xproject/web3-wrapper": "^2.0.1", "ethereum-types": "^1.0.5", "ethers": "3.0.22", "lodash": "^4.17.5", diff --git a/packages/abi-gen/package.json b/packages/abi-gen/package.json index 61a35ef09f..000e8cee08 100644 --- a/packages/abi-gen/package.json +++ b/packages/abi-gen/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/abi-gen", - "version": "1.0.6", + "version": "1.0.7", "engines": { "node": ">=6.12" }, @@ -32,7 +32,7 @@ "homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen/README.md", "dependencies": { "@0xproject/typescript-typings": "^1.0.5", - "@0xproject/utils": "^1.0.6", + "@0xproject/utils": "^1.0.7", "chalk": "^2.3.0", "ethereum-types": "^1.0.5", "glob": "^7.1.2", diff --git a/packages/assert/package.json b/packages/assert/package.json index c67a19013d..2dea4b6161 100644 --- a/packages/assert/package.json +++ b/packages/assert/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/assert", - "version": "1.0.6", + "version": "1.0.7", "engines": { "node": ">=6.12" }, @@ -45,9 +45,9 @@ "typescript": "3.0.1" }, "dependencies": { - "@0xproject/json-schemas": "^1.0.1-rc.5", + "@0xproject/json-schemas": "^1.0.1-rc.6", "@0xproject/typescript-typings": "^1.0.5", - "@0xproject/utils": "^1.0.6", + "@0xproject/utils": "^1.0.7", "lodash": "^4.17.5", "valid-url": "^1.0.9" }, diff --git a/packages/base-contract/package.json b/packages/base-contract/package.json index 221222928c..33a66c97a3 100644 --- a/packages/base-contract/package.json +++ b/packages/base-contract/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/base-contract", - "version": "2.0.0", + "version": "2.0.1", "engines": { "node": ">=6.12" }, @@ -42,8 +42,8 @@ }, "dependencies": { "@0xproject/typescript-typings": "^1.0.5", - "@0xproject/utils": "^1.0.6", - "@0xproject/web3-wrapper": "^2.0.0", + "@0xproject/utils": "^1.0.7", + "@0xproject/web3-wrapper": "^2.0.1", "ethereum-types": "^1.0.5", "ethers": "3.0.22", "lodash": "^4.17.5" diff --git a/packages/connect/package.json b/packages/connect/package.json index 116db04699..15f537c7d2 100644 --- a/packages/connect/package.json +++ b/packages/connect/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/connect", - "version": "2.0.0-rc.1", + "version": "2.0.0-rc.2", "engines": { "node": ">=6.12" }, @@ -44,11 +44,11 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/connect/README.md", "dependencies": { - "@0xproject/assert": "^1.0.6", - "@0xproject/json-schemas": "^1.0.1-rc.5", - "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/assert": "^1.0.7", + "@0xproject/json-schemas": "^1.0.1-rc.6", + "@0xproject/types": "^1.0.1-rc.6", "@0xproject/typescript-typings": "^1.0.5", - "@0xproject/utils": "^1.0.6", + "@0xproject/utils": "^1.0.7", "lodash": "^4.17.5", "query-string": "^5.0.1", "sinon": "^4.0.0", diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json index 63fe6a5e5c..7d9417d656 100644 --- a/packages/contract-wrappers/package.json +++ b/packages/contract-wrappers/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/contract-wrappers", - "version": "1.0.1-rc.4", + "version": "1.0.1-rc.5", "description": "Smart TS wrappers for 0x smart contracts", "keywords": [ "0xproject", @@ -44,10 +44,10 @@ "node": ">=6.0.0" }, "devDependencies": { - "@0xproject/abi-gen": "^1.0.6", - "@0xproject/dev-utils": "^1.0.5", - "@0xproject/migrations": "^1.0.5", - "@0xproject/subproviders": "^2.0.0", + "@0xproject/abi-gen": "^1.0.7", + "@0xproject/dev-utils": "^1.0.6", + "@0xproject/migrations": "^1.0.6", + "@0xproject/subproviders": "^2.0.1", "@0xproject/tslint-config": "^1.0.6", "@types/lodash": "4.14.104", "@types/mocha": "^2.2.42", @@ -74,15 +74,15 @@ "web3-provider-engine": "14.0.6" }, "dependencies": { - "@0xproject/assert": "^1.0.6", - "@0xproject/base-contract": "^2.0.0", - "@0xproject/fill-scenarios": "^1.0.1-rc.4", - "@0xproject/json-schemas": "^1.0.1-rc.5", - "@0xproject/order-utils": "^1.0.1-rc.4", - "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/assert": "^1.0.7", + "@0xproject/base-contract": "^2.0.1", + "@0xproject/fill-scenarios": "^1.0.1-rc.5", + "@0xproject/json-schemas": "^1.0.1-rc.6", + "@0xproject/order-utils": "^1.0.1-rc.6", + "@0xproject/types": "^1.0.1-rc.6", "@0xproject/typescript-typings": "^1.0.5", - "@0xproject/utils": "^1.0.6", - "@0xproject/web3-wrapper": "^2.0.0", + "@0xproject/utils": "^1.0.7", + "@0xproject/web3-wrapper": "^2.0.1", "ethereum-types": "^1.0.5", "ethereumjs-blockstream": "5.0.0", "ethereumjs-util": "^5.1.1", diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 1c1ac81da5..5d2f290acb 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "contracts", - "version": "2.1.41", + "version": "2.1.42", "engines": { "node": ">=6.12" }, @@ -20,14 +20,11 @@ "test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov", "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html", "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha", - "run_mocha": - "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit", + "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit", "compile": "sol-compiler --contracts-dir src", "clean": "shx rm -rf lib generated_contract_wrappers", - "generate_contract_wrappers": - "abi-gen --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output generated_contract_wrappers --backend ethers", - "lint": - "tslint --project . --exclude **/src/generated_contract_wrappers/**/* --exclude **/lib/**/* && yarn lint-contracts", + "generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output generated_contract_wrappers --backend ethers", + "lint": "tslint --project . --exclude **/src/generated_contract_wrappers/**/* --exclude **/lib/**/* && yarn lint-contracts", "coverage:report:text": "istanbul report text", "coverage:report:html": "istanbul report html && open coverage/index.html", "profiler:report:html": "istanbul report html && open coverage/index.html", @@ -36,8 +33,7 @@ "lint-contracts": "solhint src/2.0.0/**/**/**/**/*.sol" }, "config": { - "abis": - "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|DummyNoReturnERC20Token|ERC20Proxy|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|InvalidERC721Receiver|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|OrderValidator|ReentrantERC20Token|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestExchangeInternals|TestLibBytes|TestLibs|TestSignatureValidator|TestStaticCallReceiver|Validator|Wallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json" + "abis": "../migrations/artifacts/2.0.0/@(AssetProxyOwner|DummyERC20Token|DummyERC721Receiver|DummyERC721Token|DummyNoReturnERC20Token|ERC20Proxy|ERC721Proxy|Forwarder|Exchange|ExchangeWrapper|IAssetData|IAssetProxy|InvalidERC721Receiver|MixinAuthorizable|MultiSigWallet|MultiSigWalletWithTimeLock|OrderValidator|ReentrantERC20Token|TestAssetProxyOwner|TestAssetProxyDispatcher|TestConstants|TestExchangeInternals|TestLibBytes|TestLibs|TestSignatureValidator|TestStaticCallReceiver|Validator|Wallet|TokenRegistry|Whitelist|WETH9|ZRXToken).json" }, "repository": { "type": "git", @@ -50,11 +46,11 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/contracts/README.md", "devDependencies": { - "@0xproject/abi-gen": "^1.0.6", - "@0xproject/dev-utils": "^1.0.5", - "@0xproject/sol-compiler": "^1.1.0", - "@0xproject/sol-cov": "^2.1.0", - "@0xproject/subproviders": "^2.0.0", + "@0xproject/abi-gen": "^1.0.7", + "@0xproject/dev-utils": "^1.0.6", + "@0xproject/sol-compiler": "^1.1.1", + "@0xproject/sol-cov": "^2.1.1", + "@0xproject/subproviders": "^2.0.1", "@0xproject/tslint-config": "^1.0.6", "@types/bn.js": "^4.11.0", "@types/ethereumjs-abi": "^0.6.0", @@ -77,12 +73,12 @@ "yargs": "^10.0.3" }, "dependencies": { - "@0xproject/base-contract": "^2.0.0", - "@0xproject/order-utils": "^1.0.1-rc.4", - "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/base-contract": "^2.0.1", + "@0xproject/order-utils": "^1.0.1-rc.6", + "@0xproject/types": "^1.0.1-rc.6", "@0xproject/typescript-typings": "^1.0.5", - "@0xproject/utils": "^1.0.6", - "@0xproject/web3-wrapper": "^2.0.0", + "@0xproject/utils": "^1.0.7", + "@0xproject/web3-wrapper": "^2.0.1", "@types/js-combinatorics": "^0.5.29", "bn.js": "^4.11.8", "ethereum-types": "^1.0.5", diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index a131613207..d4740d3bde 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/dev-utils", - "version": "1.0.5", + "version": "1.0.6", "engines": { "node": ">=6.12" }, @@ -43,11 +43,11 @@ "typescript": "3.0.1" }, "dependencies": { - "@0xproject/subproviders": "^2.0.0", - "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/subproviders": "^2.0.1", + "@0xproject/types": "^1.0.1-rc.6", "@0xproject/typescript-typings": "^1.0.5", - "@0xproject/utils": "^1.0.6", - "@0xproject/web3-wrapper": "^2.0.0", + "@0xproject/utils": "^1.0.7", + "@0xproject/web3-wrapper": "^2.0.1", "ethereum-types": "^1.0.5", "lodash": "^4.17.5" }, diff --git a/packages/fill-scenarios/package.json b/packages/fill-scenarios/package.json index 74a95fa43d..d0cb29df4f 100644 --- a/packages/fill-scenarios/package.json +++ b/packages/fill-scenarios/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/fill-scenarios", - "version": "1.0.1-rc.4", + "version": "1.0.1-rc.5", "description": "0x order fill scenario generator", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -27,7 +27,7 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/fill-scenarios/README.md", "devDependencies": { - "@0xproject/abi-gen": "^1.0.6", + "@0xproject/abi-gen": "^1.0.7", "@0xproject/tslint-config": "^1.0.6", "@types/lodash": "4.14.104", "copyfiles": "^2.0.0", @@ -38,12 +38,12 @@ "typescript": "3.0.1" }, "dependencies": { - "@0xproject/base-contract": "^2.0.0", - "@0xproject/order-utils": "^1.0.1-rc.4", - "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/base-contract": "^2.0.1", + "@0xproject/order-utils": "^1.0.1-rc.6", + "@0xproject/types": "^1.0.1-rc.6", "@0xproject/typescript-typings": "^1.0.5", - "@0xproject/utils": "^1.0.6", - "@0xproject/web3-wrapper": "^2.0.0", + "@0xproject/utils": "^1.0.7", + "@0xproject/web3-wrapper": "^2.0.1", "ethereum-types": "^1.0.5", "ethers": "3.0.22", "lodash": "^4.17.5" diff --git a/packages/forwarder-helper/package.json b/packages/forwarder-helper/package.json index b030413044..fccd7ccddb 100644 --- a/packages/forwarder-helper/package.json +++ b/packages/forwarder-helper/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/forwarder-helper", - "version": "1.0.1-rc.1", + "version": "1.0.1-rc.2", "engines": { "node": ">=6.12" }, @@ -39,12 +39,12 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/forwarder-helper/README.md", "dependencies": { - "@0xproject/assert": "^1.0.6", - "@0xproject/json-schemas": "^1.0.1-rc.5", - "@0xproject/order-utils": "^1.0.1-rc.4", - "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/assert": "^1.0.7", + "@0xproject/json-schemas": "^1.0.1-rc.6", + "@0xproject/order-utils": "^1.0.1-rc.6", + "@0xproject/types": "^1.0.1-rc.6", "@0xproject/typescript-typings": "^1.0.5", - "@0xproject/utils": "^1.0.6", + "@0xproject/utils": "^1.0.7", "@types/node": "^8.0.53", "lodash": "^4.17.10" }, diff --git a/packages/json-schemas/package.json b/packages/json-schemas/package.json index af4c086728..bdd801a190 100644 --- a/packages/json-schemas/package.json +++ b/packages/json-schemas/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/json-schemas", - "version": "1.0.1-rc.5", + "version": "1.0.1-rc.6", "engines": { "node": ">=6.12" }, @@ -46,7 +46,7 @@ }, "devDependencies": { "@0xproject/tslint-config": "^1.0.6", - "@0xproject/utils": "^1.0.6", + "@0xproject/utils": "^1.0.7", "@types/lodash.foreach": "^4.5.3", "@types/lodash.values": "^4.3.3", "@types/mocha": "^2.2.42", diff --git a/packages/metacoin/package.json b/packages/metacoin/package.json index 7731c1ca31..ea251e2fef 100644 --- a/packages/metacoin/package.json +++ b/packages/metacoin/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/metacoin", - "version": "0.0.16", + "version": "0.0.17", "engines": { "node": ">=6.12" }, @@ -29,15 +29,15 @@ "author": "", "license": "Apache-2.0", "dependencies": { - "@0xproject/abi-gen": "^1.0.6", - "@0xproject/base-contract": "^2.0.0", - "@0xproject/sol-cov": "^2.1.0", - "@0xproject/subproviders": "^2.0.0", + "@0xproject/abi-gen": "^1.0.7", + "@0xproject/base-contract": "^2.0.1", + "@0xproject/sol-cov": "^2.1.1", + "@0xproject/subproviders": "^2.0.1", "@0xproject/tslint-config": "^1.0.6", - "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/types": "^1.0.1-rc.6", "@0xproject/typescript-typings": "^1.0.5", - "@0xproject/utils": "^1.0.6", - "@0xproject/web3-wrapper": "^2.0.0", + "@0xproject/utils": "^1.0.7", + "@0xproject/web3-wrapper": "^2.0.1", "@types/mocha": "^5.2.2", "copyfiles": "^2.0.0", "ethereum-types": "^1.0.5", @@ -46,8 +46,8 @@ "run-s": "^0.0.0" }, "devDependencies": { - "@0xproject/dev-utils": "^1.0.5", - "@0xproject/sol-compiler": "^1.1.0", + "@0xproject/dev-utils": "^1.0.6", + "@0xproject/sol-compiler": "^1.1.1", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^2.0.1", diff --git a/packages/migrations/package.json b/packages/migrations/package.json index 57f856ce59..89cd4207a5 100644 --- a/packages/migrations/package.json +++ b/packages/migrations/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/migrations", - "version": "1.0.5", + "version": "1.0.6", "engines": { "node": ">=6.12" }, @@ -35,10 +35,10 @@ }, "license": "Apache-2.0", "devDependencies": { - "@0xproject/abi-gen": "^1.0.6", - "@0xproject/dev-utils": "^1.0.5", + "@0xproject/abi-gen": "^1.0.7", + "@0xproject/dev-utils": "^1.0.6", "@0xproject/tslint-config": "^1.0.6", - "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/types": "^1.0.1-rc.6", "@types/yargs": "^10.0.0", "copyfiles": "^2.0.0", "make-promises-safe": "^1.1.0", @@ -49,13 +49,13 @@ "yargs": "^10.0.3" }, "dependencies": { - "@0xproject/base-contract": "^2.0.0", - "@0xproject/order-utils": "^1.0.1-rc.4", - "@0xproject/sol-compiler": "^1.1.0", - "@0xproject/subproviders": "^2.0.0", + "@0xproject/base-contract": "^2.0.1", + "@0xproject/order-utils": "^1.0.1-rc.6", + "@0xproject/sol-compiler": "^1.1.1", + "@0xproject/subproviders": "^2.0.1", "@0xproject/typescript-typings": "^1.0.5", - "@0xproject/utils": "^1.0.6", - "@0xproject/web3-wrapper": "^2.0.0", + "@0xproject/utils": "^1.0.7", + "@0xproject/web3-wrapper": "^2.0.1", "@ledgerhq/hw-app-eth": "^4.3.0", "ethereum-types": "^1.0.5", "ethers": "3.0.22", diff --git a/packages/monorepo-scripts/package.json b/packages/monorepo-scripts/package.json index 6a4d0bb45e..a2f2343b89 100644 --- a/packages/monorepo-scripts/package.json +++ b/packages/monorepo-scripts/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@0xproject/monorepo-scripts", - "version": "1.0.6", + "version": "1.0.7", "engines": { "node": ">=6.12" }, diff --git a/packages/order-utils/package.json b/packages/order-utils/package.json index 0a35251d72..77a4142fcd 100644 --- a/packages/order-utils/package.json +++ b/packages/order-utils/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/order-utils", - "version": "1.0.1-rc.4", + "version": "1.0.1-rc.6", "engines": { "node": ">=6.12" }, @@ -40,7 +40,7 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/order-utils/README.md", "devDependencies": { - "@0xproject/dev-utils": "^1.0.5", + "@0xproject/dev-utils": "^1.0.6", "@0xproject/tslint-config": "^1.0.6", "@types/bn.js": "^4.11.0", "@types/lodash": "4.14.104", @@ -59,13 +59,13 @@ "typescript": "3.0.1" }, "dependencies": { - "@0xproject/assert": "^1.0.6", - "@0xproject/base-contract": "^2.0.0", - "@0xproject/json-schemas": "^1.0.1-rc.5", - "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/assert": "^1.0.7", + "@0xproject/base-contract": "^2.0.1", + "@0xproject/json-schemas": "^1.0.1-rc.6", + "@0xproject/types": "^1.0.1-rc.6", "@0xproject/typescript-typings": "^1.0.5", - "@0xproject/utils": "^1.0.6", - "@0xproject/web3-wrapper": "^2.0.0", + "@0xproject/utils": "^1.0.7", + "@0xproject/web3-wrapper": "^2.0.1", "@types/node": "^8.0.53", "bn.js": "^4.11.8", "ethereum-types": "^1.0.5", diff --git a/packages/order-watcher/package.json b/packages/order-watcher/package.json index 70db15783c..0d5bfd48cf 100644 --- a/packages/order-watcher/package.json +++ b/packages/order-watcher/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/order-watcher", - "version": "1.0.1-rc.4", + "version": "1.0.1-rc.5", "description": "An order watcher daemon that watches for order validity", "keywords": [ "0x", @@ -43,9 +43,9 @@ "node": ">=6.0.0" }, "devDependencies": { - "@0xproject/abi-gen": "^1.0.6", - "@0xproject/dev-utils": "^1.0.5", - "@0xproject/migrations": "^1.0.5", + "@0xproject/abi-gen": "^1.0.7", + "@0xproject/dev-utils": "^1.0.6", + "@0xproject/migrations": "^1.0.6", "@0xproject/tslint-config": "^1.0.6", "@types/bintrees": "^1.0.2", "@types/lodash": "4.14.104", @@ -71,16 +71,16 @@ "typescript": "3.0.1" }, "dependencies": { - "@0xproject/assert": "^1.0.6", - "@0xproject/base-contract": "^2.0.0", - "@0xproject/contract-wrappers": "^1.0.1-rc.4", - "@0xproject/fill-scenarios": "^1.0.1-rc.4", - "@0xproject/json-schemas": "^1.0.1-rc.5", - "@0xproject/order-utils": "^1.0.1-rc.4", - "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/assert": "^1.0.7", + "@0xproject/base-contract": "^2.0.1", + "@0xproject/contract-wrappers": "^1.0.1-rc.5", + "@0xproject/fill-scenarios": "^1.0.1-rc.5", + "@0xproject/json-schemas": "^1.0.1-rc.6", + "@0xproject/order-utils": "^1.0.1-rc.6", + "@0xproject/types": "^1.0.1-rc.6", "@0xproject/typescript-typings": "^1.0.5", - "@0xproject/utils": "^1.0.6", - "@0xproject/web3-wrapper": "^2.0.0", + "@0xproject/utils": "^1.0.7", + "@0xproject/web3-wrapper": "^2.0.1", "bintrees": "^1.0.2", "ethereum-types": "^1.0.5", "ethereumjs-blockstream": "5.0.0", diff --git a/packages/react-docs/package.json b/packages/react-docs/package.json index 47b266e8e8..9e95e69d08 100644 --- a/packages/react-docs/package.json +++ b/packages/react-docs/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/react-docs", - "version": "1.0.6", + "version": "1.0.7", "engines": { "node": ">=6.12" }, @@ -24,7 +24,7 @@ "url": "https://github.com/0xProject/0x-monorepo.git" }, "devDependencies": { - "@0xproject/dev-utils": "^1.0.5", + "@0xproject/dev-utils": "^1.0.6", "@0xproject/tslint-config": "^1.0.6", "@types/compare-versions": "^3.0.0", "copyfiles": "^2.0.0", @@ -34,8 +34,8 @@ "typescript": "3.0.1" }, "dependencies": { - "@0xproject/react-shared": "^1.0.7", - "@0xproject/utils": "^1.0.6", + "@0xproject/react-shared": "^1.0.8", + "@0xproject/utils": "^1.0.7", "@types/lodash": "4.14.104", "@types/material-ui": "0.18.0", "@types/node": "^8.0.53", diff --git a/packages/react-shared/package.json b/packages/react-shared/package.json index 27927bbc86..eb66790447 100644 --- a/packages/react-shared/package.json +++ b/packages/react-shared/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/react-shared", - "version": "1.0.7", + "version": "1.0.8", "engines": { "node": ">=6.12" }, @@ -24,7 +24,7 @@ "url": "https://github.com/0xProject/0x-monorepo.git" }, "devDependencies": { - "@0xproject/dev-utils": "^1.0.5", + "@0xproject/dev-utils": "^1.0.6", "@0xproject/tslint-config": "^1.0.6", "copyfiles": "^2.0.0", "make-promises-safe": "^1.1.0", diff --git a/packages/sol-compiler/package.json b/packages/sol-compiler/package.json index f7e901819a..f60edc1f96 100644 --- a/packages/sol-compiler/package.json +++ b/packages/sol-compiler/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/sol-compiler", - "version": "1.1.0", + "version": "1.1.1", "engines": { "node": ">=6.12" }, @@ -42,7 +42,7 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/sol-compiler/README.md", "devDependencies": { - "@0xproject/dev-utils": "^1.0.5", + "@0xproject/dev-utils": "^1.0.6", "@0xproject/tslint-config": "^1.0.6", "@types/mkdirp": "^0.5.2", "@types/require-from-string": "^1.2.0", @@ -65,13 +65,13 @@ "zeppelin-solidity": "1.8.0" }, "dependencies": { - "@0xproject/assert": "^1.0.6", - "@0xproject/json-schemas": "^1.0.1-rc.5", - "@0xproject/sol-resolver": "^1.0.6", - "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/assert": "^1.0.7", + "@0xproject/json-schemas": "^1.0.1-rc.6", + "@0xproject/sol-resolver": "^1.0.7", + "@0xproject/types": "^1.0.1-rc.6", "@0xproject/typescript-typings": "^1.0.5", - "@0xproject/utils": "^1.0.6", - "@0xproject/web3-wrapper": "^2.0.0", + "@0xproject/utils": "^1.0.7", + "@0xproject/web3-wrapper": "^2.0.1", "@types/yargs": "^11.0.0", "chalk": "^2.3.0", "ethereum-types": "^1.0.5", diff --git a/packages/sol-cov/package.json b/packages/sol-cov/package.json index 00bb300ad6..b8c008b3e7 100644 --- a/packages/sol-cov/package.json +++ b/packages/sol-cov/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/sol-cov", - "version": "2.1.0", + "version": "2.1.1", "engines": { "node": ">=6.12" }, @@ -42,12 +42,12 @@ }, "homepage": "https://github.com/0xProject/0x.js/packages/sol-cov/README.md", "dependencies": { - "@0xproject/dev-utils": "^1.0.5", - "@0xproject/sol-compiler": "^1.1.0", - "@0xproject/subproviders": "^2.0.0", + "@0xproject/dev-utils": "^1.0.6", + "@0xproject/sol-compiler": "^1.1.1", + "@0xproject/subproviders": "^2.0.1", "@0xproject/typescript-typings": "^1.0.5", - "@0xproject/utils": "^1.0.6", - "@0xproject/web3-wrapper": "^2.0.0", + "@0xproject/utils": "^1.0.7", + "@0xproject/web3-wrapper": "^2.0.1", "@types/solidity-parser-antlr": "^0.2.1", "ethereum-types": "^1.0.5", "ethereumjs-util": "^5.1.1", diff --git a/packages/sol-resolver/package.json b/packages/sol-resolver/package.json index 031e9dbdd7..f3772a1183 100644 --- a/packages/sol-resolver/package.json +++ b/packages/sol-resolver/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/sol-resolver", - "version": "1.0.6", + "version": "1.0.7", "engines": { "node": ">=6.12" }, @@ -31,7 +31,7 @@ "typescript": "3.0.1" }, "dependencies": { - "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/types": "^1.0.1-rc.6", "@0xproject/typescript-typings": "^1.0.5", "lodash": "^4.17.5" }, diff --git a/packages/sra-report/package.json b/packages/sra-report/package.json index 4311d77fe9..91b97dd985 100644 --- a/packages/sra-report/package.json +++ b/packages/sra-report/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/sra-report", - "version": "1.0.6", + "version": "1.0.7", "engines": { "node": ">=6.12" }, @@ -34,13 +34,13 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/sra-report/README.md", "dependencies": { - "@0xproject/assert": "^1.0.6", + "@0xproject/assert": "^1.0.7", "@0xproject/connect": "1.0.4", "@0xproject/json-schemas": "^0.8.3", "@0xproject/order-utils": "^0.0.9", "@0xproject/types": "^0.8.2", "@0xproject/typescript-typings": "^1.0.5", - "@0xproject/utils": "^1.0.6", + "@0xproject/utils": "^1.0.7", "chalk": "^2.3.0", "lodash": "^4.17.5", "newman": "^3.9.3", diff --git a/packages/sra-spec/package.json b/packages/sra-spec/package.json index f0820e136a..b560fa77bc 100644 --- a/packages/sra-spec/package.json +++ b/packages/sra-spec/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/sra-spec", - "version": "1.0.1-rc.5", + "version": "1.0.1-rc.6", "engines": { "node": ">=6.12" }, @@ -34,7 +34,7 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/sra-spec/README.md", "dependencies": { - "@0xproject/json-schemas": "^1.0.1-rc.5" + "@0xproject/json-schemas": "^1.0.1-rc.6" }, "devDependencies": { "@0xproject/tslint-config": "^1.0.6", diff --git a/packages/subproviders/package.json b/packages/subproviders/package.json index cf30cc4168..48c6d5ae9f 100644 --- a/packages/subproviders/package.json +++ b/packages/subproviders/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/subproviders", - "version": "2.0.0", + "version": "2.0.1", "engines": { "node": ">=6.12" }, @@ -29,11 +29,11 @@ } }, "dependencies": { - "@0xproject/assert": "^1.0.6", - "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/assert": "^1.0.7", + "@0xproject/types": "^1.0.1-rc.6", "@0xproject/typescript-typings": "^1.0.5", - "@0xproject/utils": "^1.0.6", - "@0xproject/web3-wrapper": "^2.0.0", + "@0xproject/utils": "^1.0.7", + "@0xproject/web3-wrapper": "^2.0.1", "@ledgerhq/hw-app-eth": "^4.3.0", "@ledgerhq/hw-transport-u2f": "^4.3.0", "@types/hdkey": "^0.7.0", diff --git a/packages/testnet-faucets/package.json b/packages/testnet-faucets/package.json index 6dc351c29e..9c32dde475 100644 --- a/packages/testnet-faucets/package.json +++ b/packages/testnet-faucets/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@0xproject/testnet-faucets", - "version": "1.0.42", + "version": "1.0.43", "engines": { "node": ">=6.12" }, @@ -19,10 +19,10 @@ "license": "Apache-2.0", "dependencies": { "0x.js": "0.38.5", - "@0xproject/subproviders": "^2.0.0", + "@0xproject/subproviders": "^2.0.1", "@0xproject/typescript-typings": "^1.0.5", - "@0xproject/utils": "^1.0.6", - "@0xproject/web3-wrapper": "^2.0.0", + "@0xproject/utils": "^1.0.7", + "@0xproject/web3-wrapper": "^2.0.1", "body-parser": "^1.17.1", "ethereum-types": "^1.0.5", "ethereumjs-tx": "^1.3.5", diff --git a/packages/types/package.json b/packages/types/package.json index 6078f422a5..291452cbbf 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/types", - "version": "1.0.1-rc.5", + "version": "1.0.1-rc.6", "engines": { "node": ">=6.12" }, diff --git a/packages/utils/package.json b/packages/utils/package.json index b4795cefd3..c72fb4c831 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/utils", - "version": "1.0.6", + "version": "1.0.7", "engines": { "node": ">=6.12" }, @@ -41,7 +41,7 @@ "typescript": "3.0.1" }, "dependencies": { - "@0xproject/types": "^1.0.1-rc.5", + "@0xproject/types": "^1.0.1-rc.6", "@0xproject/typescript-typings": "^1.0.5", "@types/node": "^8.0.53", "abortcontroller-polyfill": "^1.1.9", diff --git a/packages/web3-wrapper/package.json b/packages/web3-wrapper/package.json index fe8e82d15e..f840744476 100644 --- a/packages/web3-wrapper/package.json +++ b/packages/web3-wrapper/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/web3-wrapper", - "version": "2.0.0", + "version": "2.0.1", "engines": { "node": ">=6.12" }, @@ -53,10 +53,10 @@ "typescript": "3.0.1" }, "dependencies": { - "@0xproject/assert": "^1.0.6", - "@0xproject/json-schemas": "^1.0.1-rc.5", + "@0xproject/assert": "^1.0.7", + "@0xproject/json-schemas": "^1.0.1-rc.6", "@0xproject/typescript-typings": "^1.0.5", - "@0xproject/utils": "^1.0.6", + "@0xproject/utils": "^1.0.7", "ethereum-types": "^1.0.5", "ethereumjs-util": "^5.1.1", "ethers": "3.0.22", diff --git a/packages/website/package.json b/packages/website/package.json index bd6b18866b..9b6a0ba364 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/website", - "version": "0.0.45", + "version": "0.0.46", "engines": { "node": ">=6.12" }, @@ -20,13 +20,13 @@ "dependencies": { "@0xproject/contract-wrappers": "^0.0.5", "@0xproject/order-utils": "^0.0.9", - "@0xproject/react-docs": "^1.0.6", + "@0xproject/react-docs": "^1.0.7", "@0xproject/react-shared": "^0.2.3", - "@0xproject/subproviders": "^2.0.0", + "@0xproject/subproviders": "^2.0.1", "@0xproject/types": "^0.8.1", "@0xproject/typescript-typings": "^0.4.3", - "@0xproject/utils": "^1.0.6", - "@0xproject/web3-wrapper": "^2.0.0", + "@0xproject/utils": "^1.0.7", + "@0xproject/web3-wrapper": "^2.0.1", "accounting": "^0.4.1", "basscss": "^8.0.3", "blockies": "^0.0.2", From f4a4fefe422a5b2140d5bb394a7f06f842352c69 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 27 Aug 2018 15:02:12 +0100 Subject: [PATCH 120/120] Exit with non-error code at end of publishRelease --- packages/monorepo-scripts/src/publish_release_notes.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/monorepo-scripts/src/publish_release_notes.ts b/packages/monorepo-scripts/src/publish_release_notes.ts index 13cf0d85df..a9bc8fe75b 100644 --- a/packages/monorepo-scripts/src/publish_release_notes.ts +++ b/packages/monorepo-scripts/src/publish_release_notes.ts @@ -17,6 +17,7 @@ const args = yargs const allUpdatedPackages = await utils.getUpdatedPackagesAsync(shouldIncludePrivate); await publishReleaseNotesAsync(allUpdatedPackages, isDryRun); + process.exit(0); })().catch(err => { utils.log(err); process.exit(1);