diff --git a/.circleci/config.yml b/.circleci/config.yml index 8845d9cdff..600c710e8e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,18 +7,23 @@ jobs: build: resource_class: medium+ docker: - - image: circleci/node:9-browsers + - image: nikolaik/python-nodejs:python3.7-nodejs8 environment: CONTRACTS_COMMIT_HASH: '9ed05f5' working_directory: ~/repo steps: - checkout - run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV - - run: - # HACK(albrow): Without this, yarn commands will sometimes - # fail with a "permission denied" error. - name: Set npm path - command: npm set prefix=/home/circleci/npm && echo 'export PATH=$HOME/circleci/npm/bin:$PATH' >> /home/circleci/.bashrc + # HACK(feuGeneA): commented out this hack as we're changing + # from a circleci-maintained container to a different + # container, and this hack may not apply anymore, as + # suggested by the non-existance of `/home/circleci/.bashrc` + # when running the command below. + # - run: + # # HACK(albrow): Without this, yarn commands will sometimes + # # fail with a "permission denied" error. + # name: Set npm path + # command: npm set prefix=/home/circleci/npm && echo 'export PATH=$HOME/circleci/npm/bin:$PATH' >> /home/circleci/.bashrc - run: name: install-yarn command: npm install --global yarn@1.9.4 @@ -40,10 +45,12 @@ jobs: path: ~/repo/packages/python-contract-wrappers/generated - store_artifacts: path: ~/repo/packages/abi-gen/test-cli/output + - store_artifacts: + path: ~/repo/packages/abi-gen-wrappers/generated_docs build-3.0: resource_class: medium+ docker: - - image: circleci/node:9-browsers + - image: nikolaik/python-nodejs:python3.7-nodejs8 environment: CONTRACTS_COMMIT_HASH: '9ed05f5' working_directory: ~/repo @@ -52,7 +59,7 @@ jobs: - run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV - run: name: install-yarn - command: sudo npm install --global yarn@1.9.4 + command: npm install --global yarn@1.9.4 - run: name: yarn command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install @@ -66,7 +73,7 @@ jobs: build-website: resource_class: medium+ docker: - - image: circleci/node:9-browsers + - image: nikolaik/python-nodejs:python3.7-nodejs8 working_directory: ~/repo steps: - restore_cache: @@ -74,8 +81,9 @@ jobs: - repo-{{ .Environment.CIRCLE_SHA1 }} - run: cd packages/website && yarn build:prod test-contracts-ganache: + resource_class: medium+ docker: - - image: circleci/node:9-browsers + - image: nikolaik/python-nodejs:python3.7-nodejs8 working_directory: ~/repo steps: - restore_cache: @@ -83,8 +91,9 @@ jobs: - repo-{{ .Environment.CIRCLE_SHA1 }} - run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-extensions @0x/contracts-asset-proxy @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-dev-utils @0x/contracts-staking test-contracts-ganache-3.0: + resource_class: medium+ docker: - - image: circleci/node:9-browsers + - image: nikolaik/python-nodejs:python3.7-nodejs8 working_directory: ~/repo steps: - restore_cache: @@ -101,7 +110,7 @@ jobs: # - run: yarn wsrun test:circleci @0x/contracts-coordinator test-contracts-geth: docker: - - image: circleci/node:9-browsers + - image: nikolaik/python-nodejs:python3.7-nodejs8 - image: 0xorg/devnet working_directory: ~/repo steps: @@ -114,7 +123,7 @@ jobs: test-publish: resource_class: medium+ docker: - - image: circleci/node:9-browsers + - image: nikolaik/python-nodejs:python3.7-nodejs8 - image: 0xorg/verdaccio working_directory: ~/repo steps: @@ -124,7 +133,7 @@ jobs: - run: yarn test:publish:circleci test-doc-generation: docker: - - image: circleci/node:9-browsers + - image: nikolaik/python-nodejs:python3.7-nodejs8 working_directory: ~/repo steps: - restore_cache: @@ -133,7 +142,7 @@ jobs: - run: yarn test:generate_docs:circleci test-rest: docker: - - image: circleci/node:9-browsers + - image: nikolaik/python-nodejs:python3.7-nodejs8 working_directory: ~/repo steps: - restore_cache: @@ -150,7 +159,6 @@ jobs: - run: yarn wsrun test:circleci @0x/dev-utils - run: yarn wsrun test:circleci @0x/json-schemas - run: yarn wsrun test:circleci @0x/order-utils - - run: yarn wsrun test:circleci @0x/order-watcher - run: yarn wsrun test:circleci @0x/sol-compiler - run: yarn wsrun test:circleci @0x/sol-tracing-utils - run: yarn wsrun test:circleci @0x/sol-doc @@ -194,10 +202,6 @@ jobs: key: coverage-order-utils-{{ .Environment.CIRCLE_SHA1 }} paths: - ~/repo/packages/order-utils/coverage/lcov.info - - save_cache: - key: coverage-order-watcher-{{ .Environment.CIRCLE_SHA1 }} - paths: - - ~/repo/packages/order-watcher/coverage/lcov.info - save_cache: key: coverage-sol-compiler-{{ .Environment.CIRCLE_SHA1 }} paths: @@ -219,8 +223,9 @@ jobs: paths: - ~/repo/packages/web3-wrapper/coverage/lcov.info test-rest-3.0: + resource_class: medium+ docker: - - image: circleci/node:9-browsers + - image: nikolaik/python-nodejs:python3.7-nodejs8 working_directory: ~/repo steps: - restore_cache: @@ -290,18 +295,17 @@ jobs: test-python: working_directory: ~/repo docker: - - image: circleci/python + - image: nikolaik/python-nodejs:python3.7-nodejs8 - image: 0xorg/ganache-cli:2.2.2 - - image: 0xorg/launch-kit-ci + - image: 0xorg/launch-kit-backend:74bcc39 environment: RPC_URL: http://localhost:8545 NETWORK_ID: 50 WHITELIST_ALL_TOKENS: True - command: bash -c "until curl -sfd'{\"method\":\"net_listening\"}' http://localhost:8545 | grep true; do continue; done; forever ts/lib/index.js" + command: | + sh -c "until printf 'POST /\r\nContent-Length: 26\r\n\r\n{\"method\":\"net_listening\"}' | nc localhost 8545 | grep true; do continue; done; node_modules/.bin/forever ts/lib/index.js" steps: - checkout - - run: sudo chown -R circleci:circleci /usr/local/bin - - run: sudo chown -R circleci:circleci /usr/local/lib/python3.7 - restore_cache: key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }} - restore_cache: @@ -320,7 +324,7 @@ jobs: - run: command: | cd python-packages - ./parallel coverage run setup.py test + ./parallel_without_sra_client coverage run setup.py test ./build_docs - save_cache: key: coverage-python-contract-addresses-{{ .Environment.CIRCLE_SHA1 }} @@ -367,11 +371,9 @@ jobs: test-rest-python: working_directory: ~/repo docker: - - image: circleci/python + - image: nikolaik/python-nodejs:python3.7-nodejs8 steps: - checkout - - run: sudo chown -R circleci:circleci /usr/local/bin - - run: sudo chown -R circleci:circleci /usr/local/lib/python3.7 - restore_cache: key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }} - run: @@ -395,11 +397,9 @@ jobs: static-tests-python: working_directory: ~/repo docker: - - image: circleci/python + - image: nikolaik/python-nodejs:python3.7-nodejs8 steps: - checkout - - run: sudo chown -R circleci:circleci /usr/local/bin - - run: sudo chown -R circleci:circleci /usr/local/lib/python3.7 - restore_cache: key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }} - restore_cache: @@ -414,7 +414,7 @@ jobs: static-tests: working_directory: ~/repo docker: - - image: circleci/node:9-browsers + - image: nikolaik/python-nodejs:python3.7-nodejs8 steps: - restore_cache: keys: @@ -427,7 +427,7 @@ jobs: static-tests-3.0: working_directory: ~/repo docker: - - image: circleci/node:9-browsers + - image: nikolaik/python-nodejs:python3.7-nodejs8 steps: - restore_cache: keys: @@ -437,7 +437,7 @@ jobs: - run: yarn deps_versions:ci submit-coverage: docker: - - image: circleci/node:9-browsers + - image: nikolaik/python-nodejs:python3.7-nodejs8 working_directory: ~/repo steps: - restore_cache: @@ -470,9 +470,6 @@ jobs: - restore_cache: keys: - coverage-order-utils-{{ .Environment.CIRCLE_SHA1 }} - - restore_cache: - keys: - - coverage-order-watcher-{{ .Environment.CIRCLE_SHA1 }} - restore_cache: keys: - coverage-sol-compiler-{{ .Environment.CIRCLE_SHA1 }} @@ -512,7 +509,7 @@ jobs: - run: yarn report_coverage submit-coverage-3.0: docker: - - image: circleci/node:9-browsers + - image: nikolaik/python-nodejs:python3.7-nodejs8 working_directory: ~/repo steps: - restore_cache: diff --git a/.gitattributes b/.gitattributes index f6d6b3c00a..10ff8a1bc3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,4 +4,5 @@ *.svg linguist-generated=true packages/contract-artifacts/artifacts/*json linguist-generated=true packages/abi-gen-wrappers/src/generated-wrappers/*.ts linguist-generated=true +packages/contract-wrappers/src/generated-wrappers/*.ts linguist-generated=true diff --git a/.github/autolabeler.yml b/.github/autolabeler.yml index 70ba92e871..56e045a82e 100644 --- a/.github/autolabeler.yml +++ b/.github/autolabeler.yml @@ -21,10 +21,7 @@ contracts: ['contracts'] @0x/utils: ['packages/utils'] @0x/tslint-config: ['packages/tslint-config'] @0x/asset-buyer: ['packages/asset-buyer'] -@0x/order-watcher: ['packages/order-watcher'] -@0x/react-docs: ['packages/react-docs'] @0x/order-utils: ['packages/order-utils'] -@0x/react-shared: ['packages/react-shared'] @0x/assert: ['packages/assert'] @0x/base-contract: ['packages/base-contract'] @0x/typescript-typings: ['packages/typescript-typings'] diff --git a/.gitignore b/.gitignore index 2f2bba325d..5e5b05b5a2 100644 --- a/.gitignore +++ b/.gitignore @@ -77,7 +77,6 @@ TODO.md packages/website/public/bundle* packages/dev-tools-pages/public/bundle* -packages/react-docs/example/public/bundle* # server cli packages/testnet-faucets/server/ @@ -117,6 +116,24 @@ contracts/exchange-forwarder/generated-wrappers/ contracts/dev-utils/generated-wrappers/ python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc20_token/__init__.py python-packages/contract_wrappers/src/zero_ex/contract_wrappers/exchange/__init__.py +python-packages/contract_wrappers/src/zero_ex/contract_wrappers/asset_proxy_owner/__init__.py +python-packages/contract_wrappers/src/zero_ex/contract_wrappers/coordinator/__init__.py +python-packages/contract_wrappers/src/zero_ex/contract_wrappers/coordinator_registry/__init__.py +python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dummy_erc20_token/__init__.py +python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dummy_erc721_token/__init__.py +python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dutch_auction/__init__.py +python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc20_proxy/__init__.py +python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc721_proxy/__init__.py +python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc721_token/__init__.py +python-packages/contract_wrappers/src/zero_ex/contract_wrappers/eth_balance_checker/__init__.py +python-packages/contract_wrappers/src/zero_ex/contract_wrappers/forwarder/__init__.py +python-packages/contract_wrappers/src/zero_ex/contract_wrappers/i_asset_proxy/__init__.py +python-packages/contract_wrappers/src/zero_ex/contract_wrappers/i_validator/__init__.py +python-packages/contract_wrappers/src/zero_ex/contract_wrappers/i_wallet/__init__.py +python-packages/contract_wrappers/src/zero_ex/contract_wrappers/multi_asset_proxy/__init__.py +python-packages/contract_wrappers/src/zero_ex/contract_wrappers/order_validator/__init__.py +python-packages/contract_wrappers/src/zero_ex/contract_wrappers/weth9/__init__.py +python-packages/contract_wrappers/src/zero_ex/contract_wrappers/zrx_token/__init__.py # cli test output packages/abi-gen/test-cli/output diff --git a/README.md b/README.md index 334c45da34..8bd08e67b5 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ Visit our [developer portal](https://0xproject.com/docs/order-utils) for a compr | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | | [`0x-contract-addresses`](/python-packages/contract_addresses) | [![PyPI](https://img.shields.io/pypi/v/0x-contract-addresses.svg)](https://pypi.org/project/0x-contract-addresses/) | A tiny utility library for getting known deployed contract addresses for a particular network | | [`0x-contract-artifacts`](/python-packages/contract_artifacts) | [![PyPI](https://img.shields.io/pypi/v/0x-contract-artifacts.svg)](https://pypi.org/project/0x-contract-artifacts/) | 0x smart contract compilation artifacts | +| [`0x-contract-wrappers`](/python-packages/contract_wrappers) | [![PyPI](https://img.shields.io/pypi/v/0x-contract-wrappers.svg)](https://pypi.org/project/0x-contract-wrappers/) | 0x smart contract wrappers | | [`0x-json-schemas`](/python-packages/json_schemas) | [![PyPI](https://img.shields.io/pypi/v/0x-json-schemas.svg)](https://pypi.org/project/0x-json-schemas/) | 0x-related JSON schemas | | [`0x-order-utils`](/python-packages/order_utils) | [![PyPI](https://img.shields.io/pypi/v/0x-order-utils.svg)](https://pypi.org/project/0x-order-utils/) | A set of utilities for generating, parsing, signing and validating 0x orders | | [`0x-sra-client`](/python-packages/sra_client) | [![PyPI](https://img.shields.io/pypi/v/0x-sra-client.svg)](https://pypi.org/project/0x-sra-client/) | A Python client for interacting with servers conforming to the Standard Relayer API specification | @@ -63,8 +64,7 @@ These packages are all under development. See [/contracts/README.md](/contracts/ | [`@0x/contract-addresses`](/packages/contract-addresses) | [![npm](https://img.shields.io/npm/v/@0x/contract-addresses.svg)](https://www.npmjs.com/package/@0x/contract-addresses) | A tiny utility library for getting known deployed contract addresses for a particular network. | | [`@0x/contract-wrappers`](/packages/contract-wrappers) | [![npm](https://img.shields.io/npm/v/@0x/contract-wrappers.svg)](https://www.npmjs.com/package/@0x/contract-wrappers) | JS/TS wrappers for interacting with the 0x smart contracts | | [`@0x/order-utils`](/packages/order-utils) | [![npm](https://img.shields.io/npm/v/@0x/order-utils.svg)](https://www.npmjs.com/package/@0x/order-utils) | A set of utilities for generating, parsing, signing and validating 0x orders | -| [`@0x/json-schemas`](/packages/json-schemas) | [![npm](https://img.shields.io/npm/v/@0x/json-schemas.svg)](https://www.npmjs.com/package/@0x/json-schemas) | 0x-related JSON schemas | -| [`@0x/order-watcher`](/packages/order-watcher) | [![npm](https://img.shields.io/npm/v/@0x/order-watcher.svg)](https://www.npmjs.com/package/@0x/order-watcher) | An order watcher daemon that watches for order validity | +| [`@0x/json-schemas`](/packages/json-schemas) | [![npm](https://img.shields.io/npm/v/@0x/json-schemas.svg)](https://www.npmjs.com/package/@0x/json-schemas) | 0x-related JSON schemas | | | [`@0x/migrations`](/packages/migrations) | [![npm](https://img.shields.io/npm/v/@0x/migrations.svg)](https://www.npmjs.com/package/@0x/migrations) | Migration tool for deploying 0x smart contracts on private testnets | | [`@0x/contract-artifacts`](/packages/contract-artifacts) | [![npm](https://img.shields.io/npm/v/@0x/contract-artifacts.svg)](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts | | [`@0x/abi-gen-wrappers`](/packages/abi-gen-wrappers) | [![npm](https://img.shields.io/npm/v/@0x/abi-gen-wrappers.svg)](https://www.npmjs.com/package/@0x/abi-gen-wrappers) | Low-level 0x smart contract wrappers generated using `@0x/abi-gen` | @@ -88,19 +88,17 @@ These packages are all under development. See [/contracts/README.md](/contracts/ #### Utilities -| Package | Version | Description | -| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | -| [`@0x/abi-gen`](/packages/abi-gen) | [![npm](https://img.shields.io/npm/v/@0x/abi-gen.svg)](https://www.npmjs.com/package/@0x/abi-gen) | Tool to generate TS wrappers from smart contract ABIs | -| [`@0x/tslint-config`](/packages/tslint-config) | [![npm](https://img.shields.io/npm/v/@0x/tslint-config.svg)](https://www.npmjs.com/package/@0x/tslint-config) | Custom TSLint rules used by the 0x core team | -| [`@0x/types`](/packages/types) | [![npm](https://img.shields.io/npm/v/@0x/types.svg)](https://www.npmjs.com/package/@0x/types) | Shared type declarations | -| [`@0x/typescript-typings`](/packages/typescript-typings) | [![npm](https://img.shields.io/npm/v/@0x/typescript-typings.svg)](https://www.npmjs.com/package/@0x/typescript-typings) | Repository of types for external packages | -| [`@0x/utils`](/packages/utils) | [![npm](https://img.shields.io/npm/v/@0x/utils.svg)](https://www.npmjs.com/package/@0x/utils) | Shared utilities | -| [`@0x/react-docs`](/packages/react-docs) | [![npm](https://img.shields.io/npm/v/@0x/react-docs.svg)](https://www.npmjs.com/package/@0x/react-docs) | React documentation component for rendering TypeDoc & sol-doc generated JSON | -| [`@0x/react-shared`](/packages/react-shared) | [![npm](https://img.shields.io/npm/v/@0x/react-shared.svg)](https://www.npmjs.com/package/@0x/react-shared) | 0x shared react components | -| [`@0x/assert`](/packages/assert) | [![npm](https://img.shields.io/npm/v/@0x/assert.svg)](https://www.npmjs.com/package/@0x/assert) | Type and schema assertions used by our packages | -| [`@0x/base-contract`](/packages/base-contract) | [![npm](https://img.shields.io/npm/v/@0x/base-contract.svg)](https://www.npmjs.com/package/@0x/base-contract) | BaseContract used by auto-generated `abi-gen` wrapper contracts | -| [`@0x/dev-utils`](/packages/dev-utils) | [![npm](https://img.shields.io/npm/v/@0x/dev-utils.svg)](https://www.npmjs.com/package/@0x/dev-utils) | Dev utils to be shared across 0x packages | -| [`@0x/fill-scenarios`](/packages/fill-scenarios) | [![npm](https://img.shields.io/npm/v/@0x/fill-scenarios.svg)](https://www.npmjs.com/package/@0x/fill-scenarios) | 0x order fill scenario generator | +| Package | Version | Description | +| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | +| [`@0x/abi-gen`](/packages/abi-gen) | [![npm](https://img.shields.io/npm/v/@0x/abi-gen.svg)](https://www.npmjs.com/package/@0x/abi-gen) | Tool to generate TS wrappers from smart contract ABIs | +| [`@0x/tslint-config`](/packages/tslint-config) | [![npm](https://img.shields.io/npm/v/@0x/tslint-config.svg)](https://www.npmjs.com/package/@0x/tslint-config) | Custom TSLint rules used by the 0x core team | +| [`@0x/types`](/packages/types) | [![npm](https://img.shields.io/npm/v/@0x/types.svg)](https://www.npmjs.com/package/@0x/types) | Shared type declarations | +| [`@0x/typescript-typings`](/packages/typescript-typings) | [![npm](https://img.shields.io/npm/v/@0x/typescript-typings.svg)](https://www.npmjs.com/package/@0x/typescript-typings) | Repository of types for external packages | +| [`@0x/utils`](/packages/utils) | [![npm](https://img.shields.io/npm/v/@0x/utils.svg)](https://www.npmjs.com/package/@0x/utils) | Shared utilities | +| [`@0x/assert`](/packages/assert) | [![npm](https://img.shields.io/npm/v/@0x/assert.svg)](https://www.npmjs.com/package/@0x/assert) | Type and schema assertions used by our packages | +| [`@0x/base-contract`](/packages/base-contract) | [![npm](https://img.shields.io/npm/v/@0x/base-contract.svg)](https://www.npmjs.com/package/@0x/base-contract) | BaseContract used by auto-generated `abi-gen` wrapper contracts | +| [`@0x/dev-utils`](/packages/dev-utils) | [![npm](https://img.shields.io/npm/v/@0x/dev-utils.svg)](https://www.npmjs.com/package/@0x/dev-utils) | Dev utils to be shared across 0x packages | +| [`@0x/fill-scenarios`](/packages/fill-scenarios) | [![npm](https://img.shields.io/npm/v/@0x/fill-scenarios.svg)](https://www.npmjs.com/package/@0x/fill-scenarios) | 0x order fill scenario generator | #### Private Packages diff --git a/contracts/asset-proxy/CHANGELOG.json b/contracts/asset-proxy/CHANGELOG.json index 3550e36264..b71f16f77c 100644 --- a/contracts/asset-proxy/CHANGELOG.json +++ b/contracts/asset-proxy/CHANGELOG.json @@ -16,6 +16,34 @@ } ] }, + { + "timestamp": 1565296576, + "version": "2.2.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "version": "2.2.4", + "changes": [ + { + "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", + "pr": 1995 + } + ], + "timestamp": 1564607468 + }, + { + "timestamp": 1563957393, + "version": "2.2.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563193019, "version": "2.2.2", diff --git a/contracts/asset-proxy/CHANGELOG.md b/contracts/asset-proxy/CHANGELOG.md index ced104961f..8ddca3df18 100644 --- a/contracts/asset-proxy/CHANGELOG.md +++ b/contracts/asset-proxy/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.2.5 - _August 8, 2019_ + + * Dependencies updated + +## v2.2.4 - _July 31, 2019_ + + * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) + +## v2.2.3 - _July 24, 2019_ + + * Dependencies updated + ## v2.2.2 - _July 15, 2019_ * Dependencies updated diff --git a/contracts/asset-proxy/package.json b/contracts/asset-proxy/package.json index 8f8b2a64e1..ded6fce96b 100644 --- a/contracts/asset-proxy/package.json +++ b/contracts/asset-proxy/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-asset-proxy", - "version": "2.2.2", + "version": "2.2.5", "engines": { "node": ">=6.12" }, @@ -47,20 +47,21 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md", "devDependencies": { - "@0x/abi-gen": "^2.1.1", - "@0x/contracts-gen": "^1.0.10", - "@0x/contracts-test-utils": "^3.1.10", - "@0x/dev-utils": "^2.2.4", - "@0x/sol-compiler": "^3.1.9", + "@0x/abi-gen": "^4.1.0", + "@0x/contracts-gen": "^1.0.13", + "@0x/contracts-test-utils": "^3.1.13", + "@0x/dev-utils": "^2.3.0", + "@0x/sol-compiler": "^3.1.12", "@0x/tslint-config": "^3.0.1", "@types/lodash": "4.14.104", + "@types/mocha": "^5.2.7", "@types/node": "*", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^3.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", "solhint": "^1.4.1", @@ -68,17 +69,17 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/base-contract": "^5.1.1", - "@0x/contracts-erc1155": "^1.1.9", - "@0x/contracts-erc20": "^2.2.8", - "@0x/contracts-erc721": "^2.1.9", - "@0x/contracts-utils": "^3.1.9", - "@0x/order-utils": "^8.2.2", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", - "ethereum-types": "^2.1.3", + "@0x/base-contract": "^5.3.1", + "@0x/contracts-erc1155": "^1.1.12", + "@0x/contracts-erc20": "^2.2.11", + "@0x/contracts-erc721": "^2.1.12", + "@0x/contracts-utils": "^3.2.1", + "@0x/order-utils": "^8.2.5", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", + "ethereum-types": "^2.1.4", "ethereumjs-util": "^5.1.1", "lodash": "^4.17.11" }, diff --git a/contracts/asset-proxy/test/authorizable.ts b/contracts/asset-proxy/test/authorizable.ts index 2f93334c6a..37b8cbaee1 100644 --- a/contracts/asset-proxy/test/authorizable.ts +++ b/contracts/asset-proxy/test/authorizable.ts @@ -39,6 +39,7 @@ describe('Authorizable', () => { artifacts.MixinAuthorizable, provider, txDefaults, + artifacts, ); }); diff --git a/contracts/asset-proxy/test/erc1155_proxy.ts b/contracts/asset-proxy/test/erc1155_proxy.ts index 3177ac6a9b..d67e6670ec 100644 --- a/contracts/asset-proxy/test/erc1155_proxy.ts +++ b/contracts/asset-proxy/test/erc1155_proxy.ts @@ -23,7 +23,7 @@ import { LogWithDecodedArgs } from 'ethereum-types'; import * as ethUtil from 'ethereumjs-util'; import * as _ from 'lodash'; -import { ERC1155ProxyWrapper, ERC721ProxyContract } from '../src'; +import { artifacts, ERC1155ProxyContract, ERC1155ProxyWrapper } from '../src'; chaiSetup.configure(); const expect = chai.expect; @@ -51,7 +51,7 @@ describe('ERC1155Proxy', () => { let receiver: string; let receiverContract: string; // contracts & wrappers - let erc1155Proxy: ERC721ProxyContract; + let erc1155Proxy: ERC1155ProxyContract; let erc1155Receiver: DummyERC1155ReceiverContract; let erc1155ProxyWrapper: ERC1155ProxyWrapper; let erc1155Contract: ERC1155MintableContract; @@ -89,6 +89,7 @@ describe('ERC1155Proxy', () => { erc1155Artifacts.DummyERC1155Receiver, provider, txDefaults, + artifacts, ); receiverContract = erc1155Receiver.address; await erc1155ProxyWrapper.setBalancesAndAllowancesAsync(); diff --git a/contracts/asset-proxy/test/proxies.ts b/contracts/asset-proxy/test/proxies.ts index b95e4f75e8..2d7d01aa9f 100644 --- a/contracts/asset-proxy/test/proxies.ts +++ b/contracts/asset-proxy/test/proxies.ts @@ -31,6 +31,7 @@ import * as _ from 'lodash'; import { artifacts, + ERC1155ProxyContract, ERC1155ProxyWrapper, ERC20ProxyContract, ERC20Wrapper, @@ -71,7 +72,7 @@ describe('Asset Transfer Proxies', () => { let erc721AFromTokenId: BigNumber; let erc721BFromTokenId: BigNumber; - let erc1155Proxy: ERC721ProxyContract; + let erc1155Proxy: ERC1155ProxyContract; let erc1155ProxyWrapper: ERC1155ProxyWrapper; let erc1155Contract: ERC1155MintableContract; let erc1155Contract2: ERC1155MintableContract; @@ -100,6 +101,7 @@ describe('Asset Transfer Proxies', () => { artifacts.MultiAssetProxy, provider, txDefaults, + artifacts, ); // Configure ERC20Proxy @@ -172,6 +174,7 @@ describe('Asset Transfer Proxies', () => { erc20Artifacts.DummyNoReturnERC20Token, provider, txDefaults, + artifacts, constants.DUMMY_TOKEN_NAME, constants.DUMMY_TOKEN_SYMBOL, constants.DUMMY_TOKEN_DECIMALS, @@ -181,6 +184,7 @@ describe('Asset Transfer Proxies', () => { erc20Artifacts.DummyMultipleReturnERC20Token, provider, txDefaults, + artifacts, constants.DUMMY_TOKEN_NAME, constants.DUMMY_TOKEN_SYMBOL, constants.DUMMY_TOKEN_DECIMALS, @@ -223,6 +227,7 @@ describe('Asset Transfer Proxies', () => { erc721Artifacts.DummyERC721Receiver, provider, txDefaults, + artifacts, ); await erc721Wrapper.setBalancesAndAllowancesAsync(); diff --git a/contracts/asset-proxy/test/static_call_proxy.ts b/contracts/asset-proxy/test/static_call_proxy.ts index 36f38785a2..a1cf95a4d3 100644 --- a/contracts/asset-proxy/test/static_call_proxy.ts +++ b/contracts/asset-proxy/test/static_call_proxy.ts @@ -41,12 +41,14 @@ describe('StaticCallProxy', () => { artifacts.StaticCallProxy, provider, txDefaults, + artifacts, ); staticCallProxy = new IAssetProxyContract(staticCallProxyWithoutTransferFrom.address, provider, txDefaults); staticCallTarget = await TestStaticCallTargetContract.deployFrom0xArtifactAsync( artifacts.TestStaticCallTarget, provider, txDefaults, + artifacts, ); }); beforeEach(async () => { diff --git a/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts b/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts index a0205df93b..78c154df19 100644 --- a/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts +++ b/contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts @@ -54,6 +54,7 @@ export class ERC1155ProxyWrapper { erc1155Artifacts.ERC1155Mintable, this._provider, txDefaults, + artifacts, ); const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._provider, this._contractOwnerAddress); this._dummyTokenWrappers.push(erc1155Wrapper); @@ -69,6 +70,7 @@ export class ERC1155ProxyWrapper { artifacts.ERC1155Proxy, this._provider, txDefaults, + artifacts, ); this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync(); return this._proxyContract; diff --git a/contracts/asset-proxy/test/utils/erc20_wrapper.ts b/contracts/asset-proxy/test/utils/erc20_wrapper.ts index 2bb1702222..8fdd210b24 100644 --- a/contracts/asset-proxy/test/utils/erc20_wrapper.ts +++ b/contracts/asset-proxy/test/utils/erc20_wrapper.ts @@ -37,6 +37,7 @@ export class ERC20Wrapper { erc20Artifacts.DummyERC20Token, this._provider, txDefaults, + artifacts, constants.DUMMY_TOKEN_NAME, constants.DUMMY_TOKEN_SYMBOL, decimals, @@ -51,6 +52,7 @@ export class ERC20Wrapper { artifacts.ERC20Proxy, this._provider, txDefaults, + artifacts, ); this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync(); return this._proxyContract; diff --git a/contracts/asset-proxy/test/utils/erc721_wrapper.ts b/contracts/asset-proxy/test/utils/erc721_wrapper.ts index cfad9bf4a9..3ff03f3d19 100644 --- a/contracts/asset-proxy/test/utils/erc721_wrapper.ts +++ b/contracts/asset-proxy/test/utils/erc721_wrapper.ts @@ -29,6 +29,7 @@ export class ERC721Wrapper { erc721Artifacts.DummyERC721Token, this._provider, txDefaults, + artifacts, constants.DUMMY_TOKEN_NAME, constants.DUMMY_TOKEN_SYMBOL, ), @@ -41,6 +42,7 @@ export class ERC721Wrapper { artifacts.ERC721Proxy, this._provider, txDefaults, + artifacts, ); this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync(); return this._proxyContract; diff --git a/contracts/coordinator/CHANGELOG.json b/contracts/coordinator/CHANGELOG.json index ae186a592e..f95c9fe5f7 100644 --- a/contracts/coordinator/CHANGELOG.json +++ b/contracts/coordinator/CHANGELOG.json @@ -44,6 +44,34 @@ } ] }, + { + "timestamp": 1565296576, + "version": "2.0.10", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "version": "2.0.9", + "changes": [ + { + "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", + "pr": 1995 + } + ], + "timestamp": 1564607468 + }, + { + "timestamp": 1563957393, + "version": "2.0.8", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563193019, "version": "2.0.7", diff --git a/contracts/coordinator/CHANGELOG.md b/contracts/coordinator/CHANGELOG.md index 1659fe009e..4ecdce0d31 100644 --- a/contracts/coordinator/CHANGELOG.md +++ b/contracts/coordinator/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.10 - _August 8, 2019_ + + * Dependencies updated + +## v2.0.9 - _July 31, 2019_ + + * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) + +## v2.0.8 - _July 24, 2019_ + + * Dependencies updated + ## v2.0.7 - _July 15, 2019_ * Dependencies updated diff --git a/contracts/coordinator/package.json b/contracts/coordinator/package.json index 3cfdf27df0..4690659a29 100644 --- a/contracts/coordinator/package.json +++ b/contracts/coordinator/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-coordinator", - "version": "2.0.7", + "version": "2.0.10", "engines": { "node": ">=6.12" }, @@ -47,20 +47,21 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md", "devDependencies": { - "@0x/abi-gen": "^2.1.1", - "@0x/contracts-gen": "^1.0.10", - "@0x/contracts-test-utils": "^3.1.10", - "@0x/dev-utils": "^2.2.4", - "@0x/sol-compiler": "^3.1.9", + "@0x/abi-gen": "^4.1.0", + "@0x/contracts-gen": "^1.0.13", + "@0x/contracts-test-utils": "^3.1.13", + "@0x/dev-utils": "^2.3.0", + "@0x/sol-compiler": "^3.1.12", "@0x/tslint-config": "^3.0.1", "@types/lodash": "4.14.104", + "@types/mocha": "^5.2.7", "@types/node": "*", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^3.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", "solhint": "^1.4.1", @@ -68,18 +69,18 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/base-contract": "^5.1.1", - "@0x/contracts-asset-proxy": "^2.2.2", - "@0x/contracts-erc20": "^2.2.8", - "@0x/contracts-exchange": "^2.1.8", - "@0x/contracts-exchange-libs": "^3.0.2", - "@0x/contracts-utils": "^3.1.9", - "@0x/order-utils": "^8.2.2", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", - "ethereum-types": "^2.1.3", + "@0x/base-contract": "^5.3.1", + "@0x/contracts-asset-proxy": "^2.2.5", + "@0x/contracts-erc20": "^2.2.11", + "@0x/contracts-exchange": "^2.1.11", + "@0x/contracts-exchange-libs": "^3.0.5", + "@0x/contracts-utils": "^3.2.1", + "@0x/order-utils": "^8.2.5", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", + "ethereum-types": "^2.1.4", "ethereumjs-util": "^5.1.1", "lodash": "^4.17.11" }, diff --git a/contracts/coordinator/test/coordinator.ts b/contracts/coordinator/test/coordinator.ts index aab9c9538f..26f29458e9 100644 --- a/contracts/coordinator/test/coordinator.ts +++ b/contracts/coordinator/test/coordinator.ts @@ -96,6 +96,7 @@ describe('Coordinator tests', () => { artifacts.Coordinator, provider, txDefaults, + artifacts, exchange.address, new BigNumber(chainId), ); diff --git a/contracts/coordinator/test/libs.ts b/contracts/coordinator/test/libs.ts index a594cbd58c..6e584246d7 100644 --- a/contracts/coordinator/test/libs.ts +++ b/contracts/coordinator/test/libs.ts @@ -27,6 +27,7 @@ describe('Libs tests', () => { artifacts.Coordinator, provider, txDefaults, + artifacts, exchangeAddress, new BigNumber(chainId), ); diff --git a/contracts/coordinator/test/mixins.ts b/contracts/coordinator/test/mixins.ts index ce1fe22d5d..98b039ee88 100644 --- a/contracts/coordinator/test/mixins.ts +++ b/contracts/coordinator/test/mixins.ts @@ -48,6 +48,7 @@ describe('Mixins tests', () => { artifacts.Coordinator, provider, txDefaults, + artifacts, exchangeAddress, new BigNumber(chainId), ); diff --git a/contracts/coordinator/test/utils/coordinator_registry_wrapper.ts b/contracts/coordinator/test/utils/coordinator_registry_wrapper.ts index 3c80714225..3d7a2999ef 100644 --- a/contracts/coordinator/test/utils/coordinator_registry_wrapper.ts +++ b/contracts/coordinator/test/utils/coordinator_registry_wrapper.ts @@ -24,6 +24,7 @@ export class CoordinatorRegistryWrapper { artifacts.CoordinatorRegistry, this._provider, txDefaults, + artifacts, ); if (this._coordinatorRegistryContract === undefined) { throw new Error(`Failed to deploy Coordinator Registry contract.`); diff --git a/contracts/dev-utils/CHANGELOG.json b/contracts/dev-utils/CHANGELOG.json index e216383dca..fe23acc223 100644 --- a/contracts/dev-utils/CHANGELOG.json +++ b/contracts/dev-utils/CHANGELOG.json @@ -12,6 +12,43 @@ } ] }, + { + "timestamp": 1565296576, + "version": "0.0.7", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1564607468, + "version": "0.0.6", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "version": "0.0.5", + "changes": [ + { + "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", + "pr": 1995 + } + ], + "timestamp": 1564604963 + }, + { + "timestamp": 1563957393, + "version": "0.0.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563193019, "version": "0.0.4", diff --git a/contracts/dev-utils/CHANGELOG.md b/contracts/dev-utils/CHANGELOG.md index 4a8c0420a3..6ecac45fdf 100644 --- a/contracts/dev-utils/CHANGELOG.md +++ b/contracts/dev-utils/CHANGELOG.md @@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v0.0.7 - _August 8, 2019_ + + * Dependencies updated + +## v0.0.6 - _July 31, 2019_ + + * Dependencies updated + +## v0.0.5 - _July 31, 2019_ + + * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) + +## v0.0.5 - _July 24, 2019_ + + * Dependencies updated + ## v0.0.4 - _July 15, 2019_ * Dependencies updated diff --git a/contracts/dev-utils/package.json b/contracts/dev-utils/package.json index 0f5e18e359..ff5ac66184 100644 --- a/contracts/dev-utils/package.json +++ b/contracts/dev-utils/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-dev-utils", - "version": "0.0.4", + "version": "0.0.7", "engines": { "node": ">=6.12" }, @@ -47,20 +47,21 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/dev-utils/README.md", "devDependencies": { - "@0x/abi-gen": "^2.1.1", - "@0x/contracts-gen": "^1.0.10", - "@0x/contracts-test-utils": "^3.1.10", - "@0x/dev-utils": "^2.2.4", - "@0x/sol-compiler": "^3.1.9", + "@0x/abi-gen": "^4.1.0", + "@0x/contracts-gen": "^1.0.13", + "@0x/contracts-test-utils": "^3.1.13", + "@0x/dev-utils": "^2.3.0", + "@0x/sol-compiler": "^3.1.12", "@0x/tslint-config": "^3.0.1", "@types/lodash": "4.14.104", + "@types/mocha": "^5.2.7", "@types/node": "*", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^3.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", "solhint": "^1.4.1", @@ -68,20 +69,20 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/base-contract": "^5.1.1", - "@0x/contracts-asset-proxy": "^2.2.2", - "@0x/contracts-erc1155": "^1.1.9", - "@0x/contracts-erc20": "^2.2.8", - "@0x/contracts-erc721": "^2.1.9", - "@0x/contracts-exchange": "^2.1.8", - "@0x/contracts-exchange-libs": "^3.0.2", - "@0x/contracts-utils": "^3.1.9", - "@0x/order-utils": "^8.2.2", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", - "ethereum-types": "^2.1.3", + "@0x/base-contract": "^5.3.1", + "@0x/contracts-asset-proxy": "^2.2.5", + "@0x/contracts-erc1155": "^1.1.12", + "@0x/contracts-erc20": "^2.2.11", + "@0x/contracts-erc721": "^2.1.12", + "@0x/contracts-exchange": "^2.1.11", + "@0x/contracts-exchange-libs": "^3.0.5", + "@0x/contracts-utils": "^3.2.1", + "@0x/order-utils": "^8.2.5", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", + "ethereum-types": "^2.1.4", "ethereumjs-util": "^5.1.1" }, "publishConfig": { diff --git a/contracts/dev-utils/test/lib_asset_data.ts b/contracts/dev-utils/test/lib_asset_data.ts index 03a67999e8..3707b34280 100644 --- a/contracts/dev-utils/test/lib_asset_data.ts +++ b/contracts/dev-utils/test/lib_asset_data.ts @@ -92,6 +92,7 @@ describe('LibAssetData', () => { exchangeArtifacts.Exchange, provider, txDefaults, + {}, new BigNumber(chainId), ); @@ -99,26 +100,31 @@ describe('LibAssetData', () => { proxyArtifacts.ERC20Proxy, provider, txDefaults, + artifacts, ); erc721Proxy = await ERC721ProxyContract.deployFrom0xArtifactAsync( proxyArtifacts.ERC721Proxy, provider, txDefaults, + artifacts, ); erc1155Proxy = await ERC1155ProxyContract.deployFrom0xArtifactAsync( proxyArtifacts.ERC1155Proxy, provider, txDefaults, + artifacts, ); multiAssetProxy = await MultiAssetProxyContract.deployFrom0xArtifactAsync( proxyArtifacts.MultiAssetProxy, provider, txDefaults, + artifacts, ); staticCallProxy = await StaticCallProxyContract.deployFrom0xArtifactAsync( proxyArtifacts.StaticCallProxy, provider, txDefaults, + artifacts, ); await exchange.registerAssetProxy.awaitTransactionSuccessAsync(erc20Proxy.address); @@ -131,6 +137,7 @@ describe('LibAssetData', () => { artifacts.LibAssetData, provider, txDefaults, + artifacts, exchange.address, ); @@ -138,6 +145,7 @@ describe('LibAssetData', () => { proxyArtifacts.TestStaticCallTarget, provider, txDefaults, + artifacts, ); [tokenOwnerAddress] = await web3Wrapper.getAvailableAddressesAsync(); @@ -146,6 +154,7 @@ describe('LibAssetData', () => { erc20Artifacts.DummyERC20Token, provider, txDefaults, + artifacts, 'Dummy', 'DUM', new BigNumber(1), @@ -156,6 +165,7 @@ describe('LibAssetData', () => { erc721Artifacts.DummyERC721Token, provider, txDefaults, + artifacts, 'Dummy', 'DUM', ); @@ -172,6 +182,7 @@ describe('LibAssetData', () => { erc1155Artifacts.ERC1155Mintable, provider, txDefaults, + artifacts, ); const logDecoder = new LogDecoder(web3Wrapper, erc1155Artifacts); diff --git a/contracts/dev-utils/test/lib_transaction_decoder.ts b/contracts/dev-utils/test/lib_transaction_decoder.ts index efa8dd8593..4cb91233e6 100644 --- a/contracts/dev-utils/test/lib_transaction_decoder.ts +++ b/contracts/dev-utils/test/lib_transaction_decoder.ts @@ -39,6 +39,7 @@ describe('LibTransactionDecoder', () => { artifacts.LibTransactionDecoder, provider, txDefaults, + artifacts, ); }); after(async () => { diff --git a/contracts/dev-utils/test/order_validation_utils.ts b/contracts/dev-utils/test/order_validation_utils.ts index 0e08a28b82..58d2df4eca 100644 --- a/contracts/dev-utils/test/order_validation_utils.ts +++ b/contracts/dev-utils/test/order_validation_utils.ts @@ -84,6 +84,7 @@ describe('OrderValidationUtils/OrderTransferSimulatorUtils', () => { exchangeArtifacts.Exchange, provider, txDefaults, + {}, new BigNumber(chainId), ); @@ -91,6 +92,7 @@ describe('OrderValidationUtils/OrderTransferSimulatorUtils', () => { proxyArtifacts.MultiAssetProxy, provider, txDefaults, + artifacts, ); const exchangeWrapper = new ExchangeWrapper(exchange, provider); await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner); @@ -103,6 +105,7 @@ describe('OrderValidationUtils/OrderTransferSimulatorUtils', () => { artifacts.DevUtils, provider, txDefaults, + artifacts, exchange.address, ); diff --git a/contracts/erc1155/CHANGELOG.json b/contracts/erc1155/CHANGELOG.json index 936de68fcb..84aa34a58d 100644 --- a/contracts/erc1155/CHANGELOG.json +++ b/contracts/erc1155/CHANGELOG.json @@ -1,6 +1,6 @@ [ { - "version": "1.1.10", + "version": "1.1.13", "changes": [ { "note": "Add `mintKnownFungibleTokensAsync()`, `isNonFungibleItemAsync()`, `isFungibleItemAsync()`, `getOwnerOfAsync()`, `getBalanceAsync()` to `Erc1155Wrapper`.", @@ -8,6 +8,34 @@ } ] }, + { + "timestamp": 1565296576, + "version": "1.1.12", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "version": "1.1.11", + "changes": [ + { + "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", + "pr": 1995 + } + ], + "timestamp": 1564604963 + }, + { + "timestamp": 1563957393, + "version": "1.1.10", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563193019, "version": "1.1.9", diff --git a/contracts/erc1155/CHANGELOG.md b/contracts/erc1155/CHANGELOG.md index bb969015c0..316c9beceb 100644 --- a/contracts/erc1155/CHANGELOG.md +++ b/contracts/erc1155/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.1.12 - _August 8, 2019_ + + * Dependencies updated + +## v1.1.11 - _July 31, 2019_ + + * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) + +## v1.1.10 - _July 24, 2019_ + + * Dependencies updated + ## v1.1.9 - _July 15, 2019_ * Dependencies updated diff --git a/contracts/erc1155/package.json b/contracts/erc1155/package.json index 41295f7c5f..9d18486694 100644 --- a/contracts/erc1155/package.json +++ b/contracts/erc1155/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-erc1155", - "version": "1.1.9", + "version": "1.1.12", "engines": { "node": ">=6.12" }, @@ -47,19 +47,20 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md", "devDependencies": { - "@0x/abi-gen": "^2.1.1", - "@0x/contracts-gen": "^1.0.10", - "@0x/dev-utils": "^2.2.4", - "@0x/sol-compiler": "^3.1.9", + "@0x/abi-gen": "^4.1.0", + "@0x/contracts-gen": "^1.0.13", + "@0x/dev-utils": "^2.3.0", + "@0x/sol-compiler": "^3.1.12", "@0x/tslint-config": "^3.0.1", "@types/lodash": "4.14.104", + "@types/mocha": "^5.2.7", "@types/node": "*", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^3.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", "solhint": "^1.4.1", @@ -67,14 +68,14 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/base-contract": "^5.1.1", - "@0x/contracts-test-utils": "^3.1.10", - "@0x/contracts-utils": "^3.1.9", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", - "ethereum-types": "^2.1.3", + "@0x/base-contract": "^5.3.1", + "@0x/contracts-test-utils": "^3.1.13", + "@0x/contracts-utils": "^3.2.1", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", + "ethereum-types": "^2.1.4", "lodash": "^4.17.11" }, "publishConfig": { diff --git a/contracts/erc1155/test/erc1155_token.ts b/contracts/erc1155/test/erc1155_token.ts index 29315c065d..147896937b 100644 --- a/contracts/erc1155/test/erc1155_token.ts +++ b/contracts/erc1155/test/erc1155_token.ts @@ -59,11 +59,13 @@ describe('ERC1155Token', () => { artifacts.ERC1155Mintable, provider, txDefaults, + artifacts, ); erc1155Receiver = await DummyERC1155ReceiverContract.deployFrom0xArtifactAsync( artifacts.DummyERC1155Receiver, provider, txDefaults, + artifacts, ); receiver = erc1155Receiver.address; // create wrapper & mint erc1155 tokens diff --git a/contracts/erc20/CHANGELOG.json b/contracts/erc20/CHANGELOG.json index 0151b32f3b..1b4511b492 100644 --- a/contracts/erc20/CHANGELOG.json +++ b/contracts/erc20/CHANGELOG.json @@ -1,4 +1,32 @@ [ + { + "timestamp": 1565296576, + "version": "2.2.11", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "version": "2.2.10", + "changes": [ + { + "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", + "pr": 1995 + } + ], + "timestamp": 1564604963 + }, + { + "timestamp": 1563957393, + "version": "2.2.9", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563193019, "version": "2.2.8", diff --git a/contracts/erc20/CHANGELOG.md b/contracts/erc20/CHANGELOG.md index a77399445a..21afb013a5 100644 --- a/contracts/erc20/CHANGELOG.md +++ b/contracts/erc20/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.2.11 - _August 8, 2019_ + + * Dependencies updated + +## v2.2.10 - _July 31, 2019_ + + * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) + +## v2.2.9 - _July 24, 2019_ + + * Dependencies updated + ## v2.2.8 - _July 15, 2019_ * Dependencies updated diff --git a/contracts/erc20/package.json b/contracts/erc20/package.json index bbb5ff93e6..155825a4e9 100644 --- a/contracts/erc20/package.json +++ b/contracts/erc20/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-erc20", - "version": "2.2.8", + "version": "2.2.11", "engines": { "node": ">=6.12" }, @@ -47,20 +47,21 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md", "devDependencies": { - "@0x/abi-gen": "^2.1.1", - "@0x/contracts-gen": "^1.0.10", - "@0x/contracts-test-utils": "^3.1.10", - "@0x/dev-utils": "^2.2.4", - "@0x/sol-compiler": "^3.1.9", + "@0x/abi-gen": "^4.1.0", + "@0x/contracts-gen": "^1.0.13", + "@0x/contracts-test-utils": "^3.1.13", + "@0x/dev-utils": "^2.3.0", + "@0x/sol-compiler": "^3.1.12", "@0x/tslint-config": "^3.0.1", "@types/lodash": "4.14.104", + "@types/mocha": "^5.2.7", "@types/node": "*", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^3.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", "solhint": "^1.4.1", @@ -68,13 +69,13 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/base-contract": "^5.1.1", - "@0x/contracts-utils": "^3.1.9", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", - "ethereum-types": "^2.1.3", + "@0x/base-contract": "^5.3.1", + "@0x/contracts-utils": "^3.2.1", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", + "ethereum-types": "^2.1.4", "lodash": "^4.17.11" }, "publishConfig": { diff --git a/contracts/erc20/test/unlimited_allowance_token.ts b/contracts/erc20/test/unlimited_allowance_token.ts index e31507d7ab..9d9de2ab01 100644 --- a/contracts/erc20/test/unlimited_allowance_token.ts +++ b/contracts/erc20/test/unlimited_allowance_token.ts @@ -37,6 +37,7 @@ describe('UnlimitedAllowanceToken', () => { artifacts.DummyERC20Token, provider, txDefaults, + artifacts, constants.DUMMY_TOKEN_NAME, constants.DUMMY_TOKEN_SYMBOL, constants.DUMMY_TOKEN_DECIMALS, diff --git a/contracts/erc20/test/weth9.ts b/contracts/erc20/test/weth9.ts index 444a8c3ef6..e410880a6e 100644 --- a/contracts/erc20/test/weth9.ts +++ b/contracts/erc20/test/weth9.ts @@ -33,10 +33,15 @@ describe('EtherToken', () => { const accounts = await web3Wrapper.getAvailableAddressesAsync(); account = accounts[0]; - etherToken = await WETH9Contract.deployFrom0xArtifactAsync(artifacts.WETH9, provider, { - gasPrice, - ...txDefaults, - }); + etherToken = await WETH9Contract.deployFrom0xArtifactAsync( + artifacts.WETH9, + provider, + { + gasPrice, + ...txDefaults, + }, + artifacts, + ); }); beforeEach(async () => { await blockchainLifecycle.startAsync(); diff --git a/contracts/erc20/test/zrx_token.ts b/contracts/erc20/test/zrx_token.ts index 820b054e6b..a148fc0d85 100644 --- a/contracts/erc20/test/zrx_token.ts +++ b/contracts/erc20/test/zrx_token.ts @@ -26,7 +26,12 @@ describe('ZRXToken', () => { const accounts = await web3Wrapper.getAvailableAddressesAsync(); owner = accounts[0]; spender = accounts[1]; - zrxToken = await ZRXTokenContract.deployFrom0xArtifactAsync(artifacts.ZRXToken, provider, txDefaults); + zrxToken = await ZRXTokenContract.deployFrom0xArtifactAsync( + artifacts.ZRXToken, + provider, + txDefaults, + artifacts, + ); MAX_UINT = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; }); beforeEach(async () => { diff --git a/contracts/erc721/CHANGELOG.json b/contracts/erc721/CHANGELOG.json index 6aacaf1a84..fa0e462ac2 100644 --- a/contracts/erc721/CHANGELOG.json +++ b/contracts/erc721/CHANGELOG.json @@ -1,4 +1,32 @@ [ + { + "timestamp": 1565296576, + "version": "2.1.12", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "version": "2.1.11", + "changes": [ + { + "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", + "pr": 1995 + } + ], + "timestamp": 1564604963 + }, + { + "timestamp": 1563957393, + "version": "2.1.10", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563193019, "version": "2.1.9", diff --git a/contracts/erc721/CHANGELOG.md b/contracts/erc721/CHANGELOG.md index 89b0ca1f60..e6bd351268 100644 --- a/contracts/erc721/CHANGELOG.md +++ b/contracts/erc721/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.1.12 - _August 8, 2019_ + + * Dependencies updated + +## v2.1.11 - _July 31, 2019_ + + * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) + +## v2.1.10 - _July 24, 2019_ + + * Dependencies updated + ## v2.1.9 - _July 15, 2019_ * Dependencies updated diff --git a/contracts/erc721/package.json b/contracts/erc721/package.json index ac34172fd3..3dc2c0a1c1 100644 --- a/contracts/erc721/package.json +++ b/contracts/erc721/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-erc721", - "version": "2.1.9", + "version": "2.1.12", "engines": { "node": ">=6.12" }, @@ -47,20 +47,21 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/tokens/README.md", "devDependencies": { - "@0x/abi-gen": "^2.1.1", - "@0x/contracts-gen": "^1.0.10", - "@0x/contracts-test-utils": "^3.1.10", - "@0x/dev-utils": "^2.2.4", - "@0x/sol-compiler": "^3.1.9", + "@0x/abi-gen": "^4.1.0", + "@0x/contracts-gen": "^1.0.13", + "@0x/contracts-test-utils": "^3.1.13", + "@0x/dev-utils": "^2.3.0", + "@0x/sol-compiler": "^3.1.12", "@0x/tslint-config": "^3.0.1", "@types/lodash": "4.14.104", + "@types/mocha": "^5.2.7", "@types/node": "*", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^3.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", "solhint": "^1.4.1", @@ -68,13 +69,13 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/base-contract": "^5.1.1", - "@0x/contracts-utils": "^3.1.9", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", - "ethereum-types": "^2.1.3", + "@0x/base-contract": "^5.3.1", + "@0x/contracts-utils": "^3.2.1", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", + "ethereum-types": "^2.1.4", "lodash": "^4.17.11" }, "publishConfig": { diff --git a/contracts/erc721/test/erc721_token.ts b/contracts/erc721/test/erc721_token.ts index 13332cd35c..b3c0ba4141 100644 --- a/contracts/erc721/test/erc721_token.ts +++ b/contracts/erc721/test/erc721_token.ts @@ -48,6 +48,7 @@ describe('ERC721Token', () => { artifacts.DummyERC721Token, provider, txDefaults, + artifacts, constants.DUMMY_TOKEN_NAME, constants.DUMMY_TOKEN_SYMBOL, ); @@ -55,6 +56,7 @@ describe('ERC721Token', () => { artifacts.DummyERC721Receiver, provider, txDefaults, + artifacts, ); logDecoder = new LogDecoder(web3Wrapper, artifacts); await web3Wrapper.awaitTransactionSuccessAsync( @@ -176,6 +178,7 @@ describe('ERC721Token', () => { artifacts.DummyERC721Token, provider, txDefaults, + artifacts, constants.DUMMY_TOKEN_NAME, constants.DUMMY_TOKEN_SYMBOL, ); @@ -190,6 +193,7 @@ describe('ERC721Token', () => { artifacts.InvalidERC721Receiver, provider, txDefaults, + artifacts, ); const from = owner; const to = invalidErc721Receiver.address; @@ -237,6 +241,7 @@ describe('ERC721Token', () => { artifacts.DummyERC721Token, provider, txDefaults, + artifacts, constants.DUMMY_TOKEN_NAME, constants.DUMMY_TOKEN_SYMBOL, ); @@ -251,6 +256,7 @@ describe('ERC721Token', () => { artifacts.InvalidERC721Receiver, provider, txDefaults, + artifacts, ); const from = owner; const to = invalidErc721Receiver.address; diff --git a/contracts/exchange-forwarder/CHANGELOG.json b/contracts/exchange-forwarder/CHANGELOG.json index aeb24117b9..eb0f061968 100644 --- a/contracts/exchange-forwarder/CHANGELOG.json +++ b/contracts/exchange-forwarder/CHANGELOG.json @@ -1,4 +1,32 @@ [ + { + "timestamp": 1565296576, + "version": "3.0.9", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "version": "3.0.8", + "changes": [ + { + "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", + "pr": 1995 + } + ], + "timestamp": 1564607468 + }, + { + "timestamp": 1563957393, + "version": "3.0.7", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563193019, "version": "3.0.6", diff --git a/contracts/exchange-forwarder/CHANGELOG.md b/contracts/exchange-forwarder/CHANGELOG.md index 793b199e8f..e2a9a1ef3b 100644 --- a/contracts/exchange-forwarder/CHANGELOG.md +++ b/contracts/exchange-forwarder/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.0.9 - _August 8, 2019_ + + * Dependencies updated + +## v3.0.8 - _July 31, 2019_ + + * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) + +## v3.0.7 - _July 24, 2019_ + + * Dependencies updated + ## v3.0.6 - _July 15, 2019_ * Dependencies updated diff --git a/contracts/exchange-forwarder/package.json b/contracts/exchange-forwarder/package.json index b0338cbcbf..0a83ec33ef 100644 --- a/contracts/exchange-forwarder/package.json +++ b/contracts/exchange-forwarder/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-exchange-forwarder", - "version": "3.0.6", + "version": "3.0.9", "engines": { "node": ">=6.12" }, @@ -46,20 +46,21 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md", "devDependencies": { - "@0x/abi-gen": "^2.1.1", - "@0x/contracts-gen": "^1.0.10", - "@0x/contracts-test-utils": "^3.1.10", - "@0x/dev-utils": "^2.2.4", - "@0x/sol-compiler": "^3.1.9", + "@0x/abi-gen": "^4.1.0", + "@0x/contracts-gen": "^1.0.13", + "@0x/contracts-test-utils": "^3.1.13", + "@0x/dev-utils": "^2.3.0", + "@0x/sol-compiler": "^3.1.12", "@0x/tslint-config": "^3.0.1", "@types/lodash": "4.14.104", + "@types/mocha": "^5.2.7", "@types/node": "*", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^3.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", "solhint": "^1.4.1", @@ -67,19 +68,19 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/base-contract": "^5.1.1", - "@0x/contracts-asset-proxy": "^2.2.2", - "@0x/contracts-erc20": "^2.2.8", - "@0x/contracts-erc721": "^2.1.9", - "@0x/contracts-exchange": "^2.1.8", - "@0x/contracts-exchange-libs": "^3.0.2", - "@0x/contracts-utils": "^3.1.9", - "@0x/order-utils": "^8.2.2", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", - "ethereum-types": "^2.1.3", + "@0x/base-contract": "^5.3.1", + "@0x/contracts-asset-proxy": "^2.2.5", + "@0x/contracts-erc20": "^2.2.11", + "@0x/contracts-erc721": "^2.1.12", + "@0x/contracts-exchange": "^2.1.11", + "@0x/contracts-exchange-libs": "^3.0.5", + "@0x/contracts-utils": "^3.2.1", + "@0x/order-utils": "^8.2.5", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", + "ethereum-types": "^2.1.4", "lodash": "^4.17.11" }, "publishConfig": { diff --git a/contracts/exchange-forwarder/test/forwarder.ts b/contracts/exchange-forwarder/test/forwarder.ts index 3c3eae7f55..ef77168a3f 100644 --- a/contracts/exchange-forwarder/test/forwarder.ts +++ b/contracts/exchange-forwarder/test/forwarder.ts @@ -102,7 +102,6 @@ describe(ContractName.Forwarder, () => { exchangeArtifacts.Exchange, provider, txDefaults, - zrxAssetData, new BigNumber(chainId), ); exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider); @@ -177,7 +176,6 @@ describe(ContractName.Forwarder, () => { exchangeArtifacts.Exchange, provider, txDefaults, - zrxAssetData, new BigNumber(chainId), ); return expectContractCreationFailedAsync( diff --git a/contracts/exchange-libs/CHANGELOG.json b/contracts/exchange-libs/CHANGELOG.json index e881cb4899..3aee997527 100644 --- a/contracts/exchange-libs/CHANGELOG.json +++ b/contracts/exchange-libs/CHANGELOG.json @@ -104,6 +104,34 @@ } ] }, + { + "timestamp": 1565296576, + "version": "3.0.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "version": "3.0.4", + "changes": [ + { + "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", + "pr": 1995 + } + ], + "timestamp": 1564604963 + }, + { + "timestamp": 1563957393, + "version": "3.0.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563193019, "version": "3.0.2", diff --git a/contracts/exchange-libs/CHANGELOG.md b/contracts/exchange-libs/CHANGELOG.md index 9186bfb711..313aadd23e 100644 --- a/contracts/exchange-libs/CHANGELOG.md +++ b/contracts/exchange-libs/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.0.5 - _August 8, 2019_ + + * Dependencies updated + +## v3.0.4 - _July 31, 2019_ + + * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) + +## v3.0.3 - _July 24, 2019_ + + * Dependencies updated + ## v3.0.2 - _July 15, 2019_ * Dependencies updated diff --git a/contracts/exchange-libs/package.json b/contracts/exchange-libs/package.json index 3f093eaa5f..50f278da67 100644 --- a/contracts/exchange-libs/package.json +++ b/contracts/exchange-libs/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-exchange-libs", - "version": "3.0.2", + "version": "3.0.5", "engines": { "node": ">=6.12" }, @@ -47,14 +47,15 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/libs/README.md", "devDependencies": { - "@0x/abi-gen": "^2.1.1", - "@0x/contracts-gen": "^1.0.10", - "@0x/contracts-test-utils": "^3.1.10", - "@0x/dev-utils": "^2.2.4", - "@0x/sol-compiler": "^3.1.9", + "@0x/abi-gen": "^4.1.0", + "@0x/contracts-gen": "^1.0.13", + "@0x/contracts-test-utils": "^3.1.13", + "@0x/dev-utils": "^2.3.0", + "@0x/sol-compiler": "^3.1.12", "@0x/subproviders": "^4.1.1", "@0x/tslint-config": "^3.0.1", "@types/lodash": "4.14.104", + "@types/mocha": "^5.2.7", "@types/node": "*", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", @@ -62,7 +63,7 @@ "dirty-chai": "^2.0.1", "ethereumjs-util": "^5.1.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", "solhint": "^1.4.1", @@ -70,14 +71,15 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/base-contract": "^5.1.1", - "@0x/contracts-utils": "^3.1.9", - "@0x/order-utils": "^8.2.2", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", - "ethereum-types": "^2.1.3", + "@0x/base-contract": "^5.3.1", + "@0x/contracts-utils": "^3.2.1", + "@0x/order-utils": "^8.2.5", + "@0x/subproviders": "5.0.1", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", + "ethereum-types": "^2.1.4", "lodash": "^4.17.11" }, "publishConfig": { diff --git a/contracts/exchange-libs/test/lib_eip712_exchange_domain.ts b/contracts/exchange-libs/test/lib_eip712_exchange_domain.ts index e23d77cbb5..56363d9771 100644 --- a/contracts/exchange-libs/test/lib_eip712_exchange_domain.ts +++ b/contracts/exchange-libs/test/lib_eip712_exchange_domain.ts @@ -12,6 +12,7 @@ blockchainTests('LibEIP712ExchangeDomain', env => { artifacts.TestLibEIP712ExchangeDomain, env.provider, env.txDefaults, + {}, new BigNumber(chainId), constants.NULL_ADDRESS, ); @@ -32,6 +33,7 @@ blockchainTests('LibEIP712ExchangeDomain', env => { artifacts.TestLibEIP712ExchangeDomain, env.provider, env.txDefaults, + {}, new BigNumber(chainId), verifyingContractAddress, ); diff --git a/contracts/exchange-libs/test/lib_fill_results.ts b/contracts/exchange-libs/test/lib_fill_results.ts index 9ba60471a4..cf62cdc712 100644 --- a/contracts/exchange-libs/test/lib_fill_results.ts +++ b/contracts/exchange-libs/test/lib_fill_results.ts @@ -58,6 +58,7 @@ blockchainTests('LibFillResults', env => { artifacts.TestLibFillResults, env.provider, env.txDefaults, + {}, ); }); diff --git a/contracts/exchange-libs/test/lib_math.ts b/contracts/exchange-libs/test/lib_math.ts index 0c54ad5bf3..bdb9673007 100644 --- a/contracts/exchange-libs/test/lib_math.ts +++ b/contracts/exchange-libs/test/lib_math.ts @@ -20,6 +20,7 @@ blockchainTests('LibMath', env => { artifacts.TestLibMath, env.provider, env.txDefaults, + {}, ); }); diff --git a/contracts/exchange-libs/test/lib_order.ts b/contracts/exchange-libs/test/lib_order.ts index 364c017305..64b7865e68 100644 --- a/contracts/exchange-libs/test/lib_order.ts +++ b/contracts/exchange-libs/test/lib_order.ts @@ -41,6 +41,7 @@ blockchainTests('LibOrder', env => { artifacts.TestLibOrder, env.provider, env.txDefaults, + {}, ); }); diff --git a/contracts/exchange-libs/test/lib_zero_ex_transaction.ts b/contracts/exchange-libs/test/lib_zero_ex_transaction.ts index f2b02d315d..f49100188c 100644 --- a/contracts/exchange-libs/test/lib_zero_ex_transaction.ts +++ b/contracts/exchange-libs/test/lib_zero_ex_transaction.ts @@ -31,6 +31,7 @@ blockchainTests('LibZeroExTransaction', env => { artifacts.TestLibZeroExTransaction, env.provider, env.txDefaults, + {}, ); }); diff --git a/contracts/exchange/CHANGELOG.json b/contracts/exchange/CHANGELOG.json index ecc5948702..17ca08a8f9 100644 --- a/contracts/exchange/CHANGELOG.json +++ b/contracts/exchange/CHANGELOG.json @@ -176,6 +176,34 @@ } ] }, + { + "timestamp": 1565296576, + "version": "2.1.11", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "version": "2.1.10", + "changes": [ + { + "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", + "pr": 1995 + } + ], + "timestamp": 1564607468 + }, + { + "timestamp": 1563957393, + "version": "2.1.9", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563193019, "version": "2.1.8", diff --git a/contracts/exchange/CHANGELOG.md b/contracts/exchange/CHANGELOG.md index 00bc84dc04..f9965bb542 100644 --- a/contracts/exchange/CHANGELOG.md +++ b/contracts/exchange/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.1.11 - _August 8, 2019_ + + * Dependencies updated + +## v2.1.10 - _July 31, 2019_ + + * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) + +## v2.1.9 - _July 24, 2019_ + + * Dependencies updated + ## v2.1.8 - _July 15, 2019_ * Dependencies updated diff --git a/contracts/exchange/package.json b/contracts/exchange/package.json index 5246e81385..caf00dd3c6 100644 --- a/contracts/exchange/package.json +++ b/contracts/exchange/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-exchange", - "version": "2.1.8", + "version": "2.1.11", "engines": { "node": ">=6.12" }, @@ -47,20 +47,21 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/protocol/README.md", "devDependencies": { - "@0x/abi-gen": "^2.1.1", - "@0x/contracts-gen": "^1.0.10", - "@0x/contracts-test-utils": "^3.1.10", - "@0x/dev-utils": "^2.2.4", - "@0x/sol-compiler": "^3.1.9", + "@0x/abi-gen": "^4.1.0", + "@0x/contracts-gen": "^1.0.13", + "@0x/contracts-test-utils": "^3.1.13", + "@0x/dev-utils": "^2.3.0", + "@0x/sol-compiler": "^3.1.12", "@0x/tslint-config": "^3.0.1", "@types/lodash": "4.14.104", + "@types/mocha": "^5.2.7", "@types/node": "*", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^3.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", "solhint": "^1.4.1", @@ -68,19 +69,19 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/base-contract": "^5.1.1", - "@0x/contracts-asset-proxy": "^2.2.2", - "@0x/contracts-erc1155": "^1.1.9", - "@0x/contracts-erc20": "^2.2.8", - "@0x/contracts-erc721": "^2.1.9", - "@0x/contracts-exchange-libs": "^3.0.2", - "@0x/contracts-utils": "^3.1.9", - "@0x/order-utils": "^8.2.2", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", - "ethereum-types": "^2.1.3", + "@0x/base-contract": "^5.3.1", + "@0x/contracts-asset-proxy": "^2.2.5", + "@0x/contracts-erc1155": "^1.1.12", + "@0x/contracts-erc20": "^2.2.11", + "@0x/contracts-erc721": "^2.1.12", + "@0x/contracts-exchange-libs": "^3.0.5", + "@0x/contracts-utils": "^3.2.1", + "@0x/order-utils": "^8.2.5", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", + "ethereum-types": "^2.1.4", "ethereumjs-util": "^5.1.1", "lodash": "^4.17.11" }, diff --git a/contracts/exchange/test/core.ts b/contracts/exchange/test/core.ts index c3e4fb590f..58552ec104 100644 --- a/contracts/exchange/test/core.ts +++ b/contracts/exchange/test/core.ts @@ -1,5 +1,6 @@ import { artifacts as proxyArtifacts, + ERC1155ProxyContract, ERC1155ProxyWrapper, ERC20ProxyContract, ERC20Wrapper, @@ -67,7 +68,7 @@ blockchainTests.resets('Exchange core', () => { let exchange: ExchangeContract; let erc20Proxy: ERC20ProxyContract; let erc721Proxy: ERC721ProxyContract; - let erc1155Proxy: ERC721ProxyContract; + let erc1155Proxy: ERC1155ProxyContract; let multiAssetProxy: MultiAssetProxyContract; let validatorWallet: TestValidatorWalletContract; let erc1155Contract: ERC1155MintableContract; @@ -111,11 +112,13 @@ blockchainTests.resets('Exchange core', () => { proxyArtifacts.MultiAssetProxy, provider, txDefaults, + {}, ); staticCallProxy = await StaticCallProxyContract.deployFrom0xArtifactAsync( proxyArtifacts.StaticCallProxy, provider, txDefaults, + {}, ); const numDummyErc20ToDeploy = 3; [erc20TokenA, erc20TokenB, feeToken] = await erc20Wrapper.deployDummyTokensAsync( @@ -126,12 +129,13 @@ blockchainTests.resets('Exchange core', () => { erc20Artifacts.DummyNoReturnERC20Token, provider, txDefaults, + {}, constants.DUMMY_TOKEN_NAME, constants.DUMMY_TOKEN_SYMBOL, constants.DUMMY_TOKEN_DECIMALS, constants.DUMMY_TOKEN_TOTAL_SUPPLY, ); - erc20Wrapper.addDummyTokenContract(noReturnErc20Token); + erc20Wrapper.addDummyTokenContract((noReturnErc20Token as any) as DummyERC20TokenContract); [erc721Token] = await erc721Wrapper.deployDummyTokensAsync(); erc1155Proxy = await erc1155ProxyWrapper.deployProxyAsync(); [erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyContractsAsync(); @@ -140,12 +144,14 @@ blockchainTests.resets('Exchange core', () => { artifacts.Exchange, provider, txDefaults, + {}, new BigNumber(chainId), ); validatorWallet = await TestValidatorWalletContract.deployFrom0xArtifactAsync( artifacts.TestValidatorWallet, provider, txDefaults, + {}, exchange.address, ); // Configure ERC20Proxy @@ -1067,6 +1073,7 @@ blockchainTests.resets('Exchange core', () => { proxyArtifacts.TestStaticCallTarget, provider, txDefaults, + {}, ); }); it('should revert if the staticcall is unsuccessful', async () => { diff --git a/contracts/exchange/test/dispatcher.ts b/contracts/exchange/test/dispatcher.ts index 71e8ab182e..467f051edb 100644 --- a/contracts/exchange/test/dispatcher.ts +++ b/contracts/exchange/test/dispatcher.ts @@ -29,6 +29,8 @@ import { TestAssetProxyDispatcherContract, } from '../src'; +import { dependencyArtifacts } from './utils/dependency_artifacts'; + chaiSetup.configure(); const expect = chai.expect; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); @@ -76,6 +78,7 @@ describe('AssetProxyDispatcher', () => { artifacts.TestAssetProxyDispatcher, provider, txDefaults, + dependencyArtifacts, ); await erc20Proxy.addAuthorizedAddress.awaitTransactionSuccessAsync(assetProxyDispatcher.address, { from: owner, @@ -126,6 +129,7 @@ describe('AssetProxyDispatcher', () => { proxyArtifacts.ERC20Proxy, provider, txDefaults, + dependencyArtifacts, ); const expectedError = new ExchangeRevertErrors.AssetProxyExistsError(proxyAddress); const tx = assetProxyDispatcher.registerAssetProxy.sendTransactionAsync(newErc20TransferProxy.address, { diff --git a/contracts/exchange/test/internal.ts b/contracts/exchange/test/internal.ts index e7fc187446..e00d384dfc 100644 --- a/contracts/exchange/test/internal.ts +++ b/contracts/exchange/test/internal.ts @@ -32,6 +32,7 @@ blockchainTests('Exchange core internal functions', env => { artifacts.TestExchangeInternals, env.provider, env.txDefaults, + {}, new BigNumber(CHAIN_ID), ); logDecoder = new LogDecoder(env.web3Wrapper, artifacts); diff --git a/contracts/exchange/test/lib_exchange_rich_error_decoder.ts b/contracts/exchange/test/lib_exchange_rich_error_decoder.ts index 8c3ce7e660..eb29ebd4e6 100644 --- a/contracts/exchange/test/lib_exchange_rich_error_decoder.ts +++ b/contracts/exchange/test/lib_exchange_rich_error_decoder.ts @@ -16,6 +16,7 @@ blockchainTests.resets('LibExchangeRichErrorDecoder', ({ provider, txDefaults }) artifacts.TestLibExchangeRichErrorDecoder, provider, txDefaults, + {}, ); }); diff --git a/contracts/exchange/test/match_orders.ts b/contracts/exchange/test/match_orders.ts index 70e1091b8b..f4cdff0f75 100644 --- a/contracts/exchange/test/match_orders.ts +++ b/contracts/exchange/test/match_orders.ts @@ -117,7 +117,7 @@ describe('matchOrders', () => { await erc721Wrapper.setBalancesAndAllowancesAsync(); // Deploy ERC1155 token and proxy [erc1155Wrapper] = await erc1155ProxyWrapper.deployDummyContractsAsync(); - erc1155Token = erc1155Wrapper.getContract(); + erc1155Token = (erc1155Wrapper.getContract() as any) as ERC1155TokenContract; erc1155Proxy = await erc1155ProxyWrapper.deployProxyAsync(); await erc1155ProxyWrapper.setBalancesAndAllowancesAsync(); // Deploy MultiAssetProxy. @@ -125,12 +125,14 @@ describe('matchOrders', () => { assetProxyArtifacts.MultiAssetProxy, provider, txDefaults, + {}, ); // Depoy exchange exchange = await ExchangeContract.deployFrom0xArtifactAsync( artifacts.Exchange, provider, txDefaults, + {}, new BigNumber(chainId), ); exchangeWrapper = new ExchangeWrapper(exchange, provider); diff --git a/contracts/exchange/test/reentrancy_tests.ts b/contracts/exchange/test/reentrancy_tests.ts index 69e05bf822..593c8285f2 100644 --- a/contracts/exchange/test/reentrancy_tests.ts +++ b/contracts/exchange/test/reentrancy_tests.ts @@ -93,6 +93,7 @@ blockchainTests.resets('Reentrancy Tests', env => { artifacts.ReentrancyTester, env.provider, env.txDefaults, + {}, ); }); diff --git a/contracts/exchange/test/signature_validator.ts b/contracts/exchange/test/signature_validator.ts index 35bcae9fc2..fe9146d7ec 100644 --- a/contracts/exchange/test/signature_validator.ts +++ b/contracts/exchange/test/signature_validator.ts @@ -50,12 +50,14 @@ blockchainTests.resets('MixinSignatureValidator', env => { artifacts.TestSignatureValidator, env.provider, env.txDefaults, + {}, new BigNumber(chainId), ); validatorWallet = await TestValidatorWalletContract.deployFrom0xArtifactAsync( artifacts.TestValidatorWallet, env.provider, env.txDefaults, + {}, signatureValidator.address, ); validatorWalletRevertReason = await validatorWallet.REVERT_REASON.callAsync(); diff --git a/contracts/exchange/test/transactions.ts b/contracts/exchange/test/transactions.ts index a0e9f2e40e..5adab3fb14 100644 --- a/contracts/exchange/test/transactions.ts +++ b/contracts/exchange/test/transactions.ts @@ -103,6 +103,7 @@ blockchainTests.resets('Exchange transactions', env => { artifacts.Exchange, env.provider, env.txDefaults, + {}, new BigNumber(chainId), ); exchangeWrapper = new ExchangeWrapper(exchangeInstance, env.provider); @@ -976,6 +977,7 @@ blockchainTests.resets('Exchange transactions', env => { artifacts.ExchangeWrapper, env.provider, env.txDefaults, + {}, exchangeInstance.address, ); }); @@ -1078,6 +1080,7 @@ blockchainTests.resets('Exchange transactions', env => { artifacts.Whitelist, env.provider, env.txDefaults, + {}, exchangeInstance.address, ); const isApproved = true; diff --git a/contracts/exchange/test/utils/dependency_artifacts.ts b/contracts/exchange/test/utils/dependency_artifacts.ts new file mode 100644 index 0000000000..3e0eb253da --- /dev/null +++ b/contracts/exchange/test/utils/dependency_artifacts.ts @@ -0,0 +1,9 @@ +import { artifacts as erc1155Artifacts } from '@0x/contracts-erc1155'; +import { artifacts as erc20Artifacts } from '@0x/contracts-erc20'; +import { artifacts as erc721Artifacts } from '@0x/contracts-erc721'; + +export const dependencyArtifacts = { + ...erc20Artifacts, + ...erc721Artifacts, + ...erc1155Artifacts, +}; diff --git a/contracts/exchange/test/utils/exchange_wrapper.ts b/contracts/exchange/test/utils/exchange_wrapper.ts index 9467fba577..fbe0215425 100644 --- a/contracts/exchange/test/utils/exchange_wrapper.ts +++ b/contracts/exchange/test/utils/exchange_wrapper.ts @@ -21,6 +21,7 @@ import { AbiDecodedFillOrderData } from './types'; export class ExchangeWrapper { private readonly _exchange: ExchangeContract; + // tslint:disable no-unused-variable private readonly _web3Wrapper: Web3Wrapper; private readonly _logDecoder: LogDecoder; constructor(exchangeContract: ExchangeContract, provider: Web3ProviderEngine | ZeroExProvider) { @@ -39,20 +40,18 @@ export class ExchangeWrapper { opts: { takerAssetFillAmount?: BigNumber } = {}, ): Promise { const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); - const txHash = await this._exchange.fillOrder.sendTransactionAsync( + const txReceipt = await this._exchange.fillOrder.awaitTransactionSuccessAsync( params.order, params.takerAssetFillAmount, params.signature, { from }, ); - const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); return txReceipt; } public async cancelOrderAsync(signedOrder: SignedOrder, from: string): Promise { const params = orderUtils.createCancel(signedOrder); - const txHash = await this._exchange.cancelOrder.sendTransactionAsync(params.order, { from }); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; + const txReceipt = await this._exchange.cancelOrder.awaitTransactionSuccessAsync(params.order, { from }); + return txReceipt; } public async fillOrKillOrderAsync( signedOrder: SignedOrder, @@ -60,14 +59,13 @@ export class ExchangeWrapper { opts: { takerAssetFillAmount?: BigNumber } = {}, ): Promise { const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); - const txHash = await this._exchange.fillOrKillOrder.sendTransactionAsync( + const txReceipt = await this._exchange.fillOrKillOrder.awaitTransactionSuccessAsync( params.order, params.takerAssetFillAmount, params.signature, { from }, ); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; + return txReceipt; } public async fillOrderNoThrowAsync( signedOrder: SignedOrder, @@ -75,14 +73,13 @@ export class ExchangeWrapper { opts: { takerAssetFillAmount?: BigNumber; gas?: number } = {}, ): Promise { const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); - const txHash = await this._exchange.fillOrderNoThrow.sendTransactionAsync( + const txReceipt = await this._exchange.fillOrderNoThrow.awaitTransactionSuccessAsync( params.order, params.takerAssetFillAmount, params.signature, { from, gas: opts.gas }, ); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; + return txReceipt; } public async batchFillOrdersAsync( orders: SignedOrder[], @@ -169,17 +166,17 @@ export class ExchangeWrapper { return tx; } public async cancelOrdersUpToAsync(salt: BigNumber, from: string): Promise { - const txHash = await this._exchange.cancelOrdersUpTo.sendTransactionAsync(salt, { from }); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; + const txReceipt = await this._exchange.cancelOrdersUpTo.awaitTransactionSuccessAsync(salt, { from }); + return txReceipt; } public async registerAssetProxyAsync( assetProxyAddress: string, from: string, ): Promise { - const txHash = await this._exchange.registerAssetProxy.sendTransactionAsync(assetProxyAddress, { from }); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; + const txReceipt = await this._exchange.registerAssetProxy.awaitTransactionSuccessAsync(assetProxyAddress, { + from, + }); + return txReceipt; } public async executeTransactionAsync( signedTransaction: SignedZeroExTransaction, @@ -324,15 +321,14 @@ export class ExchangeWrapper { from: string, ): Promise { const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight); - const txHash = await this._exchange.matchOrders.sendTransactionAsync( + const txReceipt = await this._exchange.matchOrders.awaitTransactionSuccessAsync( params.left, params.right, params.leftSignature, params.rightSignature, { from }, ); - const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); - return tx; + return txReceipt; } public async getMatchOrdersResultsAsync( signedOrderLeft: SignedOrder, diff --git a/contracts/exchange/test/utils/fill_order_combinatorial_utils.ts b/contracts/exchange/test/utils/fill_order_combinatorial_utils.ts index de2b4adaba..1fc9043ef7 100644 --- a/contracts/exchange/test/utils/fill_order_combinatorial_utils.ts +++ b/contracts/exchange/test/utils/fill_order_combinatorial_utils.ts @@ -102,6 +102,7 @@ export async function fillOrderCombinatorialUtilsFactoryAsync( assetProxyArtifacts.MultiAssetProxy, provider, txDefaults, + {}, ); const assetWrapper = new AssetWrapper([erc20Wrapper, erc721Wrapper, erc1155Wrapper], burnerAddress); @@ -110,6 +111,7 @@ export async function fillOrderCombinatorialUtilsFactoryAsync( artifacts.Exchange, provider, txDefaults, + {}, new BigNumber(chainId), ); const exchangeWrapper = new ExchangeWrapper(exchangeContract, provider); diff --git a/contracts/exchange/test/utils/isolated_exchange_wrapper.ts b/contracts/exchange/test/utils/isolated_exchange_wrapper.ts index d1dfb22078..d030ed1479 100644 --- a/contracts/exchange/test/utils/isolated_exchange_wrapper.ts +++ b/contracts/exchange/test/utils/isolated_exchange_wrapper.ts @@ -53,6 +53,7 @@ export class IsolatedExchangeWrapper { artifacts.IsolatedExchange, provider, txDefaults, + {}, ); return new IsolatedExchangeWrapper(web3Wrapper, instance); } diff --git a/contracts/exchange/test/wrapper.ts b/contracts/exchange/test/wrapper.ts index dc88f73698..03bd5b9643 100644 --- a/contracts/exchange/test/wrapper.ts +++ b/contracts/exchange/test/wrapper.ts @@ -82,6 +82,7 @@ blockchainTests.resets('Exchange wrappers', env => { artifacts.Exchange, env.provider, env.txDefaults, + {}, new BigNumber(chainId), ); exchangeWrapper = new ExchangeWrapper(exchange, env.provider); diff --git a/contracts/exchange/test/wrapper_unit_tests.ts b/contracts/exchange/test/wrapper_unit_tests.ts index 6e1b4658d8..cefc45ac10 100644 --- a/contracts/exchange/test/wrapper_unit_tests.ts +++ b/contracts/exchange/test/wrapper_unit_tests.ts @@ -43,6 +43,7 @@ blockchainTests('Exchange wrapper functions unit tests.', env => { artifacts.TestWrapperFunctions, env.provider, env.txDefaults, + {}, ); }); diff --git a/contracts/extensions/CHANGELOG.json b/contracts/extensions/CHANGELOG.json index 27adf5a807..fdb740fdb4 100644 --- a/contracts/extensions/CHANGELOG.json +++ b/contracts/extensions/CHANGELOG.json @@ -1,4 +1,32 @@ [ + { + "timestamp": 1565296576, + "version": "4.0.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "version": "4.0.4", + "changes": [ + { + "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", + "pr": 1995 + } + ], + "timestamp": 1564607468 + }, + { + "timestamp": 1563957393, + "version": "4.0.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563193019, "version": "4.0.2", diff --git a/contracts/extensions/CHANGELOG.md b/contracts/extensions/CHANGELOG.md index af45997315..7414a542b8 100644 --- a/contracts/extensions/CHANGELOG.md +++ b/contracts/extensions/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v4.0.5 - _August 8, 2019_ + + * Dependencies updated + +## v4.0.4 - _July 31, 2019_ + + * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) + +## v4.0.3 - _July 24, 2019_ + + * Dependencies updated + ## v4.0.2 - _July 15, 2019_ * Dependencies updated diff --git a/contracts/extensions/package.json b/contracts/extensions/package.json index b541141ede..b1cc305c1a 100644 --- a/contracts/extensions/package.json +++ b/contracts/extensions/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-extensions", - "version": "4.0.2", + "version": "4.0.5", "engines": { "node": ">=6.12" }, @@ -47,21 +47,21 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md", "devDependencies": { - "@0x/abi-gen": "^2.1.1", - "@0x/contract-wrappers": "^9.1.7", - "@0x/contracts-gen": "^1.0.10", - "@0x/contracts-test-utils": "^3.1.10", - "@0x/dev-utils": "^2.2.4", - "@0x/sol-compiler": "^3.1.9", + "@0x/abi-gen": "^4.1.0", + "@0x/contracts-gen": "^1.0.13", + "@0x/contracts-test-utils": "^3.1.13", + "@0x/dev-utils": "^2.3.0", + "@0x/sol-compiler": "^3.1.12", "@0x/tslint-config": "^3.0.1", "@types/lodash": "4.14.104", + "@types/mocha": "^5.2.7", "@types/node": "*", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^3.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", "solhint": "^1.4.1", @@ -69,19 +69,19 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/base-contract": "^5.1.1", - "@0x/contracts-asset-proxy": "^2.2.2", - "@0x/contracts-erc20": "^2.2.8", - "@0x/contracts-erc721": "^2.1.9", - "@0x/contracts-exchange": "^2.1.8", - "@0x/contracts-exchange-libs": "^3.0.2", - "@0x/contracts-utils": "^3.1.9", - "@0x/order-utils": "^8.2.2", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", - "ethereum-types": "^2.1.3", + "@0x/base-contract": "^5.3.1", + "@0x/contracts-asset-proxy": "^2.2.5", + "@0x/contracts-erc20": "^2.2.11", + "@0x/contracts-erc721": "^2.1.12", + "@0x/contracts-exchange": "^2.1.11", + "@0x/contracts-exchange-libs": "^3.0.5", + "@0x/contracts-utils": "^3.2.1", + "@0x/order-utils": "^8.2.5", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", + "ethereum-types": "^2.1.4", "lodash": "^4.17.11" }, "publishConfig": { diff --git a/contracts/extensions/test/balance_threshold_filter.ts b/contracts/extensions/test/balance_threshold_filter.ts index e6db69926c..238f860418 100644 --- a/contracts/extensions/test/balance_threshold_filter.ts +++ b/contracts/extensions/test/balance_threshold_filter.ts @@ -132,6 +132,7 @@ describe(ContractName.BalanceThresholdFilter, () => { artifacts.Exchange, provider, txDefaults, + artifacts, zrxAssetData, new BigNumber(chainId), ); @@ -151,6 +152,7 @@ describe(ContractName.BalanceThresholdFilter, () => { artifacts.BalanceThresholdFilter, provider, txDefaults, + artifacts, exchangeInstance.address, erc721BalanceThresholdAsset.address, erc721alanceThreshold, @@ -160,6 +162,7 @@ describe(ContractName.BalanceThresholdFilter, () => { artifacts.BalanceThresholdFilter, provider, txDefaults, + artifacts, exchangeInstance.address, erc20BalanceThresholdAsset.address, erc20BalanceThreshold, diff --git a/contracts/extensions/test/dutch_auction.ts b/contracts/extensions/test/dutch_auction.ts index cec471ff08..3ac3d4fa6a 100644 --- a/contracts/extensions/test/dutch_auction.ts +++ b/contracts/extensions/test/dutch_auction.ts @@ -1,4 +1,3 @@ -import { DutchAuctionWrapper } from '@0x/contract-wrappers'; import { ERC20Wrapper, ERC721Wrapper } from '@0x/contracts-asset-proxy'; import { DummyERC20TokenContract } from '@0x/contracts-erc20'; import { DummyERC721TokenContract } from '@0x/contracts-erc721'; @@ -84,7 +83,7 @@ describe(ContractName.DutchAuction, () => { const erc721Balances = await erc721Wrapper.getBalancesAsync(); erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address]; - wethContract = await WETH9Contract.deployFrom0xArtifactAsync(artifacts.WETH9, provider, txDefaults); + wethContract = await WETH9Contract.deployFrom0xArtifactAsync(artifacts.WETH9, provider, txDefaults, artifacts); erc20Wrapper.addDummyTokenContract(wethContract as any); const zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address); @@ -92,6 +91,7 @@ describe(ContractName.DutchAuction, () => { artifacts.Exchange, provider, txDefaults, + artifacts, zrxAssetData, new BigNumber(chainId), ); @@ -110,6 +110,7 @@ describe(ContractName.DutchAuction, () => { artifacts.DutchAuction, provider, txDefaults, + artifacts, exchangeInstance.address, ); dutchAuctionContract = new DutchAuctionContract(dutchAuctionInstance.address, provider); @@ -151,7 +152,7 @@ describe(ContractName.DutchAuction, () => { feeRecipientAddress, // taker address or sender address should be set to the ducth auction contract takerAddress: dutchAuctionContract.address, - makerAssetData: DutchAuctionWrapper.encodeDutchAuctionAssetData( + makerAssetData: assetDataUtils.encodeDutchAuctionAssetData( assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress), auctionBeginTimeSeconds, auctionBeginAmount, @@ -197,7 +198,7 @@ describe(ContractName.DutchAuction, () => { describe('matchOrders', () => { it('should be worth the begin price at the begining of the auction', async () => { auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp + 2); - const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData( + const makerAssetData = assetDataUtils.encodeDutchAuctionAssetData( defaultERC20MakerAssetData, auctionBeginTimeSeconds, auctionBeginAmount, @@ -211,7 +212,7 @@ describe(ContractName.DutchAuction, () => { it('should be be worth the end price at the end of the auction', async () => { auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds * 2); auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds); - const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData( + const makerAssetData = assetDataUtils.encodeDutchAuctionAssetData( defaultERC20MakerAssetData, auctionBeginTimeSeconds, auctionBeginAmount, @@ -277,7 +278,7 @@ describe(ContractName.DutchAuction, () => { it('should revert when auction expires', async () => { auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds * 2); auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds); - const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData( + const makerAssetData = assetDataUtils.encodeDutchAuctionAssetData( defaultERC20MakerAssetData, auctionBeginTimeSeconds, auctionBeginAmount, @@ -305,7 +306,7 @@ describe(ContractName.DutchAuction, () => { }); it('begin time is less than end time', async () => { auctionBeginTimeSeconds = new BigNumber(auctionEndTimeSeconds).plus(tenMinutesInSeconds); - const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData( + const makerAssetData = assetDataUtils.encodeDutchAuctionAssetData( defaultERC20MakerAssetData, auctionBeginTimeSeconds, auctionBeginAmount, @@ -329,7 +330,7 @@ describe(ContractName.DutchAuction, () => { it('should match orders when ERC721', async () => { const makerAssetId = erc721MakerAssetIds[0]; const erc721MakerAssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId); - const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData( + const makerAssetData = assetDataUtils.encodeDutchAuctionAssetData( erc721MakerAssetData, auctionBeginTimeSeconds, auctionBeginAmount, diff --git a/contracts/extensions/test/order_matcher.ts b/contracts/extensions/test/order_matcher.ts index e6c9dc0e6c..3c85875ccc 100644 --- a/contracts/extensions/test/order_matcher.ts +++ b/contracts/extensions/test/order_matcher.ts @@ -104,12 +104,14 @@ describe('OrderMatcher', () => { proxyArtifacts.ERC721Proxy, provider, txDefaults, + artifacts, ); // Depoy exchange exchange = await ExchangeContract.deployFrom0xArtifactAsync( artifacts.Exchange, provider, txDefaults, + artifacts, assetDataUtils.encodeERC20AssetData(zrxToken.address), new BigNumber(chainId), ); @@ -128,6 +130,7 @@ describe('OrderMatcher', () => { artifacts.OrderMatcher, provider, txDefaults, + artifacts, exchange.address, ); // Set default addresses @@ -206,6 +209,7 @@ describe('OrderMatcher', () => { artifacts.Exchange, provider, txDefaults, + artifacts, constants.NULL_BYTES, new BigNumber(chainId), ); @@ -214,6 +218,7 @@ describe('OrderMatcher', () => { artifacts.OrderMatcher, provider, txDefaults, + artifacts, exchangeInstance.address, ) as any) as sendTransactionResult, RevertReason.UnregisteredAssetProxy, @@ -732,6 +737,7 @@ describe('OrderMatcher', () => { erc721Artifacts.DummyERC721Token, provider, txDefaults, + artifacts, constants.DUMMY_TOKEN_NAME, constants.DUMMY_TOKEN_SYMBOL, ); @@ -775,6 +781,7 @@ describe('OrderMatcher', () => { erc721Artifacts.DummyERC721Token, provider, txDefaults, + artifacts, constants.DUMMY_TOKEN_NAME, constants.DUMMY_TOKEN_SYMBOL, ); @@ -792,6 +799,7 @@ describe('OrderMatcher', () => { erc721Artifacts.DummyERC721Token, provider, txDefaults, + artifacts, constants.DUMMY_TOKEN_NAME, constants.DUMMY_TOKEN_SYMBOL, ); diff --git a/contracts/multisig/CHANGELOG.json b/contracts/multisig/CHANGELOG.json index f944f2ec4c..061b99e761 100644 --- a/contracts/multisig/CHANGELOG.json +++ b/contracts/multisig/CHANGELOG.json @@ -1,4 +1,32 @@ [ + { + "timestamp": 1565296576, + "version": "3.1.11", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "version": "3.1.10", + "changes": [ + { + "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", + "pr": 1995 + } + ], + "timestamp": 1564607468 + }, + { + "timestamp": 1563957393, + "version": "3.1.9", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563193019, "version": "3.1.8", diff --git a/contracts/multisig/CHANGELOG.md b/contracts/multisig/CHANGELOG.md index 931c7d2746..e566e96ca9 100644 --- a/contracts/multisig/CHANGELOG.md +++ b/contracts/multisig/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.1.11 - _August 8, 2019_ + + * Dependencies updated + +## v3.1.10 - _July 31, 2019_ + + * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) + +## v3.1.9 - _July 24, 2019_ + + * Dependencies updated + ## v3.1.8 - _July 15, 2019_ * Dependencies updated diff --git a/contracts/multisig/package.json b/contracts/multisig/package.json index a5652fe4eb..804f33b03b 100644 --- a/contracts/multisig/package.json +++ b/contracts/multisig/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-multisig", - "version": "3.1.8", + "version": "3.1.11", "engines": { "node": ">=6.12" }, @@ -47,20 +47,21 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/multisig/README.md", "devDependencies": { - "@0x/abi-gen": "^2.1.1", - "@0x/contracts-gen": "^1.0.10", - "@0x/contracts-test-utils": "^3.1.10", - "@0x/dev-utils": "^2.2.4", - "@0x/sol-compiler": "^3.1.9", + "@0x/abi-gen": "^4.1.0", + "@0x/contracts-gen": "^1.0.13", + "@0x/contracts-test-utils": "^3.1.13", + "@0x/dev-utils": "^2.3.0", + "@0x/sol-compiler": "^3.1.12", "@0x/tslint-config": "^3.0.1", "@types/lodash": "4.14.104", + "@types/mocha": "^5.2.7", "@types/node": "*", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^3.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", "solhint": "^1.4.1", @@ -68,15 +69,15 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/base-contract": "^5.1.1", - "@0x/contracts-asset-proxy": "^2.2.2", - "@0x/contracts-erc20": "^2.2.8", + "@0x/base-contract": "^5.3.1", + "@0x/contracts-asset-proxy": "^2.2.5", + "@0x/contracts-erc20": "^2.2.11", "@0x/contracts-utils": "2.0.1", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", - "ethereum-types": "^2.1.3", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", + "ethereum-types": "^2.1.4", "lodash": "^4.17.11" }, "publishConfig": { diff --git a/contracts/multisig/test/asset_proxy_owner.ts b/contracts/multisig/test/asset_proxy_owner.ts index 729449e144..94b0849bfd 100644 --- a/contracts/multisig/test/asset_proxy_owner.ts +++ b/contracts/multisig/test/asset_proxy_owner.ts @@ -61,17 +61,20 @@ describe('AssetProxyOwner', () => { proxyArtifacts.MixinAuthorizable, provider, txDefaults, + artifacts, ); erc721Proxy = await MixinAuthorizableContract.deployFrom0xArtifactAsync( proxyArtifacts.MixinAuthorizable, provider, txDefaults, + artifacts, ); const defaultAssetProxyContractAddresses: string[] = []; testAssetProxyOwner = await TestAssetProxyOwnerContract.deployFrom0xArtifactAsync( artifacts.TestAssetProxyOwner, provider, txDefaults, + artifacts, owners, defaultAssetProxyContractAddresses, REQUIRED_APPROVALS, @@ -105,6 +108,7 @@ describe('AssetProxyOwner', () => { artifacts.AssetProxyOwner, provider, txDefaults, + artifacts, owners, assetProxyContractAddresses, REQUIRED_APPROVALS, @@ -122,6 +126,7 @@ describe('AssetProxyOwner', () => { artifacts.AssetProxyOwner, provider, txDefaults, + artifacts, owners, assetProxyContractAddresses, REQUIRED_APPROVALS, diff --git a/contracts/multisig/test/multi_sig_with_time_lock.ts b/contracts/multisig/test/multi_sig_with_time_lock.ts index cd6c6b3571..4b85ff9b53 100644 --- a/contracts/multisig/test/multi_sig_with_time_lock.ts +++ b/contracts/multisig/test/multi_sig_with_time_lock.ts @@ -66,6 +66,7 @@ describe('MultiSigWalletWithTimeLock', () => { artifacts.MultiSigWalletWithTimeLock, provider, txDefaults, + artifacts, owners, REQUIRED_APPROVALS, secondsTimeLocked, @@ -81,6 +82,7 @@ describe('MultiSigWalletWithTimeLock', () => { artifacts.MultiSigWalletWithTimeLock, provider, txDefaults, + artifacts, owners, REQUIRED_APPROVALS, secondsTimeLocked, @@ -135,6 +137,7 @@ describe('MultiSigWalletWithTimeLock', () => { artifacts.MultiSigWalletWithTimeLock, provider, txDefaults, + artifacts, owners, REQUIRED_APPROVALS, secondsTimeLocked, @@ -198,6 +201,7 @@ describe('MultiSigWalletWithTimeLock', () => { artifacts.TestRejectEther, provider, txDefaults, + artifacts, ); const data = constants.NULL_BYTES; const value = new BigNumber(10); @@ -234,6 +238,7 @@ describe('MultiSigWalletWithTimeLock', () => { artifacts.MultiSigWalletWithTimeLock, provider, txDefaults, + artifacts, owners, REQUIRED_APPROVALS, secondsTimeLocked, @@ -308,6 +313,7 @@ describe('MultiSigWalletWithTimeLock', () => { artifacts.MultiSigWalletWithTimeLock, provider, txDefaults, + artifacts, owners, REQUIRED_APPROVALS, SECONDS_TIME_LOCKED, diff --git a/contracts/multisig/test/utils/asset_proxy_owner_wrapper.ts b/contracts/multisig/test/utils/asset_proxy_owner_wrapper.ts index afb6cb33ce..fdc3862450 100644 --- a/contracts/multisig/test/utils/asset_proxy_owner_wrapper.ts +++ b/contracts/multisig/test/utils/asset_proxy_owner_wrapper.ts @@ -4,14 +4,17 @@ import { BigNumber } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import { AssetProxyOwnerContract } from '../../generated-wrappers/asset_proxy_owner'; +import { AssetProxyOwnerContract, TestAssetProxyOwnerContract } from '../../src'; import { artifacts } from '../../src/artifacts'; export class AssetProxyOwnerWrapper { - private readonly _assetProxyOwner: AssetProxyOwnerContract; + private readonly _assetProxyOwner: AssetProxyOwnerContract | TestAssetProxyOwnerContract; private readonly _web3Wrapper: Web3Wrapper; private readonly _logDecoder: LogDecoder; - constructor(assetproxyOwnerContract: AssetProxyOwnerContract, provider: Web3ProviderEngine) { + constructor( + assetproxyOwnerContract: AssetProxyOwnerContract | TestAssetProxyOwnerContract, + provider: Web3ProviderEngine, + ) { this._assetProxyOwner = assetproxyOwnerContract; this._web3Wrapper = new Web3Wrapper(provider); this._logDecoder = new LogDecoder(this._web3Wrapper, { ...artifacts, ...proxyArtifacts }); @@ -57,7 +60,7 @@ export class AssetProxyOwnerWrapper { ): Promise { // tslint:disable-next-line:no-unnecessary-type-assertion const txHash = await (this - ._assetProxyOwner as AssetProxyOwnerContract).executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync( + ._assetProxyOwner as TestAssetProxyOwnerContract).executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync( txId, { from, diff --git a/contracts/multisig/test/utils/multi_sig_wrapper.ts b/contracts/multisig/test/utils/multi_sig_wrapper.ts index 9a405d0671..11f2ce51eb 100644 --- a/contracts/multisig/test/utils/multi_sig_wrapper.ts +++ b/contracts/multisig/test/utils/multi_sig_wrapper.ts @@ -3,14 +3,17 @@ import { BigNumber } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import { MultiSigWalletContract } from '../../generated-wrappers/multi_sig_wallet'; +import { MultiSigWalletContract, MultiSigWalletWithTimeLockContract } from '../../src'; import { artifacts } from '../../src/artifacts'; export class MultiSigWrapper { - private readonly _multiSig: MultiSigWalletContract; + private readonly _multiSig: MultiSigWalletContract | MultiSigWalletWithTimeLockContract; private readonly _web3Wrapper: Web3Wrapper; private readonly _logDecoder: LogDecoder; - constructor(multiSigContract: MultiSigWalletContract, provider: Web3ProviderEngine) { + constructor( + multiSigContract: MultiSigWalletContract | MultiSigWalletWithTimeLockContract, + provider: Web3ProviderEngine, + ) { this._multiSig = multiSigContract; this._web3Wrapper = new Web3Wrapper(provider); this._logDecoder = new LogDecoder(this._web3Wrapper, artifacts); diff --git a/contracts/test-utils/CHANGELOG.json b/contracts/test-utils/CHANGELOG.json index e16993f703..62eb505e62 100644 --- a/contracts/test-utils/CHANGELOG.json +++ b/contracts/test-utils/CHANGELOG.json @@ -64,6 +64,33 @@ } ] }, + { + "timestamp": 1565296576, + "version": "3.1.13", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1564604963, + "version": "3.1.12", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1563957393, + "version": "3.1.11", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563193019, "version": "3.1.10", diff --git a/contracts/test-utils/CHANGELOG.md b/contracts/test-utils/CHANGELOG.md index 6640707ebc..c448d8ee54 100644 --- a/contracts/test-utils/CHANGELOG.md +++ b/contracts/test-utils/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.1.13 - _August 8, 2019_ + + * Dependencies updated + +## v3.1.12 - _July 31, 2019_ + + * Dependencies updated + +## v3.1.11 - _July 24, 2019_ + + * Dependencies updated + ## v3.1.10 - _July 15, 2019_ * Dependencies updated diff --git a/contracts/test-utils/package.json b/contracts/test-utils/package.json index 08c7ff5ef8..7e4975316e 100644 --- a/contracts/test-utils/package.json +++ b/contracts/test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-test-utils", - "version": "3.1.10", + "version": "3.1.13", "engines": { "node": ">=6.12" }, @@ -34,24 +34,26 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/test-utils/README.md", "devDependencies": { + "@types/mocha": "^5.2.7", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", "tslint": "5.11.0", "typescript": "3.0.1" }, "dependencies": { - "@0x/dev-utils": "^2.2.4", - "@0x/order-utils": "^8.2.2", - "@0x/sol-compiler": "^3.1.9", - "@0x/sol-coverage": "^3.0.6", - "@0x/sol-profiler": "^3.1.8", - "@0x/sol-trace": "^2.0.14", - "@0x/subproviders": "^4.1.1", + "@0x/dev-utils": "^2.3.0", + "@0x/order-utils": "^8.2.5", + "@0x/sol-compiler": "^3.1.12", + "@0x/sol-coverage": "^3.0.9", + "@0x/sol-profiler": "^3.1.11", + "@0x/sol-trace": "^2.0.17", + "@0x/subproviders": "^5.0.1", "@0x/tslint-config": "^3.0.1", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", "@types/bn.js": "^4.11.0", "@types/js-combinatorics": "^0.5.29", "@types/lodash": "4.14.104", @@ -61,7 +63,7 @@ "chai-as-promised": "^7.1.0", "chai-bignumber": "^3.0.0", "dirty-chai": "^2.0.1", - "ethereum-types": "^2.1.3", + "ethereum-types": "^2.1.4", "ethereumjs-util": "^5.1.1", "ethers": "~4.0.4", "js-combinatorics": "^0.5.3", diff --git a/contracts/utils/CHANGELOG.json b/contracts/utils/CHANGELOG.json index 3b56d6271e..cae52a052e 100644 --- a/contracts/utils/CHANGELOG.json +++ b/contracts/utils/CHANGELOG.json @@ -1,6 +1,6 @@ [ { - "version": "3.2.0", + "version": "3.2.2", "changes": [ { "note": "Change ReentrancyGuard implementation to cheaper one", @@ -56,6 +56,38 @@ } ] }, + { + "timestamp": 1565296576, + "version": "3.2.1", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "version": "3.2.0", + "changes": [ + { + "note": "Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies.", + "pr": 1995 + }, + { + "note": "Added tests for decoding log arguments when artifact dependencies are included/excluded.", + "pr": 1995 + } + ], + "timestamp": 1564604963 + }, + { + "timestamp": 1563957393, + "version": "3.1.10", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563193019, "version": "3.1.9", diff --git a/contracts/utils/CHANGELOG.md b/contracts/utils/CHANGELOG.md index f95b2ed720..af595a3349 100644 --- a/contracts/utils/CHANGELOG.md +++ b/contracts/utils/CHANGELOG.md @@ -5,6 +5,19 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.2.1 - _August 8, 2019_ + + * Dependencies updated + +## v3.2.0 - _July 31, 2019_ + + * Updated calls to .deployFrom0xArtifactAsync to include artifact dependencies. (#1995) + * Added tests for decoding log arguments when artifact dependencies are included/excluded. (#1995) + +## v3.1.10 - _July 24, 2019_ + + * Dependencies updated + ## v3.1.9 - _July 15, 2019_ * Dependencies updated diff --git a/contracts/utils/contracts/test/TestLogDecoding.sol b/contracts/utils/contracts/test/TestLogDecoding.sol new file mode 100644 index 0000000000..e692d8b75f --- /dev/null +++ b/contracts/utils/contracts/test/TestLogDecoding.sol @@ -0,0 +1,55 @@ +/* + + 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.5.5; + +import "./TestLogDecodingDownstream.sol"; + + +contract TestLogDecoding { + + /// @dev arbitrary event; fields to not matter. + event TestEvent( + uint256 foo, + bytes bar, + string car + ); + + /// @dev Emits a local event + function emitEvent() + public + { + emit TestEvent(256, hex'1234', "4321"); + } + + /// @dev Emits an event in a downstream contract + function emitEventDownstream() + public + { + TestLogDecodingDownstream testLogDecodingDownstream = new TestLogDecodingDownstream(); + ITestLogDecodingDownstream(testLogDecodingDownstream).emitEvent(); + } + + /// @dev Emits a local event and a downstream event + function emitEventsLocalAndDownstream() + public + { + emitEvent(); + emitEventDownstream(); + } +} \ No newline at end of file diff --git a/contracts/utils/contracts/test/TestLogDecodingDownstream.sol b/contracts/utils/contracts/test/TestLogDecodingDownstream.sol new file mode 100644 index 0000000000..adb2ffe453 --- /dev/null +++ b/contracts/utils/contracts/test/TestLogDecodingDownstream.sol @@ -0,0 +1,48 @@ +/* + + 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.5.5; + + +contract ITestLogDecodingDownstream { + + /// @dev Emits a local event + function emitEvent() external; +} + + +contract TestLogDecodingDownstream is + ITestLogDecodingDownstream +{ + + /// @dev event with fields different than those in `TestLogDecoding.TestEvent` + /// Note: do not include this in the interface + /// For testing, we want to emit an event that is + /// not known by the calling contract. + event TestEvent2( + uint256 lorem, + string ipsum + ); + + /// @dev Emits a local event + function emitEvent() + external + { + emit TestEvent2(256, "4321"); + } +} \ No newline at end of file diff --git a/contracts/utils/package.json b/contracts/utils/package.json index a80aa90c4b..c0e4c19def 100644 --- a/contracts/utils/package.json +++ b/contracts/utils/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-utils", - "version": "3.1.9", + "version": "3.2.1", "engines": { "node": ">=6.12" }, @@ -34,7 +34,7 @@ "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol" }, "config": { - "abis": "./generated-artifacts/@(Authorizable|IAuthorizable|IOwnable|LibAddress|LibAddressArray|LibAddressArrayRichErrors|LibAuthorizableRichErrors|LibBytes|LibBytesRichErrors|LibEIP1271|LibEIP712|LibOwnableRichErrors|LibReentrancyGuardRichErrors|LibRichErrors|LibSafeMath|LibSafeMathRichErrors|Ownable|ReentrancyGuard|SafeMath|TestLibAddress|TestLibAddressArray|TestLibBytes|TestLibEIP712|TestLibRichErrors|TestOwnable|TestReentrancyGuard|TestSafeMath).json", + "abis": "./generated-artifacts/@(Authorizable|IAuthorizable|IOwnable|LibAddress|LibAddressArray|LibAddressArrayRichErrors|LibAuthorizableRichErrors|LibBytes|LibBytesRichErrors|LibEIP1271|LibEIP712|LibOwnableRichErrors|LibReentrancyGuardRichErrors|LibRichErrors|LibSafeMath|LibSafeMathRichErrors|Ownable|ReentrancyGuard|SafeMath|TestLibAddress|TestLibAddressArray|TestLibBytes|TestLibEIP712|TestLibRichErrors|TestLogDecoding|TestLogDecodingDownstream|TestOwnable|TestReentrancyGuard|TestSafeMath).json", "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually." }, "repository": { @@ -47,21 +47,22 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/contracts/utils/README.md", "devDependencies": { - "@0x/abi-gen": "^2.1.1", - "@0x/contracts-gen": "^1.0.10", - "@0x/contracts-test-utils": "^3.1.10", - "@0x/dev-utils": "^2.2.4", - "@0x/sol-compiler": "^3.1.9", + "@0x/abi-gen": "^4.1.0", + "@0x/contracts-gen": "^1.0.13", + "@0x/contracts-test-utils": "^3.1.13", + "@0x/dev-utils": "^2.3.0", + "@0x/sol-compiler": "^3.1.12", "@0x/tslint-config": "^3.0.1", "@types/bn.js": "^4.11.0", "@types/lodash": "4.14.104", + "@types/mocha": "^5.2.7", "@types/node": "*", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^3.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", "solhint": "^1.4.1", @@ -69,14 +70,14 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/base-contract": "^5.1.1", - "@0x/order-utils": "^8.2.2", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", + "@0x/base-contract": "^5.3.1", + "@0x/order-utils": "^8.2.5", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", "bn.js": "^4.11.8", - "ethereum-types": "^2.1.3", + "ethereum-types": "^2.1.4", "ethereumjs-util": "^5.1.1", "lodash": "^4.17.11" }, diff --git a/contracts/utils/src/artifacts.ts b/contracts/utils/src/artifacts.ts index 8c91c30ca1..e97e8b9a51 100644 --- a/contracts/utils/src/artifacts.ts +++ b/contracts/utils/src/artifacts.ts @@ -29,6 +29,8 @@ import * as TestLibAddressArray from '../generated-artifacts/TestLibAddressArray import * as TestLibBytes from '../generated-artifacts/TestLibBytes.json'; import * as TestLibEIP712 from '../generated-artifacts/TestLibEIP712.json'; import * as TestLibRichErrors from '../generated-artifacts/TestLibRichErrors.json'; +import * as TestLogDecoding from '../generated-artifacts/TestLogDecoding.json'; +import * as TestLogDecodingDownstream from '../generated-artifacts/TestLogDecodingDownstream.json'; import * as TestOwnable from '../generated-artifacts/TestOwnable.json'; import * as TestReentrancyGuard from '../generated-artifacts/TestReentrancyGuard.json'; import * as TestSafeMath from '../generated-artifacts/TestSafeMath.json'; @@ -57,6 +59,8 @@ export const artifacts = { TestLibBytes: TestLibBytes as ContractArtifact, TestLibEIP712: TestLibEIP712 as ContractArtifact, TestLibRichErrors: TestLibRichErrors as ContractArtifact, + TestLogDecoding: TestLogDecoding as ContractArtifact, + TestLogDecodingDownstream: TestLogDecodingDownstream as ContractArtifact, TestOwnable: TestOwnable as ContractArtifact, TestReentrancyGuard: TestReentrancyGuard as ContractArtifact, TestSafeMath: TestSafeMath as ContractArtifact, diff --git a/contracts/utils/src/wrappers.ts b/contracts/utils/src/wrappers.ts index f2562b9d7e..8c513fabe3 100644 --- a/contracts/utils/src/wrappers.ts +++ b/contracts/utils/src/wrappers.ts @@ -27,6 +27,8 @@ export * from '../generated-wrappers/test_lib_address_array'; export * from '../generated-wrappers/test_lib_bytes'; export * from '../generated-wrappers/test_lib_e_i_p712'; export * from '../generated-wrappers/test_lib_rich_errors'; +export * from '../generated-wrappers/test_log_decoding'; +export * from '../generated-wrappers/test_log_decoding_downstream'; export * from '../generated-wrappers/test_ownable'; export * from '../generated-wrappers/test_reentrancy_guard'; export * from '../generated-wrappers/test_safe_math'; diff --git a/contracts/utils/test/authorizable.ts b/contracts/utils/test/authorizable.ts index 63f99d5031..8e4bf800d8 100644 --- a/contracts/utils/test/authorizable.ts +++ b/contracts/utils/test/authorizable.ts @@ -31,6 +31,7 @@ describe('Authorizable', () => { artifacts.Authorizable, provider, txDefaults, + {}, ); }); diff --git a/contracts/utils/test/lib_address.ts b/contracts/utils/test/lib_address.ts index a6a53c2252..a538e610c0 100644 --- a/contracts/utils/test/lib_address.ts +++ b/contracts/utils/test/lib_address.ts @@ -16,7 +16,12 @@ describe('LibAddress', () => { await blockchainLifecycle.startAsync(); nonContract = (await web3Wrapper.getAvailableAddressesAsync())[0]; // Deploy LibAddress - lib = await TestLibAddressContract.deployFrom0xArtifactAsync(artifacts.TestLibAddress, provider, txDefaults); + lib = await TestLibAddressContract.deployFrom0xArtifactAsync( + artifacts.TestLibAddress, + provider, + txDefaults, + {}, + ); }); after(async () => { diff --git a/contracts/utils/test/lib_address_array.ts b/contracts/utils/test/lib_address_array.ts index 4f594ace4f..d69f8bf306 100644 --- a/contracts/utils/test/lib_address_array.ts +++ b/contracts/utils/test/lib_address_array.ts @@ -20,6 +20,7 @@ describe('LibAddressArray', () => { artifacts.TestLibAddressArray, provider, txDefaults, + artifacts, ); }); after(async () => { diff --git a/contracts/utils/test/lib_bytes.ts b/contracts/utils/test/lib_bytes.ts index 69eaa8f196..8fdd3065d8 100644 --- a/contracts/utils/test/lib_bytes.ts +++ b/contracts/utils/test/lib_bytes.ts @@ -59,7 +59,12 @@ describe('LibBytes', () => { testAddress = accounts[1]; testAddressB = accounts[2]; // Deploy LibBytes - libBytes = await TestLibBytesContract.deployFrom0xArtifactAsync(artifacts.TestLibBytes, provider, txDefaults); + libBytes = await TestLibBytesContract.deployFrom0xArtifactAsync( + artifacts.TestLibBytes, + provider, + txDefaults, + artifacts, + ); // Verify lengths of test data const byteArrayShorterThan32BytesLength = ethUtil.toBuffer(byteArrayShorterThan32Bytes).byteLength; expect(byteArrayShorterThan32BytesLength).to.be.lessThan(32); diff --git a/contracts/utils/test/lib_eip712.ts b/contracts/utils/test/lib_eip712.ts index 812d3e35e2..e276e372b9 100644 --- a/contracts/utils/test/lib_eip712.ts +++ b/contracts/utils/test/lib_eip712.ts @@ -17,7 +17,7 @@ describe('LibEIP712', () => { before(async () => { await blockchainLifecycle.startAsync(); // Deploy LibEIP712 - lib = await TestLibEIP712Contract.deployFrom0xArtifactAsync(artifacts.TestLibEIP712, provider, txDefaults); + lib = await TestLibEIP712Contract.deployFrom0xArtifactAsync(artifacts.TestLibEIP712, provider, txDefaults, {}); }); after(async () => { diff --git a/contracts/utils/test/lib_rich_errors.ts b/contracts/utils/test/lib_rich_errors.ts index df3e60b910..7d074badb6 100644 --- a/contracts/utils/test/lib_rich_errors.ts +++ b/contracts/utils/test/lib_rich_errors.ts @@ -20,6 +20,7 @@ describe('LibRichErrors', () => { artifacts.TestLibRichErrors, provider, txDefaults, + {}, ); }); diff --git a/contracts/utils/test/log_decoding.ts b/contracts/utils/test/log_decoding.ts new file mode 100644 index 0000000000..13d9d14971 --- /dev/null +++ b/contracts/utils/test/log_decoding.ts @@ -0,0 +1,95 @@ +import { chaiSetup, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils'; +import { BlockchainLifecycle } from '@0x/dev-utils'; +import { BigNumber } from '@0x/utils'; +import * as chai from 'chai'; +import { DecodedLogArgs, LogWithDecodedArgs } from 'ethereum-types'; + +import { artifacts, TestLogDecodingContract } from '../src'; + +chaiSetup.configure(); +const expect = chai.expect; + +const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); + +describe('TestLogDecoding', () => { + let testLogDecodingWithDependencies: TestLogDecodingContract; + let testLogDecodingDeployedWithoutDependencies: TestLogDecodingContract; + const expectedEvent = { + foo: new BigNumber(256), + bar: '0x1234', + car: '4321', + }; + const expectedDownstreamEvent = { + lorem: new BigNumber(256), + ipsum: '4321', + }; + const emptyDependencyList = {}; + + before(async () => { + testLogDecodingDeployedWithoutDependencies = await TestLogDecodingContract.deployFrom0xArtifactAsync( + artifacts.TestLogDecoding, + provider, + txDefaults, + emptyDependencyList, + ); + testLogDecodingWithDependencies = await TestLogDecodingContract.deployFrom0xArtifactAsync( + artifacts.TestLogDecoding, + provider, + txDefaults, + artifacts, + ); + }); + beforeEach(async () => { + await blockchainLifecycle.startAsync(); + }); + afterEach(async () => { + await blockchainLifecycle.revertAsync(); + }); + + describe('Decoding Log Arguments', () => { + it('should decode locally emitted event args when no dependencies are passed into wrapper', async () => { + const txReceipt = await testLogDecodingDeployedWithoutDependencies.emitEvent.awaitTransactionSuccessAsync(); + expect(txReceipt.logs.length).to.be.equal(1); + // tslint:disable no-unnecessary-type-assertion + expect((txReceipt.logs[0] as LogWithDecodedArgs).args).to.be.deep.equal(expectedEvent); + }); + it('should not decode event args when no dependencies are passed into wrapper', async () => { + const txReceipt = await testLogDecodingDeployedWithoutDependencies.emitEventDownstream.awaitTransactionSuccessAsync(); + expect(txReceipt.logs.length).to.be.equal(1); + // tslint:disable no-unnecessary-type-assertion + expect((txReceipt.logs[0] as LogWithDecodedArgs).args).to.be.undefined(); + }); + it('should decode args for local but not downstream event when no dependencies are passed into wrapper', async () => { + const txReceipt = await testLogDecodingDeployedWithoutDependencies.emitEventsLocalAndDownstream.awaitTransactionSuccessAsync(); + expect(txReceipt.logs.length).to.be.equal(2); + // tslint:disable no-unnecessary-type-assertion + expect((txReceipt.logs[0] as LogWithDecodedArgs).args).to.be.deep.equal(expectedEvent); + // tslint:disable no-unnecessary-type-assertion + expect((txReceipt.logs[1] as LogWithDecodedArgs).args).to.be.undefined(); + }); + it('should decode locally emitted event args when dependencies are passed into wrapper', async () => { + const txReceipt = await testLogDecodingWithDependencies.emitEvent.awaitTransactionSuccessAsync(); + expect(txReceipt.logs.length).to.be.equal(1); + // tslint:disable no-unnecessary-type-assertion + expect((txReceipt.logs[0] as LogWithDecodedArgs).args).to.be.deep.equal(expectedEvent); + }); + it('should decode downstream event args when dependencies are passed into wrapper', async () => { + const txReceipt = await testLogDecodingWithDependencies.emitEventDownstream.awaitTransactionSuccessAsync(); + expect(txReceipt.logs.length).to.be.equal(1); + // tslint:disable no-unnecessary-type-assertion + expect((txReceipt.logs[0] as LogWithDecodedArgs).args).to.be.deep.equal( + expectedDownstreamEvent, + ); + }); + it('should decode args for both local and downstream events when dependencies are passed into wrapper', async () => { + const txReceipt = await testLogDecodingWithDependencies.emitEventsLocalAndDownstream.awaitTransactionSuccessAsync(); + expect(txReceipt.logs.length).to.be.equal(2); + // tslint:disable no-unnecessary-type-assertion + expect((txReceipt.logs[0] as LogWithDecodedArgs).args).to.be.deep.equal(expectedEvent); + // tslint:disable no-unnecessary-type-assertion + expect((txReceipt.logs[1] as LogWithDecodedArgs).args).to.be.deep.equal( + expectedDownstreamEvent, + ); + }); + }); +}); diff --git a/contracts/utils/test/ownable.ts b/contracts/utils/test/ownable.ts index daeb5e6890..4b67312718 100644 --- a/contracts/utils/test/ownable.ts +++ b/contracts/utils/test/ownable.ts @@ -22,7 +22,7 @@ describe('Ownable', () => { await blockchainLifecycle.startAsync(); // Deploy Ownable from the owner address txDefaults.from = owner; - ownable = await TestOwnableContract.deployFrom0xArtifactAsync(artifacts.TestOwnable, provider, txDefaults); + ownable = await TestOwnableContract.deployFrom0xArtifactAsync(artifacts.TestOwnable, provider, txDefaults, {}); }); after(async () => { diff --git a/contracts/utils/test/reentrancy_guard.ts b/contracts/utils/test/reentrancy_guard.ts index 270c9eab84..9018e6f4c0 100644 --- a/contracts/utils/test/reentrancy_guard.ts +++ b/contracts/utils/test/reentrancy_guard.ts @@ -20,6 +20,7 @@ describe('ReentrancyGuard', () => { artifacts.TestReentrancyGuard, provider, txDefaults, + {}, ); }); diff --git a/contracts/utils/test/safe_math.ts b/contracts/utils/test/safe_math.ts index f8c4b7466d..feeb6e3534 100644 --- a/contracts/utils/test/safe_math.ts +++ b/contracts/utils/test/safe_math.ts @@ -19,6 +19,7 @@ blockchainTests('SafeMath', env => { artifacts.TestSafeMath, env.provider, env.txDefaults, + {}, ); }); diff --git a/contracts/utils/tsconfig.json b/contracts/utils/tsconfig.json index 61768eaa2f..2c3029b956 100644 --- a/contracts/utils/tsconfig.json +++ b/contracts/utils/tsconfig.json @@ -27,6 +27,8 @@ "generated-artifacts/TestLibBytes.json", "generated-artifacts/TestLibEIP712.json", "generated-artifacts/TestLibRichErrors.json", + "generated-artifacts/TestLogDecoding.json", + "generated-artifacts/TestLogDecodingDownstream.json", "generated-artifacts/TestOwnable.json", "generated-artifacts/TestReentrancyGuard.json", "generated-artifacts/TestSafeMath.json" diff --git a/package.json b/package.json index 38a19a0aa9..d5bd3f3d1a 100644 --- a/package.json +++ b/package.json @@ -52,9 +52,9 @@ "config": { "contractsPackages": "@0x/contracts-asset-proxy @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-exchange @0x/contracts-exchange-libs @0x/contracts-multisig @0x/contracts-test-utils @0x/contracts-utils @0x/contracts-dev-utils @0x/contracts-staking", "mnemonic": "concert load couple harbor equip island argue ramp clarify fence smart topic", - "packagesWithDocPages": "0x.js connect json-schemas subproviders web3-wrapper contract-wrappers order-utils order-watcher sol-compiler sol-coverage sol-profiler sol-trace ethereum-types asset-buyer migrations", + "packagesWithDocPages": "0x.js connect json-schemas subproviders web3-wrapper order-utils sol-compiler sol-coverage sol-profiler sol-trace ethereum-types asset-buyer migrations", "ignoreDependencyVersions": "@types/styled-components @types/node", - "ignoreDependencyVersionsForPackage": "website instant dev-tools-pages" + "ignoreDependencyVersionsForPackage": "website instant dev-tools-pages contract-wrappers" }, "bundlewatch": { "files": [ @@ -79,7 +79,7 @@ "graceful-fs": "4.1.15" }, "devDependencies": { - "@0x-lerna-fork/lerna": "3.16.7", + "@0x-lerna-fork/lerna": "3.16.10", "@0xproject/npm-cli-login": "^0.0.11", "async-child-process": "^1.1.1", "bundlewatch": "^0.2.1", diff --git a/packages/0x.js/CHANGELOG.json b/packages/0x.js/CHANGELOG.json index abfe801643..646d1d852f 100644 --- a/packages/0x.js/CHANGELOG.json +++ b/packages/0x.js/CHANGELOG.json @@ -1,4 +1,34 @@ [ + { + "version": "7.0.0", + "changes": [ + { + "note": "Removed @0x/order-watcher" + }, + { + "note": "Update to latest @0x/contract-wrappers v11", + "pr": 2068 + } + ] + }, + { + "timestamp": 1565296576, + "version": "6.0.15", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1564604963, + "version": "6.0.14", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "6.0.13", "changes": [ @@ -6,7 +36,8 @@ "note": "re-export new ethereum-types type, TupleDataItem", "pr": 1919 } - ] + ], + "timestamp": 1563957393 }, { "timestamp": 1563193019, diff --git a/packages/0x.js/CHANGELOG.md b/packages/0x.js/CHANGELOG.md index d19f9a6816..85572b2dee 100644 --- a/packages/0x.js/CHANGELOG.md +++ b/packages/0x.js/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v6.0.15 - _August 8, 2019_ + + * Dependencies updated + +## v6.0.14 - _July 31, 2019_ + + * Dependencies updated + +## v6.0.13 - _July 24, 2019_ + + * re-export new ethereum-types type, TupleDataItem (#1919) + ## v6.0.12 - _July 15, 2019_ * Dependencies updated diff --git a/packages/0x.js/README.md b/packages/0x.js/README.md index 5b7a2308cb..30d61f0d8b 100644 --- a/packages/0x.js/README.md +++ b/packages/0x.js/README.md @@ -1,6 +1,6 @@ ## 0x.js -A TypeScript/Javascript library for interacting with the 0x protocol. It is a high level package which combines a number of underlying packages such as order-utils and order-watcher. +A TypeScript/Javascript library for interacting with the 0x protocol. It is a high level package which combines a number of underlying packages such as order-utils and asset-data-utils. ### Read the [Documentation](https://0xproject.com/docs/0x.js). diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json index 1e5bcc390b..f9e8706e06 100644 --- a/packages/0x.js/package.json +++ b/packages/0x.js/package.json @@ -1,6 +1,6 @@ { "name": "0x.js", - "version": "6.0.12", + "version": "6.0.15", "engines": { "node": ">=6.12" }, @@ -43,13 +43,12 @@ }, "license": "Apache-2.0", "devDependencies": { - "@0x/abi-gen-wrappers": "^5.0.2", - "@0x/contract-addresses": "^3.0.2", - "@0x/dev-utils": "^2.2.4", - "@0x/migrations": "^4.1.9", + "@0x/contract-addresses": "^3.0.3", + "@0x/dev-utils": "^2.3.0", + "@0x/migrations": "^4.2.0", "@0x/tslint-config": "^3.0.1", "@types/lodash": "4.14.104", - "@types/mocha": "^2.2.42", + "@types/mocha": "^5.2.7", "@types/node": "*", "@types/sinon": "^2.2.2", "awesome-typescript-loader": "^5.2.1", @@ -59,7 +58,7 @@ "copyfiles": "^2.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "opn-cli": "^3.1.0", @@ -73,18 +72,18 @@ "webpack": "^4.20.2" }, "dependencies": { - "@0x/assert": "^2.1.0", - "@0x/base-contract": "^5.1.1", - "@0x/contract-wrappers": "^9.1.7", - "@0x/order-utils": "^8.2.2", - "@0x/order-watcher": "^4.0.14", - "@0x/subproviders": "^4.1.1", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", + "@0x/assert": "^2.1.3", + "@0x/asset-swapper": "^1.0.1", + "@0x/base-contract": "^5.3.1", + "@0x/contract-wrappers": "^11.0.0", + "@0x/order-utils": "^8.2.5", + "@0x/subproviders": "^5.0.1", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", "@types/web3-provider-engine": "^14.0.0", - "ethereum-types": "^2.1.3", + "ethereum-types": "^2.1.4", "ethers": "~4.0.4", "lodash": "^4.17.11", "web3-provider-engine": "14.0.6" diff --git a/packages/0x.js/src/index.ts b/packages/0x.js/src/index.ts index ddd7100661..f088ec02b4 100644 --- a/packages/0x.js/src/index.ts +++ b/packages/0x.js/src/index.ts @@ -13,33 +13,23 @@ export { CoordinatorWrapper, CoordinatorServerCancellationResponse, CoordinatorServerError, - DutchAuctionWrapper, - ERC20TokenWrapper, - ERC721TokenWrapper, - EtherTokenWrapper, - ExchangeWrapper, - ERC20ProxyWrapper, - ERC721ProxyWrapper, - ForwarderWrapper, - OrderValidatorWrapper, IndexedFilterValues, - BlockRange, ContractWrappersConfig, - MethodOpts, OrderTransactionOpts, TransactionOpts, - OrderStatus, OrderInfo, EventCallback, DecodedLogEvent, - TransactionEncoder, - BalanceAndAllowance, - OrderAndTraderInfo, - TraderInfo, - ValidateOrderFillableOpts, -} from '@0x/contract-wrappers'; - -export { + OrderStatus, + DutchAuctionContract, + ERC20ProxyContract, + ERC20TokenContract, + ERC721ProxyContract, + ERC721TokenContract, + ExchangeContract, + ForwarderContract, + OrderValidatorContract, + WETH9Contract, WETH9Events, WETH9WithdrawalEventArgs, WETH9ApprovalEventArgs, @@ -62,9 +52,7 @@ export { ExchangeCancelEventArgs, ExchangeEventArgs, ExchangeEvents, -} from '@0x/abi-gen-wrappers'; - -export { OrderWatcher, OnOrderStateChangeCallback, OrderWatcherConfig } from '@0x/order-watcher'; +} from '@0x/contract-wrappers'; export import Web3ProviderEngine = require('web3-provider-engine'); @@ -81,14 +69,10 @@ export { AbiDecoder, DecodedCalldata } from '@0x/utils'; export { BigNumber } from '@0x/utils'; export { - ExchangeContractErrs, Order, SignedOrder, DutchAuctionData, ECSignature, - OrderStateValid, - OrderStateInvalid, - OrderState, AssetProxyId, AssetData, SingleAssetData, @@ -99,18 +83,12 @@ export { MultiAssetDataWithRecursiveDecoding, StaticCallAssetData, SignatureType, - ObjectMap, - OrderRelevantState, - Stats, - DutchAuctionDetails, ZeroExTransaction, SignedZeroExTransaction, } from '@0x/types'; export { - BlockParamLiteral, ContractAbi, - BlockParam, LogWithDecodedArgs, ContractEventArg, SupportedProvider, diff --git a/packages/abi-gen-templates/CHANGELOG.json b/packages/abi-gen-templates/CHANGELOG.json index b246018d16..966a03d2a1 100644 --- a/packages/abi-gen-templates/CHANGELOG.json +++ b/packages/abi-gen-templates/CHANGELOG.json @@ -1,4 +1,27 @@ [ + { + "timestamp": 1565296576, + "version": "2.4.1", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "version": "2.4.0", + "changes": [ + { + "note": "Updated interface to `deployFrom0xArtifactAsync` to include log decode dependencies.", + "pr": 1995 + }, + { + "note": "Updated interface to `deployAsync` to include log decode dependencies.", + "pr": 1995 + } + ], + "timestamp": 1564604963 + }, { "version": "2.3.0", "changes": [ @@ -18,7 +41,8 @@ "note": "Python: normalize bytes parameters in wrapper methods", "pr": 1919 } - ] + ], + "timestamp": 1563957393 }, { "timestamp": 1563006338, diff --git a/packages/abi-gen-templates/CHANGELOG.md b/packages/abi-gen-templates/CHANGELOG.md index 53da19d515..6a5f773abf 100644 --- a/packages/abi-gen-templates/CHANGELOG.md +++ b/packages/abi-gen-templates/CHANGELOG.md @@ -5,6 +5,22 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.4.1 - _August 8, 2019_ + + * Dependencies updated + +## v2.4.0 - _July 31, 2019_ + + * Updated interface to `deployFrom0xArtifactAsync` to include log decode dependencies. (#1995) + * Updated interface to `deployAsync` to include log decode dependencies. (#1995) + +## v2.3.0 - _July 24, 2019_ + + * Python: fix broken event handling (#1919) + * Python: custom validator class support (#1919) + * Python: linter fixes (#1919) + * Python: normalize bytes parameters in wrapper methods (#1919) + ## v2.2.1 - _July 13, 2019_ * Dependencies updated diff --git a/packages/abi-gen-templates/Python/contract.handlebars b/packages/abi-gen-templates/Python/contract.handlebars index 25eaa2980b..6aec525d3f 100644 --- a/packages/abi-gen-templates/Python/contract.handlebars +++ b/packages/abi-gen-templates/Python/contract.handlebars @@ -11,37 +11,18 @@ from typing import ( # pylint: disable=unused-import Union, ) +from eth_utils import to_checksum_address from mypy_extensions import TypedDict # pylint: disable=unused-import from hexbytes import HexBytes +from web3 import Web3 +from web3.contract import ContractFunction from web3.datastructures import AttributeDict from web3.providers.base import BaseProvider -from zero_ex.contract_wrappers._base_contract_wrapper import BaseContractWrapper +from zero_ex.contract_wrappers.bases import ContractMethod, Validator from zero_ex.contract_wrappers.tx_params import TxParams -class {{contractName}}ValidatorBase: - """Base class for validating inputs to {{contractName}} methods.""" - def __init__( - self, - provider: BaseProvider, - contract_address: str, - private_key: str = None, - ): - """Initialize the instance.""" - - def assert_valid( - self, method_name: str, parameter_name: str, argument_value: Any - ): - """Raise an exception if method input is not valid. - - :param method_name: Name of the method whose input is to be validated. - :param parameter_name: Name of the parameter whose input is to be - validated. - :param argument_value: Value of argument to parameter to be validated. - """ - - # Try to import a custom validator class definition; if there isn't one, # declare one that we can instantiate for the default argument to the # constructor for {{contractName}} below. @@ -53,56 +34,60 @@ try: ) except ImportError: - class {{contractName}}Validator({{contractName}}ValidatorBase): # type: ignore + class {{contractName}}Validator( # type: ignore + Validator + ): """No-op input validator.""" {{tupleDefinitions ABIString}} +{{#each methods}} +{{> method_class contractName=../contractName}} +{{/each}} -# pylint: disable=too-many-public-methods -class {{contractName}}(BaseContractWrapper): +# pylint: disable=too-many-public-methods,too-many-instance-attributes +class {{contractName}}: """Wrapper class for {{contractName}} Solidity contract.{{docBytesIfNecessary ABIString}}""" +{{#each methods}} + {{toPythonIdentifier this.languageSpecificName}}: {{toPythonClassname this.languageSpecificName}}Method + """Constructor-initialized instance of + :class:`{{toPythonClassname this.languageSpecificName}}Method`. + """ + +{{/each}} def __init__( self, provider: BaseProvider, contract_address: str, validator: {{contractName}}Validator = None, - private_key: str = None, ): """Get an instance of wrapper for smart contract. :param provider: instance of :class:`web3.providers.base.BaseProvider` :param contract_address: where the contract has been deployed - :param private_key: If specified, transactions will be signed locally, - via Web3.py's `eth.account.signTransaction()`:code:, before being - sent via `eth.sendRawTransaction()`:code:. + :param validator: for validation of method inputs. """ - super().__init__( - provider=provider, - contract_address=contract_address, - private_key=private_key, - ) + self.contract_address = contract_address if not validator: - validator = {{contractName}}Validator(provider, contract_address, private_key) + validator = {{contractName}}Validator(provider, contract_address) - self.validator = validator + self._web3_eth = Web3( # type: ignore # pylint: disable=no-member + provider + ).eth - def _get_contract_instance(self, token_address): - """Get an instance of the smart contract at a specific address. + {{#if methods}} + functions = self._web3_eth.contract(address=to_checksum_address(contract_address), abi={{contractName}}.abi()).functions - :returns: contract object - """ - return self._contract_instance( - address=token_address, abi={{contractName}}.abi() - ) -{{#each methods}} -{{> call contractName=../contractName}} -{{/each}} + {{#each methods}} + self.{{toPythonIdentifier this.languageSpecificName}} = {{toPythonClassname this.languageSpecificName}}Method(provider, contract_address, functions.{{this.name}}, validator) + + {{/each}} + {{/if}} {{#each events}} -{{> event}} +{{> event contractName=../contractName}} {{/each}} @staticmethod diff --git a/packages/abi-gen-templates/Python/partials/call.handlebars b/packages/abi-gen-templates/Python/partials/call.handlebars deleted file mode 100644 index f0756937df..0000000000 --- a/packages/abi-gen-templates/Python/partials/call.handlebars +++ /dev/null @@ -1,54 +0,0 @@ - - def {{this.languageSpecificName}}( - self, - {{> typed_params inputs=inputs}} - tx_params: Optional[TxParams] = None, - {{^this.constant}} - view_only: bool = False, - {{/this.constant}} - ) -> {{> return_type outputs=outputs~}}: - """Execute underlying, same-named contract method. -{{sanitizeDevdocDetails this.name this.devdoc.details 8}}{{~#if this.devdoc.params~}}{{#each this.devdoc.params}} -{{makeParameterDocstringRole @key this 8}}{{/each}}{{/if}} - :param tx_params: transaction parameters - {{#if this.constant~}} - {{#if this.devdoc.return}} -{{makeReturnDocstringRole this.devdoc.return 8}}{{/if}} - {{else}} - :param view_only: whether to use transact() or call() - - :returns: if param `view_only`:code: is `True`:code:, then returns the - value returned from the underlying function; else returns the - transaction hash. - {{/if}} - """ - {{#each this.inputs}} - self.validator.assert_valid( - method_name='{{../name}}', - parameter_name='{{name}}', - argument_value={{toPythonIdentifier name}}, - ) - {{#if (equal type 'address')}} - {{toPythonIdentifier this.name}} = self._validate_and_checksum_address({{toPythonIdentifier this.name}}) - {{else if (equal type 'uint256')}} - # safeguard against fractional inputs - {{toPythonIdentifier this.name}} = int({{toPythonIdentifier this.name}}) - {{else if (equal type 'bytes')}} - {{toPythonIdentifier this.name}} = bytes.fromhex({{toPythonIdentifier this.name}}.decode("utf-8")) - {{else if (equal type 'bytes[]')}} - {{toPythonIdentifier this.name}} = [ - bytes.fromhex({{toPythonIdentifier this.name}}_element.decode("utf-8")) - for {{toPythonIdentifier this.name}}_element in {{toPythonIdentifier this.name}} - ] -{{/if}} -{{/each}} - func = self._get_contract_instance( - self.contract_address - ).functions.{{this.name}}( - {{> params}} - ) - return self._invoke_function_call( - func=func, - tx_params=tx_params, - view_only={{#if this.constant}}True{{else}}view_only{{/if}} - ) diff --git a/packages/abi-gen-templates/Python/partials/event.handlebars b/packages/abi-gen-templates/Python/partials/event.handlebars index 461f38b3ec..c33d9ce1b2 100644 --- a/packages/abi-gen-templates/Python/partials/event.handlebars +++ b/packages/abi-gen-templates/Python/partials/event.handlebars @@ -6,8 +6,4 @@ {{makeEventParameterDocstringRole name 8}} """ tx_receipt = self._web3_eth.getTransactionReceipt(tx_hash) - return ( - self._get_contract_instance(self.contract_address) - .events.{{name}}() - .processReceipt(tx_receipt) - ) + return self._web3_eth.contract(address=to_checksum_address(self.contract_address), abi={{contractName}}.abi()).events.{{name}}().processReceipt(tx_receipt) diff --git a/packages/abi-gen-templates/Python/partials/method_class.handlebars b/packages/abi-gen-templates/Python/partials/method_class.handlebars new file mode 100644 index 0000000000..1817eac591 --- /dev/null +++ b/packages/abi-gen-templates/Python/partials/method_class.handlebars @@ -0,0 +1,76 @@ + +class {{toPythonClassname this.languageSpecificName}}Method(ContractMethod): + """Various interfaces to the {{this.name}} method.""" + + def __init__(self, provider: BaseProvider, contract_address: str, contract_function: ContractFunction, validator: Validator=None): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + {{#if inputs}} + def validate_and_normalize_inputs(self, {{> typed_params inputs=inputs}}): + """Validate the inputs to the {{this.name}} method.""" + {{#each this.inputs}} + self.validator.assert_valid( + method_name='{{../name}}', + parameter_name='{{name}}', + argument_value={{toPythonIdentifier name}}, + ) + {{#if (equal type 'address')}} + {{toPythonIdentifier this.name}} = self.validate_and_checksum_address({{toPythonIdentifier this.name}}) + {{else if (equal type 'uint256')}} + # safeguard against fractional inputs + {{toPythonIdentifier this.name}} = int({{toPythonIdentifier this.name}}) + {{else if (equal type 'bytes')}} + {{toPythonIdentifier this.name}} = bytes.fromhex({{toPythonIdentifier this.name}}.decode("utf-8")) + {{else if (equal type 'bytes[]')}} + {{toPythonIdentifier this.name}} = [ + bytes.fromhex({{toPythonIdentifier this.name}}_element.decode("utf-8")) + for {{toPythonIdentifier this.name}}_element in {{toPythonIdentifier this.name}} + ] +{{/if}} +{{/each}} + return ({{> params }}) + + {{/if}} + def call(self, {{#if inputs}}{{> typed_params inputs=inputs}}, {{/if}}tx_params: Optional[TxParams] = None) -> {{> return_type outputs=outputs type='call'~}}: + """Execute underlying contract method via eth_call. +{{sanitizeDevdocDetails this.name this.devdoc.details 8}}{{~#if this.devdoc.params~}}{{#each this.devdoc.params}} +{{makeParameterDocstringRole @key this 8}}{{/each}}{{/if}} + :param tx_params: transaction parameters + {{#if this.constant~}} + {{#if this.devdoc.return}} +{{makeReturnDocstringRole this.devdoc.return 8}}{{/if}} + {{else}} + :returns: the return value of the underlying method. + {{/if}} + """ + {{#if inputs}} + ({{> params }}) = self.validate_and_normalize_inputs({{> params}}) + {{/if}} + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method({{> params}}).call(tx_params.as_dict()) + + def send_transaction(self, {{#if inputs}}{{> typed_params inputs=inputs}}, {{/if}}tx_params: Optional[TxParams] = None) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. +{{sanitizeDevdocDetails this.name this.devdoc.details 8}}{{~#if this.devdoc.params~}}{{#each this.devdoc.params}} +{{makeParameterDocstringRole @key this 8}}{{/each}}{{/if}} + :param tx_params: transaction parameters + {{#if this.constant~}} + {{#if this.devdoc.return}} +{{makeReturnDocstringRole this.devdoc.return 8}}{{/if}} + {{/if}} + """ + {{#if inputs}} + ({{> params }}) = self.validate_and_normalize_inputs({{> params}}) + {{/if}} + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method({{> params}}).transact(tx_params.as_dict()) + + def estimate_gas(self, {{#if inputs}}{{> typed_params inputs=inputs}}, {{/if}}tx_params: Optional[TxParams] = None) -> int: + """Estimate gas consumption of method call.""" + {{#if inputs}} + ({{> params }}) = self.validate_and_normalize_inputs({{> params}}) + {{/if}} + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method({{> params}}).estimateGas(tx_params.as_dict()) diff --git a/packages/abi-gen-templates/Python/partials/params.handlebars b/packages/abi-gen-templates/Python/partials/params.handlebars index 1b2b86e6a5..98b3dfa702 100644 --- a/packages/abi-gen-templates/Python/partials/params.handlebars +++ b/packages/abi-gen-templates/Python/partials/params.handlebars @@ -1,3 +1,3 @@ {{#each inputs}} -{{toPythonIdentifier name}}{{#if @last}}{{else}},{{/if}} -{{/each}} +{{toPythonIdentifier name}}{{#if @last}}{{else}}, {{/if~}} +{{/each~}} diff --git a/packages/abi-gen-templates/Python/partials/return_type.handlebars b/packages/abi-gen-templates/Python/partials/return_type.handlebars index 54dc63ef71..7a1e833103 100644 --- a/packages/abi-gen-templates/Python/partials/return_type.handlebars +++ b/packages/abi-gen-templates/Python/partials/return_type.handlebars @@ -7,8 +7,8 @@ Union[ {{#returnType outputs.0.type outputs.0.components}}{{~/returnType~}} {{/singleReturnValue}} {{^singleReturnValue}} -[{{#each outputs}}{{#returnType type components}}{{/returnType}}{{#unless @last}}, {{/unless}}{{/each}}] -{{/singleReturnValue}} +Tuple[{{#each outputs}}{{#returnType type components}}{{/returnType}}{{#unless @last}}, {{/unless}}{{/each}}] +{{~/singleReturnValue}} {{else}}None {{/if}}{{^if this.constant}}, Union[HexBytes, bytes]]{{/if~}} {{else}}{{#if this.constant}}None{{else}}Union[None, Union[HexBytes, bytes]]{{/if}}{{/if~}} diff --git a/packages/abi-gen-templates/Python/partials/typed_params.handlebars b/packages/abi-gen-templates/Python/partials/typed_params.handlebars index 640d1188e5..a67cd0c201 100644 --- a/packages/abi-gen-templates/Python/partials/typed_params.handlebars +++ b/packages/abi-gen-templates/Python/partials/typed_params.handlebars @@ -1,3 +1,3 @@ {{#each inputs}} -{{toPythonIdentifier name}}: {{#parameterType type components}}{{/parameterType}}, -{{/each}} +{{toPythonIdentifier name}}: {{#parameterType type components}}{{/parameterType}}{{^if @last}}, {{/if~}} +{{/each~}} diff --git a/packages/abi-gen-templates/contract.handlebars b/packages/abi-gen-templates/contract.handlebars index 67d1b6e198..12ffaba4be 100644 --- a/packages/abi-gen-templates/contract.handlebars +++ b/packages/abi-gen-templates/contract.handlebars @@ -1,7 +1,11 @@ // tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma // tslint:disable:whitespace no-unbound-method no-trailing-whitespace // tslint:disable:no-unused-variable -import { BaseContract, PromiseWithTransactionHash } from '@0x/base-contract'; +import { BaseContract{{#if events}}, + BlockRange, + EventCallback, + IndexedFilterValues, + SubscriptionManager{{/if}},PromiseWithTransactionHash } from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { BlockParam, @@ -9,7 +13,8 @@ import { CallData, ContractAbi, ContractArtifact, - DecodedLogArgs, + DecodedLogArgs,{{#if events}} + LogWithDecodedArgs,{{/if}} MethodAbi, TransactionReceiptWithDecodedLogs, TxData, @@ -46,6 +51,11 @@ export enum {{contractName}}Events { // tslint:disable-next-line:class-name export class {{contractName}}Contract extends BaseContract { {{#each methods}} + {{#if this.devdoc.details}} + /** + * {{formatDocstringForMethodTs this.devdoc.details}} + */ + {{/if}} {{#this.constant}} {{> call contractName=../contractName}} {{/this.constant}} @@ -53,10 +63,12 @@ export class {{contractName}}Contract extends BaseContract { {{> tx contractName=../contractName}} {{/this.constant}} {{/each}} - public static async deployFrom0xArtifactAsync( +{{#if events}}private readonly _subscriptionManager: SubscriptionManager<{{contractName}}EventArgs, {{contractName}}Events>; +{{/if}}public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: (ContractArtifact | SimpleContractArtifact) }, {{> typed_params inputs=ctor.inputs}} ): Promise<{{contractName}}Contract> { assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ @@ -70,13 +82,20 @@ export class {{contractName}}Contract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; - return {{contractName}}Contract.deployAsync(bytecode, abi, provider, txDefaults, {{> params inputs=ctor.inputs}}); + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return {{contractName}}Contract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly, {{> params inputs=ctor.inputs}}); } public static async deployAsync( bytecode: string, abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, {{> typed_params inputs=ctor.inputs}} ): Promise<{{contractName}}Contract> { assert.isHexString('bytecode', bytecode); @@ -105,7 +124,7 @@ export class {{contractName}}Contract extends BaseContract { logUtils.log(`transactionHash: ${txHash}`); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); logUtils.log(`{{contractName}} successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new {{contractName}}Contract(txReceipt.contractAddress as string, provider, txDefaults); + const contractInstance = new {{contractName}}Contract(txReceipt.contractAddress as string, provider, txDefaults, logDecodeDependencies); contractInstance.constructorArgs = [{{> params inputs=ctor.inputs}}]; return contractInstance; } @@ -138,10 +157,82 @@ export class {{contractName}}Contract extends BaseContract { {{/each}} ] as ContractAbi; return abi; + }{{#if events}} + /** + * Subscribe to an event type emitted by the {{contractName}} contract. + * @param eventName The {{contractName}} contract event you would like to subscribe to. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` + * @param callback Callback that gets called when a log is added/removed + * @param isVerbose Enable verbose subscription warnings (e.g recoverable network issues encountered) + * @return Subscription token used later to unsubscribe + */ + public subscribe( + eventName: {{contractName}}Events, + indexFilterValues: IndexedFilterValues, + callback: EventCallback, + isVerbose: boolean = false, + blockPollingIntervalMs?: number, + ): string { + assert.doesBelongToStringEnum('eventName', eventName, {{contractName}}Events); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + assert.isFunction('callback', callback); + const subscriptionToken = this._subscriptionManager.subscribe( + this.address, + eventName, + indexFilterValues, + {{contractName}}Contract.ABI(), + callback, + isVerbose, + blockPollingIntervalMs, + ); + return subscriptionToken; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('{{contractName}}', {{contractName}}Contract.ABI(), address, supportedProvider, txDefaults); - classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); + /** + * Cancel a subscription + * @param subscriptionToken Subscription token returned by `subscribe()` + */ + public unsubscribe(subscriptionToken: string): void { + this._subscriptionManager.unsubscribe(subscriptionToken); + } + /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + this._subscriptionManager.unsubscribeAll(); + } + /** + * Gets historical logs without creating a subscription + * @param eventName The {{contractName}} contract event you would like to subscribe to. + * @param blockRange Block range to get logs from. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` + * @return Array of logs that match the parameters + */ + public async getLogsAsync( + eventName: {{contractName}}Events, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, + ): Promise>> { + assert.doesBelongToStringEnum('eventName', eventName, {{contractName}}Events); + assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + const logs = await this._subscriptionManager.getLogsAsync( + this.address, + eventName, + blockRange, + indexFilterValues, + {{contractName}}Contract.ABI(), + ); + return logs; + }{{/if}} + constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial, logDecodeDependencies?: { [contractName: string]: ContractAbi }) { + super('{{contractName}}', {{contractName}}Contract.ABI(), address, supportedProvider, txDefaults, logDecodeDependencies); + classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']);{{#if events}} + this._subscriptionManager = new SubscriptionManager<{{contractName}}EventArgs, {{contractName}}Events>( + {{contractName}}Contract.ABI(), + this._web3Wrapper, + );{{/if}} } } diff --git a/packages/abi-gen-templates/package.json b/packages/abi-gen-templates/package.json index 115f96d8bd..62524d7000 100644 --- a/packages/abi-gen-templates/package.json +++ b/packages/abi-gen-templates/package.json @@ -1,6 +1,6 @@ { "name": "@0x/abi-gen-templates", - "version": "2.2.1", + "version": "2.4.1", "engines": { "node": ">=6.12" }, diff --git a/packages/abi-gen-templates/partials/callAsync.handlebars b/packages/abi-gen-templates/partials/callAsync.handlebars index 51d26ad8e6..1389ea8a06 100644 --- a/packages/abi-gen-templates/partials/callAsync.handlebars +++ b/packages/abi-gen-templates/partials/callAsync.handlebars @@ -1,3 +1,12 @@ +/** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. +{{> params_docstring inputs=inputs docstrings=devdoc.params}} +{{#if devdoc.return}} + * @returns {{devdoc.return}} +{{/if}} + */ async callAsync( {{> typed_params inputs=inputs}} callData: Partial = {}, @@ -39,6 +48,12 @@ async callAsync( // tslint:enable boolean-naming return result; }, +/** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). +{{> params_docstring inputs=inputs docstrings=devdoc.params}} + */ getABIEncodedTransactionData( {{> typed_params inputs=inputs}} ): string { @@ -49,3 +64,21 @@ getABIEncodedTransactionData( const abiEncodedTransactionData = self._strictEncodeArguments('{{this.functionSignature}}', [{{> normalized_params inputs=inputs}}]); return abiEncodedTransactionData; }, +getABIDecodedTransactionData( + callData: string +): ({{> return_type inputs=inputs ~}}) { + const self = this as any as {{contractName}}Contract; + const abiEncoder = self._lookupAbiEncoder('{{this.functionSignature}}'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<{{> return_type inputs=inputs}}>(callData); + return abiDecodedCallData; +}, +getABIDecodedReturnData( + returnData: string +): ({{> return_type outputs=outputs ~}}) { + const self = this as any as {{contractName}}Contract; + const abiEncoder = self._lookupAbiEncoder('{{this.functionSignature}}'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<{{> return_type outputs=outputs}}>(returnData); + return abiDecodedReturnData; +}, diff --git a/packages/abi-gen-templates/partials/params_docstring.handlebars b/packages/abi-gen-templates/partials/params_docstring.handlebars new file mode 100644 index 0000000000..86aa1d0aeb --- /dev/null +++ b/packages/abi-gen-templates/partials/params_docstring.handlebars @@ -0,0 +1,5 @@ +{{#each inputs}} + {{#if (getDocstringForParamTs name ../docstrings)}} + {{formatDocstringForParamTs name (getDocstringForParamTs name ../docstrings)}} + {{/if}} +{{/each}} diff --git a/packages/abi-gen-templates/partials/tx.handlebars b/packages/abi-gen-templates/partials/tx.handlebars index b2c695c87b..a2ee94af53 100644 --- a/packages/abi-gen-templates/partials/tx.handlebars +++ b/packages/abi-gen-templates/partials/tx.handlebars @@ -1,4 +1,11 @@ public {{languageSpecificName}} = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + {{> params_docstring inputs=inputs docstrings=devdoc.params}} + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( {{> typed_params inputs=inputs}} txData?: Partial | undefined, @@ -30,6 +37,14 @@ public {{languageSpecificName}} = { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + {{> params_docstring inputs=inputs docstrings=devdoc.params}} + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( {{> typed_params inputs=inputs}} txData?: Partial, @@ -57,6 +72,12 @@ public {{languageSpecificName}} = { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + {{> params_docstring inputs=inputs docstrings=devdoc.params}} + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( {{> typed_params inputs=inputs}} txData?: Partial | undefined, @@ -85,4 +106,22 @@ public {{languageSpecificName}} = { return gas; }, {{> callAsync}} + async validateAndSendTransactionAsync( + {{> typed_params inputs=inputs}} + txData?: Partial | undefined, + ): Promise { + await (this as any).{{languageSpecificName}}.callAsync( + {{#each inputs~}} + {{name}}, + {{/each~}} + txData, + ); + const txHash = await (this as any).{{languageSpecificName}}.sendTransactionAsync( + {{#each inputs~}} + {{name}}, + {{/each~}} + txData, + ); + return txHash; + } }; diff --git a/packages/abi-gen-wrappers/CHANGELOG.json b/packages/abi-gen-wrappers/CHANGELOG.json index 01cabd2a33..6d0a89c00b 100644 --- a/packages/abi-gen-wrappers/CHANGELOG.json +++ b/packages/abi-gen-wrappers/CHANGELOG.json @@ -1,4 +1,42 @@ [ + { + "version": "5.3.0", + "changes": [ + { + "note": "Added DevUtils", + "pr": 2060 + } + ] + }, + { + "version": "5.2.0", + "changes": [ + { + "note": "Updated to include `getABIDecodedTransactionData` and `getABIDecodedReturnData`", + "pr": 2018 + } + ], + "timestamp": 1565296576 + }, + { + "version": "5.1.0", + "changes": [ + { + "note": "Add subscribe/unsubscribe methods for events", + "pr": 1970 + } + ], + "timestamp": 1564604963 + }, + { + "timestamp": 1563957393, + "version": "5.0.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563193019, "version": "5.0.2", diff --git a/packages/abi-gen-wrappers/CHANGELOG.md b/packages/abi-gen-wrappers/CHANGELOG.md index 3fff8c98f4..13e5cd3781 100644 --- a/packages/abi-gen-wrappers/CHANGELOG.md +++ b/packages/abi-gen-wrappers/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v5.2.0 - _August 8, 2019_ + + * Updated to include `getABIDecodedTransactionData` and `getABIDecodedReturnData` (#2018) + +## v5.1.0 - _July 31, 2019_ + + * Add subscribe/unsubscribe methods for events (#1970) + +## v5.0.3 - _July 24, 2019_ + + * Dependencies updated + ## v5.0.2 - _July 15, 2019_ * Dependencies updated @@ -18,6 +30,7 @@ CHANGELOG * Wrappers no longer require passing in the contract ABI at instantiation (#1883) * Contract addresses now re-exported from @0x/contract-addresses (#1883) * Update wrappers to include parameter assertions (#1823) + * Update wrappers to normalize address inputs to lowercase (#1951) * Update wrappers to include `getABIEncodedTransactionData` for view and pure functions (#1863) ## v4.3.0 - _May 10, 2019_ diff --git a/packages/abi-gen-wrappers/README.md b/packages/abi-gen-wrappers/README.md index bcf58ae067..c48ef6cab4 100644 --- a/packages/abi-gen-wrappers/README.md +++ b/packages/abi-gen-wrappers/README.md @@ -71,3 +71,9 @@ yarn lint ```bash yarn test ``` + +### Documentation + +Documentation for this package is generated by TypeDoc, using the Solidity source code for 0x contracts. Each contract corresponds to one global-level module, which contains relevant enums and interfaces for its events and structs. Most significantly, each module exports a class, `Contract`, e.g. `ExchangeContract`, which implements helper methods for all the functions defined in the corresponding contract. + +A convention to note is that these contract-specific helper methods are defined as _object literals_, which are separated from methods in the generated documentation. Each contract method has a number of sub-methods, e.g. `sendTransactionAsync`, or `estimateGasAsync`, which are documented separately. This is an example of an expected method call signature: `exchangeContractInstance.fillOrder.sendTransactionAsync(...arguments)`. diff --git a/packages/abi-gen-wrappers/package.json b/packages/abi-gen-wrappers/package.json index e317886a49..188bc9946d 100644 --- a/packages/abi-gen-wrappers/package.json +++ b/packages/abi-gen-wrappers/package.json @@ -1,6 +1,6 @@ { "name": "@0x/abi-gen-wrappers", - "version": "5.0.2", + "version": "5.2.0", "engines": { "node": ">=6.12" }, @@ -10,7 +10,7 @@ "test": "test" }, "scripts": { - "build": "yarn pre_build && tsc -b", + "build": "yarn pre_build && tsc -b && yarn docs", "build:ci": "yarn build", "lint": "tslint --format stylish --project .", "fix": "tslint --fix --format stylish --project .", @@ -18,10 +18,11 @@ "prettier": "prettier --write src/**/* --config ../../.prettierrc", "prettier_contract_wrappers": "prettier --write src/generated-wrappers/* --config ../../.prettierrc", "clean": "shx rm -rf lib src/generated-wrappers", - "generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output src/generated-wrappers --backend ethers" + "generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output src/generated-wrappers --backend ethers", + "docs": "typedoc --excludePrivate --excludeExternals --target ES5 --tsconfig typedoc-tsconfig.json --out generated_docs ./src/generated-wrappers/*" }, "config": { - "abis": "../contract-artifacts/artifacts/@(AssetProxyOwner|DutchAuction|DummyERC20Token|DummyERC721Token|ERC20Proxy|ERC20Token|ERC721Proxy|ERC721Token|Exchange|Forwarder|IAssetProxy|IValidator|IWallet|MultiAssetProxy|OrderValidator|WETH9|ZRXToken|Coordinator|CoordinatorRegistry|EthBalanceChecker).json" + "abis": "../contract-artifacts/artifacts/@(AssetProxyOwner|DevUtils|DutchAuction|DummyERC20Token|DummyERC721Token|ERC20Proxy|ERC20Token|ERC721Proxy|ERC721Token|Exchange|Forwarder|IAssetProxy|IValidator|IWallet|MultiAssetProxy|OrderValidator|WETH9|ZRXToken|Coordinator|CoordinatorRegistry|EthBalanceChecker|ERC1155Proxy|StaticCallProxy).json" }, "repository": { "type": "git", @@ -33,23 +34,23 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen-wrappers/README.md", "devDependencies": { - "@0x/abi-gen": "^2.1.1", - "@0x/abi-gen-templates": "^2.2.1", - "@0x/assert": "^2.1.0", - "@0x/json-schemas": "^3.0.11", + "@0x/abi-gen": "^4.1.0", + "@0x/abi-gen-templates": "^2.4.1", + "@0x/assert": "^2.1.3", + "@0x/json-schemas": "^3.1.13", "@0x/tslint-config": "^3.0.1", - "@0x/types": "^2.4.0", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", - "ethereum-types": "^2.1.3", + "@0x/types": "^2.4.1", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", + "ethereum-types": "^2.1.4", "ethers": "~4.0.4", "lodash": "^4.17.11", "shx": "^0.2.2" }, "dependencies": { - "@0x/base-contract": "^5.1.1", - "@0x/contract-addresses": "^3.0.2", - "@0x/contract-artifacts": "^2.0.1" + "@0x/base-contract": "^5.3.1", + "@0x/contract-addresses": "^3.0.3", + "@0x/contract-artifacts": "^2.0.4" }, "publishConfig": { "access": "public" diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/asset_proxy_owner.ts b/packages/abi-gen-wrappers/src/generated-wrappers/asset_proxy_owner.ts index e21bd4b40a..15cc5186d6 100644 --- a/packages/abi-gen-wrappers/src/generated-wrappers/asset_proxy_owner.ts +++ b/packages/abi-gen-wrappers/src/generated-wrappers/asset_proxy_owner.ts @@ -1,7 +1,14 @@ // tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma // tslint:disable:whitespace no-unbound-method no-trailing-whitespace // tslint:disable:no-unused-variable -import { BaseContract, PromiseWithTransactionHash } from '@0x/base-contract'; +import { + BaseContract, + BlockRange, + EventCallback, + IndexedFilterValues, + SubscriptionManager, + PromiseWithTransactionHash, +} from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { BlockParam, @@ -10,6 +17,7 @@ import { ContractAbi, ContractArtifact, DecodedLogArgs, + LogWithDecodedArgs, MethodAbi, TransactionReceiptWithDecodedLogs, TxData, @@ -110,6 +118,11 @@ export interface AssetProxyOwnerRequirementChangeEventArgs extends DecodedLogArg // tslint:disable-next-line:class-name export class AssetProxyOwnerContract extends BaseContract { public owners = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( index_0: BigNumber, callData: Partial = {}, @@ -151,14 +164,43 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: BigNumber): string { assert.isBigNumber('index_0', index_0); const self = (this as any) as AssetProxyOwnerContract; const abiEncodedTransactionData = self._strictEncodeArguments('owners(uint256)', [index_0]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('owners(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('owners(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Allows to remove an owner. Transaction has to be sent by wallet. + */ public removeOwner = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param owner Address of owner. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(owner: string, txData?: Partial | undefined): Promise { const self = (this as any) as AssetProxyOwnerContract; const encodedData = self._strictEncodeArguments('removeOwner(address)', [owner]); @@ -184,6 +226,14 @@ export class AssetProxyOwnerContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param owner Address of owner. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( owner: string, txData?: Partial, @@ -205,6 +255,12 @@ export class AssetProxyOwnerContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param owner Address of owner. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(owner: string, txData?: Partial | undefined): Promise { const self = (this as any) as AssetProxyOwnerContract; const encodedData = self._strictEncodeArguments('removeOwner(address)', [owner]); @@ -229,6 +285,12 @@ export class AssetProxyOwnerContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param owner Address of owner. + */ async callAsync(owner: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isString('owner', owner); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -266,6 +328,12 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param owner Address of owner. + */ getABIEncodedTransactionData(owner: string): string { assert.isString('owner', owner); const self = (this as any) as AssetProxyOwnerContract; @@ -274,8 +342,37 @@ export class AssetProxyOwnerContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('removeOwner(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('removeOwner(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(owner: string, txData?: Partial | undefined): Promise { + await (this as any).removeOwner.callAsync(owner, txData); + const txHash = await (this as any).removeOwner.sendTransactionAsync(owner, txData); + return txHash; + }, }; + /** + * Allows an owner to revoke a confirmation for a transaction. + */ public revokeConfirmation = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param transactionId Transaction ID. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(transactionId: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as AssetProxyOwnerContract; const encodedData = self._strictEncodeArguments('revokeConfirmation(uint256)', [transactionId]); @@ -301,6 +398,14 @@ export class AssetProxyOwnerContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param transactionId Transaction ID. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( transactionId: BigNumber, txData?: Partial, @@ -322,6 +427,12 @@ export class AssetProxyOwnerContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param transactionId Transaction ID. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(transactionId: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as AssetProxyOwnerContract; const encodedData = self._strictEncodeArguments('revokeConfirmation(uint256)', [transactionId]); @@ -346,6 +457,12 @@ export class AssetProxyOwnerContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param transactionId Transaction ID. + */ async callAsync( transactionId: BigNumber, callData: Partial = {}, @@ -387,6 +504,12 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param transactionId Transaction ID. + */ getABIEncodedTransactionData(transactionId: BigNumber): string { assert.isBigNumber('transactionId', transactionId); const self = (this as any) as AssetProxyOwnerContract; @@ -395,8 +518,35 @@ export class AssetProxyOwnerContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('revokeConfirmation(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('revokeConfirmation(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + transactionId: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).revokeConfirmation.callAsync(transactionId, txData); + const txHash = await (this as any).revokeConfirmation.sendTransactionAsync(transactionId, txData); + return txHash; + }, }; public isOwner = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( index_0: string, callData: Partial = {}, @@ -438,14 +588,38 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: string): string { assert.isString('index_0', index_0); const self = (this as any) as AssetProxyOwnerContract; const abiEncodedTransactionData = self._strictEncodeArguments('isOwner(address)', [index_0.toLowerCase()]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('isOwner(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('isOwner(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public confirmations = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( index_0: BigNumber, index_1: string, @@ -492,6 +666,11 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: BigNumber, index_1: string): string { assert.isBigNumber('index_0', index_0); assert.isString('index_1', index_1); @@ -502,8 +681,32 @@ export class AssetProxyOwnerContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('confirmations(uint256,address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('confirmations(uint256,address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Allows execution of `removeAuthorizedAddressAtIndex` without time lock. + */ public executeRemoveAuthorizedAddressAtIndex = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param transactionId Transaction ID. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(transactionId: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as AssetProxyOwnerContract; const encodedData = self._strictEncodeArguments('executeRemoveAuthorizedAddressAtIndex(uint256)', [ @@ -531,6 +734,14 @@ export class AssetProxyOwnerContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param transactionId Transaction ID. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( transactionId: BigNumber, txData?: Partial, @@ -555,6 +766,12 @@ export class AssetProxyOwnerContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param transactionId Transaction ID. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(transactionId: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as AssetProxyOwnerContract; const encodedData = self._strictEncodeArguments('executeRemoveAuthorizedAddressAtIndex(uint256)', [ @@ -581,6 +798,12 @@ export class AssetProxyOwnerContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param transactionId Transaction ID. + */ async callAsync( transactionId: BigNumber, callData: Partial = {}, @@ -624,6 +847,12 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param transactionId Transaction ID. + */ getABIEncodedTransactionData(transactionId: BigNumber): string { assert.isBigNumber('transactionId', transactionId); const self = (this as any) as AssetProxyOwnerContract; @@ -633,8 +862,38 @@ export class AssetProxyOwnerContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('executeRemoveAuthorizedAddressAtIndex(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('executeRemoveAuthorizedAddressAtIndex(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + transactionId: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).executeRemoveAuthorizedAddressAtIndex.callAsync(transactionId, txData); + const txHash = await (this as any).executeRemoveAuthorizedAddressAtIndex.sendTransactionAsync( + transactionId, + txData, + ); + return txHash; + }, }; public secondsTimeLocked = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -671,13 +930,43 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as AssetProxyOwnerContract; const abiEncodedTransactionData = self._strictEncodeArguments('secondsTimeLocked()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('secondsTimeLocked()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('secondsTimeLocked()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Returns total number of transactions after filers are applied. + */ public getTransactionCount = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param pending Include pending transactions. + * @param executed Include executed transactions. + * @returns Total number of transactions after filters are applied. + */ async callAsync( pending: boolean, executed: boolean, @@ -721,6 +1010,13 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param pending Include pending transactions. + * @param executed Include executed transactions. + */ getABIEncodedTransactionData(pending: boolean, executed: boolean): string { assert.isBoolean('pending', pending); assert.isBoolean('executed', executed); @@ -731,8 +1027,34 @@ export class AssetProxyOwnerContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('getTransactionCount(bool,bool)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('getTransactionCount(bool,bool)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Registers or deregisters an AssetProxy to be able to execute + * `removeAuthorizedAddressAtIndex` without a timelock. + */ public registerAssetProxy = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param assetProxyContract Address of AssetProxy contract. + * @param isRegistered Status of approval for AssetProxy contract. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( assetProxyContract: string, isRegistered: boolean, @@ -765,6 +1087,15 @@ export class AssetProxyOwnerContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param assetProxyContract Address of AssetProxy contract. + * @param isRegistered Status of approval for AssetProxy contract. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( assetProxyContract: string, isRegistered: boolean, @@ -792,6 +1123,13 @@ export class AssetProxyOwnerContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param assetProxyContract Address of AssetProxy contract. + * @param isRegistered Status of approval for AssetProxy contract. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( assetProxyContract: string, isRegistered: boolean, @@ -823,6 +1161,13 @@ export class AssetProxyOwnerContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param assetProxyContract Address of AssetProxy contract. + * @param isRegistered Status of approval for AssetProxy contract. + */ async callAsync( assetProxyContract: string, isRegistered: boolean, @@ -869,6 +1214,13 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param assetProxyContract Address of AssetProxy contract. + * @param isRegistered Status of approval for AssetProxy contract. + */ getABIEncodedTransactionData(assetProxyContract: string, isRegistered: boolean): string { assert.isString('assetProxyContract', assetProxyContract); assert.isBoolean('isRegistered', isRegistered); @@ -879,8 +1231,45 @@ export class AssetProxyOwnerContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('registerAssetProxy(address,bool)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('registerAssetProxy(address,bool)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + assetProxyContract: string, + isRegistered: boolean, + txData?: Partial | undefined, + ): Promise { + await (this as any).registerAssetProxy.callAsync(assetProxyContract, isRegistered, txData); + const txHash = await (this as any).registerAssetProxy.sendTransactionAsync( + assetProxyContract, + isRegistered, + txData, + ); + return txHash; + }, }; + /** + * Allows to add a new owner. Transaction has to be sent by wallet. + */ public addOwner = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param owner Address of new owner. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(owner: string, txData?: Partial | undefined): Promise { const self = (this as any) as AssetProxyOwnerContract; const encodedData = self._strictEncodeArguments('addOwner(address)', [owner]); @@ -906,6 +1295,14 @@ export class AssetProxyOwnerContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param owner Address of new owner. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( owner: string, txData?: Partial, @@ -927,6 +1324,12 @@ export class AssetProxyOwnerContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param owner Address of new owner. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(owner: string, txData?: Partial | undefined): Promise { const self = (this as any) as AssetProxyOwnerContract; const encodedData = self._strictEncodeArguments('addOwner(address)', [owner]); @@ -951,6 +1354,12 @@ export class AssetProxyOwnerContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param owner Address of new owner. + */ async callAsync(owner: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isString('owner', owner); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -988,14 +1397,49 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param owner Address of new owner. + */ getABIEncodedTransactionData(owner: string): string { assert.isString('owner', owner); const self = (this as any) as AssetProxyOwnerContract; const abiEncodedTransactionData = self._strictEncodeArguments('addOwner(address)', [owner.toLowerCase()]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('addOwner(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('addOwner(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(owner: string, txData?: Partial | undefined): Promise { + await (this as any).addOwner.callAsync(owner, txData); + const txHash = await (this as any).addOwner.sendTransactionAsync(owner, txData); + return txHash; + }, }; + /** + * Returns the confirmation status of a transaction. + */ public isConfirmed = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param transactionId Transaction ID. + * @returns Confirmation status. + */ async callAsync( transactionId: BigNumber, callData: Partial = {}, @@ -1037,14 +1481,45 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param transactionId Transaction ID. + */ getABIEncodedTransactionData(transactionId: BigNumber): string { assert.isBigNumber('transactionId', transactionId); const self = (this as any) as AssetProxyOwnerContract; const abiEncodedTransactionData = self._strictEncodeArguments('isConfirmed(uint256)', [transactionId]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('isConfirmed(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('isConfirmed(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Changes the duration of the time lock for transactions. + */ public changeTimeLock = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _secondsTimeLocked Duration needed after a transaction is confirmed + * and before it becomes executable, in seconds. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _secondsTimeLocked: BigNumber, txData?: Partial | undefined, @@ -1073,6 +1548,15 @@ export class AssetProxyOwnerContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _secondsTimeLocked Duration needed after a transaction is confirmed + * and before it becomes executable, in seconds. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _secondsTimeLocked: BigNumber, txData?: Partial, @@ -1094,6 +1578,13 @@ export class AssetProxyOwnerContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _secondsTimeLocked Duration needed after a transaction is confirmed + * and before it becomes executable, in seconds. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(_secondsTimeLocked: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as AssetProxyOwnerContract; const encodedData = self._strictEncodeArguments('changeTimeLock(uint256)', [_secondsTimeLocked]); @@ -1118,6 +1609,13 @@ export class AssetProxyOwnerContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _secondsTimeLocked Duration needed after a transaction is confirmed + * and before it becomes executable, in seconds. + */ async callAsync( _secondsTimeLocked: BigNumber, callData: Partial = {}, @@ -1159,6 +1657,13 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _secondsTimeLocked Duration needed after a transaction is confirmed + * and before it becomes executable, in seconds. + */ getABIEncodedTransactionData(_secondsTimeLocked: BigNumber): string { assert.isBigNumber('_secondsTimeLocked', _secondsTimeLocked); const self = (this as any) as AssetProxyOwnerContract; @@ -1167,8 +1672,35 @@ export class AssetProxyOwnerContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('changeTimeLock(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('changeTimeLock(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _secondsTimeLocked: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).changeTimeLock.callAsync(_secondsTimeLocked, txData); + const txHash = await (this as any).changeTimeLock.sendTransactionAsync(_secondsTimeLocked, txData); + return txHash; + }, }; public isAssetProxyRegistered = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( index_0: string, callData: Partial = {}, @@ -1210,6 +1742,11 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: string): string { assert.isString('index_0', index_0); const self = (this as any) as AssetProxyOwnerContract; @@ -1218,8 +1755,32 @@ export class AssetProxyOwnerContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('isAssetProxyRegistered(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('isAssetProxyRegistered(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Returns number of confirmations of a transaction. + */ public getConfirmationCount = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param transactionId Transaction ID. + * @returns Number of confirmations. + */ async callAsync( transactionId: BigNumber, callData: Partial = {}, @@ -1261,6 +1822,12 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param transactionId Transaction ID. + */ getABIEncodedTransactionData(transactionId: BigNumber): string { assert.isBigNumber('transactionId', transactionId); const self = (this as any) as AssetProxyOwnerContract; @@ -1269,8 +1836,27 @@ export class AssetProxyOwnerContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('getConfirmationCount(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('getConfirmationCount(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public transactions = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( index_0: BigNumber, callData: Partial = {}, @@ -1312,14 +1898,44 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: BigNumber): string { assert.isBigNumber('index_0', index_0); const self = (this as any) as AssetProxyOwnerContract; const abiEncodedTransactionData = self._strictEncodeArguments('transactions(uint256)', [index_0]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): [string, BigNumber, string, boolean] { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('transactions(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<[string, BigNumber, string, boolean]>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): [string, BigNumber, string, boolean] { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('transactions(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<[string, BigNumber, string, boolean]>( + returnData, + ); + return abiDecodedReturnData; + }, }; + /** + * Returns list of owners. + */ public getOwners = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @returns List of owner addresses. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -1356,13 +1972,45 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as AssetProxyOwnerContract; const abiEncodedTransactionData = self._strictEncodeArguments('getOwners()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string[] { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('getOwners()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string[] { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('getOwners()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Returns list of transaction IDs in defined range. + */ public getTransactionIds = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param from Index start position of transaction array. + * @param to Index end position of transaction array. + * @param pending Include pending transactions. + * @param executed Include executed transactions. + * @returns Returns array of transaction IDs. + */ async callAsync( from: BigNumber, to: BigNumber, @@ -1415,6 +2063,15 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param from Index start position of transaction array. + * @param to Index end position of transaction array. + * @param pending Include pending transactions. + * @param executed Include executed transactions. + */ getABIEncodedTransactionData(from: BigNumber, to: BigNumber, pending: boolean, executed: boolean): string { assert.isBigNumber('from', from); assert.isBigNumber('to', to); @@ -1427,8 +2084,32 @@ export class AssetProxyOwnerContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber[] { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('getTransactionIds(uint256,uint256,bool,bool)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber[] { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('getTransactionIds(uint256,uint256,bool,bool)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Returns array with owner addresses, which confirmed transaction. + */ public getConfirmations = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param transactionId Transaction ID. + * @returns Returns array of owner addresses. + */ async callAsync( transactionId: BigNumber, callData: Partial = {}, @@ -1470,14 +2151,39 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param transactionId Transaction ID. + */ getABIEncodedTransactionData(transactionId: BigNumber): string { assert.isBigNumber('transactionId', transactionId); const self = (this as any) as AssetProxyOwnerContract; const abiEncodedTransactionData = self._strictEncodeArguments('getConfirmations(uint256)', [transactionId]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string[] { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('getConfirmations(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string[] { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('getConfirmations(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public transactionCount = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -1514,13 +2220,42 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as AssetProxyOwnerContract; const abiEncodedTransactionData = self._strictEncodeArguments('transactionCount()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('transactionCount()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('transactionCount()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Allows to change the number of required confirmations. Transaction has to be sent by wallet. + */ public changeRequirement = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _required Number of required confirmations. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(_required: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as AssetProxyOwnerContract; const encodedData = self._strictEncodeArguments('changeRequirement(uint256)', [_required]); @@ -1546,6 +2281,14 @@ export class AssetProxyOwnerContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _required Number of required confirmations. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _required: BigNumber, txData?: Partial, @@ -1567,6 +2310,12 @@ export class AssetProxyOwnerContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _required Number of required confirmations. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(_required: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as AssetProxyOwnerContract; const encodedData = self._strictEncodeArguments('changeRequirement(uint256)', [_required]); @@ -1591,6 +2340,12 @@ export class AssetProxyOwnerContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _required Number of required confirmations. + */ async callAsync( _required: BigNumber, callData: Partial = {}, @@ -1632,14 +2387,52 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _required Number of required confirmations. + */ getABIEncodedTransactionData(_required: BigNumber): string { assert.isBigNumber('_required', _required); const self = (this as any) as AssetProxyOwnerContract; const abiEncodedTransactionData = self._strictEncodeArguments('changeRequirement(uint256)', [_required]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('changeRequirement(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('changeRequirement(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _required: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).changeRequirement.callAsync(_required, txData); + const txHash = await (this as any).changeRequirement.sendTransactionAsync(_required, txData); + return txHash; + }, }; + /** + * Allows an owner to confirm a transaction. + */ public confirmTransaction = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param transactionId Transaction ID. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(transactionId: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as AssetProxyOwnerContract; const encodedData = self._strictEncodeArguments('confirmTransaction(uint256)', [transactionId]); @@ -1665,6 +2458,14 @@ export class AssetProxyOwnerContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param transactionId Transaction ID. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( transactionId: BigNumber, txData?: Partial, @@ -1686,6 +2487,12 @@ export class AssetProxyOwnerContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param transactionId Transaction ID. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(transactionId: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as AssetProxyOwnerContract; const encodedData = self._strictEncodeArguments('confirmTransaction(uint256)', [transactionId]); @@ -1710,6 +2517,12 @@ export class AssetProxyOwnerContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param transactionId Transaction ID. + */ async callAsync( transactionId: BigNumber, callData: Partial = {}, @@ -1751,6 +2564,12 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param transactionId Transaction ID. + */ getABIEncodedTransactionData(transactionId: BigNumber): string { assert.isBigNumber('transactionId', transactionId); const self = (this as any) as AssetProxyOwnerContract; @@ -1759,8 +2578,42 @@ export class AssetProxyOwnerContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('confirmTransaction(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('confirmTransaction(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + transactionId: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).confirmTransaction.callAsync(transactionId, txData); + const txHash = await (this as any).confirmTransaction.sendTransactionAsync(transactionId, txData); + return txHash; + }, }; + /** + * Allows an owner to submit and confirm a transaction. + */ public submitTransaction = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param destination Transaction target address. + * @param value Transaction ether value. + * @param data Transaction data payload. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( destination: string, value: BigNumber, @@ -1795,6 +2648,16 @@ export class AssetProxyOwnerContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param destination Transaction target address. + * @param value Transaction ether value. + * @param data Transaction data payload. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( destination: string, value: BigNumber, @@ -1825,6 +2688,14 @@ export class AssetProxyOwnerContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param destination Transaction target address. + * @param value Transaction ether value. + * @param data Transaction data payload. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( destination: string, value: BigNumber, @@ -1858,6 +2729,15 @@ export class AssetProxyOwnerContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param destination Transaction target address. + * @param value Transaction ether value. + * @param data Transaction data payload. + * @returns Returns transaction ID. + */ async callAsync( destination: string, value: BigNumber, @@ -1907,6 +2787,14 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param destination Transaction target address. + * @param value Transaction ether value. + * @param data Transaction data payload. + */ getABIEncodedTransactionData(destination: string, value: BigNumber, data: string): string { assert.isString('destination', destination); assert.isBigNumber('value', value); @@ -1919,8 +2807,37 @@ export class AssetProxyOwnerContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('submitTransaction(address,uint256,bytes)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('submitTransaction(address,uint256,bytes)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + destination: string, + value: BigNumber, + data: string, + txData?: Partial | undefined, + ): Promise { + await (this as any).submitTransaction.callAsync(destination, value, data, txData); + const txHash = await (this as any).submitTransaction.sendTransactionAsync(destination, value, data, txData); + return txHash; + }, }; public confirmationTimes = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( index_0: BigNumber, callData: Partial = {}, @@ -1962,14 +2879,38 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: BigNumber): string { assert.isBigNumber('index_0', index_0); const self = (this as any) as AssetProxyOwnerContract; const abiEncodedTransactionData = self._strictEncodeArguments('confirmationTimes(uint256)', [index_0]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('confirmationTimes(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('confirmationTimes(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public MAX_OWNER_COUNT = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -2006,13 +2947,37 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as AssetProxyOwnerContract; const abiEncodedTransactionData = self._strictEncodeArguments('MAX_OWNER_COUNT()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('MAX_OWNER_COUNT()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('MAX_OWNER_COUNT()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public required = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -2049,13 +3014,43 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as AssetProxyOwnerContract; const abiEncodedTransactionData = self._strictEncodeArguments('required()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('required()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('required()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Allows to replace an owner with a new owner. Transaction has to be sent by wallet. + */ public replaceOwner = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param owner Address of owner to be replaced. + * @param newOwner Address of new owner. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( owner: string, newOwner: string, @@ -2085,6 +3080,15 @@ export class AssetProxyOwnerContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param owner Address of owner to be replaced. + * @param newOwner Address of new owner. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( owner: string, newOwner: string, @@ -2112,6 +3116,13 @@ export class AssetProxyOwnerContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param owner Address of owner to be replaced. + * @param newOwner Address of new owner. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(owner: string, newOwner: string, txData?: Partial | undefined): Promise { const self = (this as any) as AssetProxyOwnerContract; const encodedData = self._strictEncodeArguments('replaceOwner(address,address)', [owner, newOwner]); @@ -2136,6 +3147,13 @@ export class AssetProxyOwnerContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param owner Address of owner to be replaced. + * @param newOwner Address of new owner. + */ async callAsync( owner: string, newOwner: string, @@ -2182,6 +3200,13 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param owner Address of owner to be replaced. + * @param newOwner Address of new owner. + */ getABIEncodedTransactionData(owner: string, newOwner: string): string { assert.isString('owner', owner); assert.isString('newOwner', newOwner); @@ -2192,8 +3217,41 @@ export class AssetProxyOwnerContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('replaceOwner(address,address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('replaceOwner(address,address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + owner: string, + newOwner: string, + txData?: Partial | undefined, + ): Promise { + await (this as any).replaceOwner.callAsync(owner, newOwner, txData); + const txHash = await (this as any).replaceOwner.sendTransactionAsync(owner, newOwner, txData); + return txHash; + }, }; + /** + * Allows anyone to execute a confirmed transaction. + */ public executeTransaction = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param transactionId Transaction ID. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(transactionId: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as AssetProxyOwnerContract; const encodedData = self._strictEncodeArguments('executeTransaction(uint256)', [transactionId]); @@ -2219,6 +3277,14 @@ export class AssetProxyOwnerContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param transactionId Transaction ID. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( transactionId: BigNumber, txData?: Partial, @@ -2240,6 +3306,12 @@ export class AssetProxyOwnerContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param transactionId Transaction ID. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(transactionId: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as AssetProxyOwnerContract; const encodedData = self._strictEncodeArguments('executeTransaction(uint256)', [transactionId]); @@ -2264,6 +3336,12 @@ export class AssetProxyOwnerContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param transactionId Transaction ID. + */ async callAsync( transactionId: BigNumber, callData: Partial = {}, @@ -2305,6 +3383,12 @@ export class AssetProxyOwnerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param transactionId Transaction ID. + */ getABIEncodedTransactionData(transactionId: BigNumber): string { assert.isBigNumber('transactionId', transactionId); const self = (this as any) as AssetProxyOwnerContract; @@ -2313,11 +3397,35 @@ export class AssetProxyOwnerContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('executeTransaction(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AssetProxyOwnerContract; + const abiEncoder = self._lookupAbiEncoder('executeTransaction(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + transactionId: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).executeTransaction.callAsync(transactionId, txData); + const txHash = await (this as any).executeTransaction.sendTransactionAsync(transactionId, txData); + return txHash; + }, }; + private readonly _subscriptionManager: SubscriptionManager; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, _owners: string[], _assetProxyContracts: string[], _required: BigNumber, @@ -2334,11 +3442,18 @@ export class AssetProxyOwnerContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } return AssetProxyOwnerContract.deployAsync( bytecode, abi, provider, txDefaults, + logDecodeDependenciesAbiOnly, _owners, _assetProxyContracts, _required, @@ -2350,6 +3465,7 @@ export class AssetProxyOwnerContract extends BaseContract { abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, _owners: string[], _assetProxyContracts: string[], _required: BigNumber, @@ -2381,7 +3497,12 @@ export class AssetProxyOwnerContract extends BaseContract { logUtils.log(`transactionHash: ${txHash}`); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); logUtils.log(`AssetProxyOwner successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new AssetProxyOwnerContract(txReceipt.contractAddress as string, provider, txDefaults); + const contractInstance = new AssetProxyOwnerContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); contractInstance.constructorArgs = [_owners, _assetProxyContracts, _required, _secondsTimeLocked]; return contractInstance; } @@ -3092,9 +4213,93 @@ export class AssetProxyOwnerContract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('AssetProxyOwner', AssetProxyOwnerContract.ABI(), address, supportedProvider, txDefaults); + /** + * Subscribe to an event type emitted by the AssetProxyOwner contract. + * @param eventName The AssetProxyOwner contract event you would like to subscribe to. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` + * @param callback Callback that gets called when a log is added/removed + * @param isVerbose Enable verbose subscription warnings (e.g recoverable network issues encountered) + * @return Subscription token used later to unsubscribe + */ + public subscribe( + eventName: AssetProxyOwnerEvents, + indexFilterValues: IndexedFilterValues, + callback: EventCallback, + isVerbose: boolean = false, + blockPollingIntervalMs?: number, + ): string { + assert.doesBelongToStringEnum('eventName', eventName, AssetProxyOwnerEvents); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + assert.isFunction('callback', callback); + const subscriptionToken = this._subscriptionManager.subscribe( + this.address, + eventName, + indexFilterValues, + AssetProxyOwnerContract.ABI(), + callback, + isVerbose, + blockPollingIntervalMs, + ); + return subscriptionToken; + } + /** + * Cancel a subscription + * @param subscriptionToken Subscription token returned by `subscribe()` + */ + public unsubscribe(subscriptionToken: string): void { + this._subscriptionManager.unsubscribe(subscriptionToken); + } + /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + this._subscriptionManager.unsubscribeAll(); + } + /** + * Gets historical logs without creating a subscription + * @param eventName The AssetProxyOwner contract event you would like to subscribe to. + * @param blockRange Block range to get logs from. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` + * @return Array of logs that match the parameters + */ + public async getLogsAsync( + eventName: AssetProxyOwnerEvents, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, + ): Promise>> { + assert.doesBelongToStringEnum('eventName', eventName, AssetProxyOwnerEvents); + assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + const logs = await this._subscriptionManager.getLogsAsync( + this.address, + eventName, + blockRange, + indexFilterValues, + AssetProxyOwnerContract.ABI(), + ); + return logs; + } + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super( + 'AssetProxyOwner', + AssetProxyOwnerContract.ABI(), + address, + supportedProvider, + txDefaults, + logDecodeDependencies, + ); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); + this._subscriptionManager = new SubscriptionManager( + AssetProxyOwnerContract.ABI(), + this._web3Wrapper, + ); } } diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/coordinator.ts b/packages/abi-gen-wrappers/src/generated-wrappers/coordinator.ts index 8039570667..2a9e278685 100644 --- a/packages/abi-gen-wrappers/src/generated-wrappers/coordinator.ts +++ b/packages/abi-gen-wrappers/src/generated-wrappers/coordinator.ts @@ -27,7 +27,17 @@ import * as ethers from 'ethers'; // tslint:disable:no-parameter-reassignment // tslint:disable-next-line:class-name export class CoordinatorContract extends BaseContract { + /** + * Recovers the address of a signer given a hash and signature. + */ public getSignerAddress = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param hash Any 32 byte hash. + * @param signature Proof that the hash has been signed by signer. + */ async callAsync( hash: string, signature: string, @@ -71,6 +81,13 @@ export class CoordinatorContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param hash Any 32 byte hash. + * @param signature Proof that the hash has been signed by signer. + */ getABIEncodedTransactionData(hash: string, signature: string): string { assert.isString('hash', hash); assert.isString('signature', signature); @@ -81,8 +98,32 @@ export class CoordinatorContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as CoordinatorContract; + const abiEncoder = self._lookupAbiEncoder('getSignerAddress(bytes32,bytes)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as CoordinatorContract; + const abiEncoder = self._lookupAbiEncoder('getSignerAddress(bytes32,bytes)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Calculates the EIP712 hash of a 0x transaction using the domain separator of the Exchange contract. + */ public getTransactionHash = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param transaction 0x transaction containing salt, signerAddress, and data. + * @returns EIP712 hash of the transaction with the domain separator of this contract. + */ async callAsync( transaction: { salt: BigNumber; signerAddress: string; data: string }, callData: Partial = {}, @@ -125,6 +166,12 @@ export class CoordinatorContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param transaction 0x transaction containing salt, signerAddress, and data. + */ getABIEncodedTransactionData(transaction: { salt: BigNumber; signerAddress: string; data: string }): string { const self = (this as any) as CoordinatorContract; const abiEncodedTransactionData = self._strictEncodeArguments( @@ -133,8 +180,33 @@ export class CoordinatorContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as CoordinatorContract; + const abiEncoder = self._lookupAbiEncoder('getTransactionHash((uint256,address,bytes))'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as CoordinatorContract; + const abiEncoder = self._lookupAbiEncoder('getTransactionHash((uint256,address,bytes))'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Calculated the EIP712 hash of the Coordinator approval mesasage using the domain separator of this contract. + */ public getCoordinatorApprovalHash = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param approval Coordinator approval message containing the transaction + * hash, transaction signature, and expiration of the approval. + * @returns EIP712 hash of the Coordinator approval message with the domain separator of this contract. + */ async callAsync( approval: { txOrigin: string; @@ -183,6 +255,13 @@ export class CoordinatorContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param approval Coordinator approval message containing the transaction + * hash, transaction signature, and expiration of the approval. + */ getABIEncodedTransactionData(approval: { txOrigin: string; transactionHash: string; @@ -196,8 +275,40 @@ export class CoordinatorContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as CoordinatorContract; + const abiEncoder = self._lookupAbiEncoder('getCoordinatorApprovalHash((address,bytes32,bytes,uint256))'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as CoordinatorContract; + const abiEncoder = self._lookupAbiEncoder('getCoordinatorApprovalHash((address,bytes32,bytes,uint256))'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Executes a 0x transaction that has been signed by the feeRecipients that correspond to each order in the transaction's Exchange calldata. + */ public executeTransaction = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param transaction 0x transaction containing salt, signerAddress, and data. + * @param txOrigin Required signer of Ethereum transaction calling this + * function. + * @param transactionSignature Proof that the transaction has been signed by + * the signer. + * @param approvalExpirationTimeSeconds Array of expiration times in seconds + * for which each corresponding approval signature expires. + * @param approvalSignatures Array of signatures that correspond to the + * feeRecipients of each order in the transaction's Exchange calldata. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( transaction: { salt: BigNumber; signerAddress: string; data: string }, txOrigin: string, @@ -240,6 +351,22 @@ export class CoordinatorContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param transaction 0x transaction containing salt, signerAddress, and data. + * @param txOrigin Required signer of Ethereum transaction calling this + * function. + * @param transactionSignature Proof that the transaction has been signed by + * the signer. + * @param approvalExpirationTimeSeconds Array of expiration times in seconds + * for which each corresponding approval signature expires. + * @param approvalSignatures Array of signatures that correspond to the + * feeRecipients of each order in the transaction's Exchange calldata. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( transaction: { salt: BigNumber; signerAddress: string; data: string }, txOrigin: string, @@ -275,6 +402,20 @@ export class CoordinatorContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param transaction 0x transaction containing salt, signerAddress, and data. + * @param txOrigin Required signer of Ethereum transaction calling this + * function. + * @param transactionSignature Proof that the transaction has been signed by + * the signer. + * @param approvalExpirationTimeSeconds Array of expiration times in seconds + * for which each corresponding approval signature expires. + * @param approvalSignatures Array of signatures that correspond to the + * feeRecipients of each order in the transaction's Exchange calldata. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( transaction: { salt: BigNumber; signerAddress: string; data: string }, txOrigin: string, @@ -309,6 +450,20 @@ export class CoordinatorContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param transaction 0x transaction containing salt, signerAddress, and data. + * @param txOrigin Required signer of Ethereum transaction calling this + * function. + * @param transactionSignature Proof that the transaction has been signed by + * the signer. + * @param approvalExpirationTimeSeconds Array of expiration times in seconds + * for which each corresponding approval signature expires. + * @param approvalSignatures Array of signatures that correspond to the + * feeRecipients of each order in the transaction's Exchange calldata. + */ async callAsync( transaction: { salt: BigNumber; signerAddress: string; data: string }, txOrigin: string, @@ -368,6 +523,20 @@ export class CoordinatorContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param transaction 0x transaction containing salt, signerAddress, and data. + * @param txOrigin Required signer of Ethereum transaction calling this + * function. + * @param transactionSignature Proof that the transaction has been signed by + * the signer. + * @param approvalExpirationTimeSeconds Array of expiration times in seconds + * for which each corresponding approval signature expires. + * @param approvalSignatures Array of signatures that correspond to the + * feeRecipients of each order in the transaction's Exchange calldata. + */ getABIEncodedTransactionData( transaction: { salt: BigNumber; signerAddress: string; data: string }, txOrigin: string, @@ -392,8 +561,57 @@ export class CoordinatorContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as CoordinatorContract; + const abiEncoder = self._lookupAbiEncoder( + 'executeTransaction((uint256,address,bytes),address,bytes,uint256[],bytes[])', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as CoordinatorContract; + const abiEncoder = self._lookupAbiEncoder( + 'executeTransaction((uint256,address,bytes),address,bytes,uint256[],bytes[])', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + transaction: { salt: BigNumber; signerAddress: string; data: string }, + txOrigin: string, + transactionSignature: string, + approvalExpirationTimeSeconds: BigNumber[], + approvalSignatures: string[], + txData?: Partial | undefined, + ): Promise { + await (this as any).executeTransaction.callAsync( + transaction, + txOrigin, + transactionSignature, + approvalExpirationTimeSeconds, + approvalSignatures, + txData, + ); + const txHash = await (this as any).executeTransaction.sendTransactionAsync( + transaction, + txOrigin, + transactionSignature, + approvalExpirationTimeSeconds, + approvalSignatures, + txData, + ); + return txHash; + }, }; public EIP712_EXCHANGE_DOMAIN_HASH = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -430,13 +648,50 @@ export class CoordinatorContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as CoordinatorContract; const abiEncodedTransactionData = self._strictEncodeArguments('EIP712_EXCHANGE_DOMAIN_HASH()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as CoordinatorContract; + const abiEncoder = self._lookupAbiEncoder('EIP712_EXCHANGE_DOMAIN_HASH()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as CoordinatorContract; + const abiEncoder = self._lookupAbiEncoder('EIP712_EXCHANGE_DOMAIN_HASH()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Validates that the 0x transaction has been approved by all of the feeRecipients + * that correspond to each order in the transaction's Exchange calldata. + */ public assertValidCoordinatorApprovals = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param transaction 0x transaction containing salt, signerAddress, and data. + * @param txOrigin Required signer of Ethereum transaction calling this + * function. + * @param transactionSignature Proof that the transaction has been signed by + * the signer. + * @param approvalExpirationTimeSeconds Array of expiration times in seconds + * for which each corresponding approval signature expires. + * @param approvalSignatures Array of signatures that correspond to the + * feeRecipients of each order in the transaction's Exchange calldata. + */ async callAsync( transaction: { salt: BigNumber; signerAddress: string; data: string }, txOrigin: string, @@ -496,6 +751,20 @@ export class CoordinatorContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param transaction 0x transaction containing salt, signerAddress, and data. + * @param txOrigin Required signer of Ethereum transaction calling this + * function. + * @param transactionSignature Proof that the transaction has been signed by + * the signer. + * @param approvalExpirationTimeSeconds Array of expiration times in seconds + * for which each corresponding approval signature expires. + * @param approvalSignatures Array of signatures that correspond to the + * feeRecipients of each order in the transaction's Exchange calldata. + */ getABIEncodedTransactionData( transaction: { salt: BigNumber; signerAddress: string; data: string }, txOrigin: string, @@ -520,8 +789,36 @@ export class CoordinatorContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as CoordinatorContract; + const abiEncoder = self._lookupAbiEncoder( + 'assertValidCoordinatorApprovals((uint256,address,bytes),address,bytes,uint256[],bytes[])', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as CoordinatorContract; + const abiEncoder = self._lookupAbiEncoder( + 'assertValidCoordinatorApprovals((uint256,address,bytes),address,bytes,uint256[],bytes[])', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Decodes the orders from Exchange calldata representing any fill method. + */ public decodeOrdersFromFillData = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param data Exchange calldata representing a fill method. + * @returns The orders from the Exchange calldata. + */ async callAsync( data: string, callData: Partial = {}, @@ -593,14 +890,99 @@ export class CoordinatorContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param data Exchange calldata representing a fill method. + */ getABIEncodedTransactionData(data: string): string { assert.isString('data', data); const self = (this as any) as CoordinatorContract; const abiEncodedTransactionData = self._strictEncodeArguments('decodeOrdersFromFillData(bytes)', [data]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): Array<{ + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }> { + const self = (this as any) as CoordinatorContract; + const abiEncoder = self._lookupAbiEncoder('decodeOrdersFromFillData(bytes)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode< + Array<{ + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }> + >(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): Array<{ + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }> { + const self = (this as any) as CoordinatorContract; + const abiEncoder = self._lookupAbiEncoder('decodeOrdersFromFillData(bytes)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue< + Array<{ + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }> + >(returnData); + return abiDecodedReturnData; + }, }; public EIP712_COORDINATOR_DOMAIN_HASH = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -637,16 +1019,36 @@ export class CoordinatorContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as CoordinatorContract; const abiEncodedTransactionData = self._strictEncodeArguments('EIP712_COORDINATOR_DOMAIN_HASH()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as CoordinatorContract; + const abiEncoder = self._lookupAbiEncoder('EIP712_COORDINATOR_DOMAIN_HASH()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as CoordinatorContract; + const abiEncoder = self._lookupAbiEncoder('EIP712_COORDINATOR_DOMAIN_HASH()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, _exchange: string, ): Promise { assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ @@ -660,13 +1062,27 @@ export class CoordinatorContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; - return CoordinatorContract.deployAsync(bytecode, abi, provider, txDefaults, _exchange); + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return CoordinatorContract.deployAsync( + bytecode, + abi, + provider, + txDefaults, + logDecodeDependenciesAbiOnly, + _exchange, + ); } public static async deployAsync( bytecode: string, abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, _exchange: string, ): Promise { assert.isHexString('bytecode', bytecode); @@ -695,7 +1111,12 @@ export class CoordinatorContract extends BaseContract { logUtils.log(`transactionHash: ${txHash}`); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); logUtils.log(`Coordinator successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new CoordinatorContract(txReceipt.contractAddress as string, provider, txDefaults); + const contractInstance = new CoordinatorContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); contractInstance.constructorArgs = [_exchange]; return contractInstance; } @@ -998,8 +1419,13 @@ export class CoordinatorContract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('Coordinator', CoordinatorContract.ABI(), address, supportedProvider, txDefaults); + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super('Coordinator', CoordinatorContract.ABI(), address, supportedProvider, txDefaults, logDecodeDependencies); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); } } diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/coordinator_registry.ts b/packages/abi-gen-wrappers/src/generated-wrappers/coordinator_registry.ts index 3beac00652..e4ececcc5d 100644 --- a/packages/abi-gen-wrappers/src/generated-wrappers/coordinator_registry.ts +++ b/packages/abi-gen-wrappers/src/generated-wrappers/coordinator_registry.ts @@ -1,7 +1,14 @@ // tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma // tslint:disable:whitespace no-unbound-method no-trailing-whitespace // tslint:disable:no-unused-variable -import { BaseContract, PromiseWithTransactionHash } from '@0x/base-contract'; +import { + BaseContract, + BlockRange, + EventCallback, + IndexedFilterValues, + SubscriptionManager, + PromiseWithTransactionHash, +} from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { BlockParam, @@ -10,6 +17,7 @@ import { ContractAbi, ContractArtifact, DecodedLogArgs, + LogWithDecodedArgs, MethodAbi, TransactionReceiptWithDecodedLogs, TxData, @@ -38,7 +46,17 @@ export interface CoordinatorRegistryCoordinatorEndpointSetEventArgs extends Deco // tslint:disable:no-parameter-reassignment // tslint:disable-next-line:class-name export class CoordinatorRegistryContract extends BaseContract { + /** + * Called by a Coordinator operator to set the endpoint of their Coordinator. + */ public setCoordinatorEndpoint = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param coordinatorEndpoint endpoint of the Coordinator. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(coordinatorEndpoint: string, txData?: Partial | undefined): Promise { const self = (this as any) as CoordinatorRegistryContract; const encodedData = self._strictEncodeArguments('setCoordinatorEndpoint(string)', [coordinatorEndpoint]); @@ -64,6 +82,14 @@ export class CoordinatorRegistryContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param coordinatorEndpoint endpoint of the Coordinator. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( coordinatorEndpoint: string, txData?: Partial, @@ -85,6 +111,12 @@ export class CoordinatorRegistryContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param coordinatorEndpoint endpoint of the Coordinator. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(coordinatorEndpoint: string, txData?: Partial | undefined): Promise { const self = (this as any) as CoordinatorRegistryContract; const encodedData = self._strictEncodeArguments('setCoordinatorEndpoint(string)', [coordinatorEndpoint]); @@ -109,6 +141,12 @@ export class CoordinatorRegistryContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param coordinatorEndpoint endpoint of the Coordinator. + */ async callAsync( coordinatorEndpoint: string, callData: Partial = {}, @@ -150,6 +188,12 @@ export class CoordinatorRegistryContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param coordinatorEndpoint endpoint of the Coordinator. + */ getABIEncodedTransactionData(coordinatorEndpoint: string): string { assert.isString('coordinatorEndpoint', coordinatorEndpoint); const self = (this as any) as CoordinatorRegistryContract; @@ -158,8 +202,39 @@ export class CoordinatorRegistryContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as CoordinatorRegistryContract; + const abiEncoder = self._lookupAbiEncoder('setCoordinatorEndpoint(string)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as CoordinatorRegistryContract; + const abiEncoder = self._lookupAbiEncoder('setCoordinatorEndpoint(string)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + coordinatorEndpoint: string, + txData?: Partial | undefined, + ): Promise { + await (this as any).setCoordinatorEndpoint.callAsync(coordinatorEndpoint, txData); + const txHash = await (this as any).setCoordinatorEndpoint.sendTransactionAsync(coordinatorEndpoint, txData); + return txHash; + }, }; + /** + * Gets the endpoint for a Coordinator. + */ public getCoordinatorEndpoint = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param coordinatorOperator operator of the Coordinator endpoint. + */ async callAsync( coordinatorOperator: string, callData: Partial = {}, @@ -203,6 +278,12 @@ export class CoordinatorRegistryContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param coordinatorOperator operator of the Coordinator endpoint. + */ getABIEncodedTransactionData(coordinatorOperator: string): string { assert.isString('coordinatorOperator', coordinatorOperator); const self = (this as any) as CoordinatorRegistryContract; @@ -211,11 +292,27 @@ export class CoordinatorRegistryContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as CoordinatorRegistryContract; + const abiEncoder = self._lookupAbiEncoder('getCoordinatorEndpoint(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as CoordinatorRegistryContract; + const abiEncoder = self._lookupAbiEncoder('getCoordinatorEndpoint(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + private readonly _subscriptionManager: SubscriptionManager; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, ): Promise { assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ schemas.addressSchema, @@ -228,13 +325,26 @@ export class CoordinatorRegistryContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; - return CoordinatorRegistryContract.deployAsync(bytecode, abi, provider, txDefaults); + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return CoordinatorRegistryContract.deployAsync( + bytecode, + abi, + provider, + txDefaults, + logDecodeDependenciesAbiOnly, + ); } public static async deployAsync( bytecode: string, abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, ): Promise { assert.isHexString('bytecode', bytecode); assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ @@ -262,6 +372,7 @@ export class CoordinatorRegistryContract extends BaseContract { txReceipt.contractAddress as string, provider, txDefaults, + logDecodeDependencies, ); contractInstance.constructorArgs = []; return contractInstance; @@ -333,9 +444,93 @@ export class CoordinatorRegistryContract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('CoordinatorRegistry', CoordinatorRegistryContract.ABI(), address, supportedProvider, txDefaults); + /** + * Subscribe to an event type emitted by the CoordinatorRegistry contract. + * @param eventName The CoordinatorRegistry contract event you would like to subscribe to. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` + * @param callback Callback that gets called when a log is added/removed + * @param isVerbose Enable verbose subscription warnings (e.g recoverable network issues encountered) + * @return Subscription token used later to unsubscribe + */ + public subscribe( + eventName: CoordinatorRegistryEvents, + indexFilterValues: IndexedFilterValues, + callback: EventCallback, + isVerbose: boolean = false, + blockPollingIntervalMs?: number, + ): string { + assert.doesBelongToStringEnum('eventName', eventName, CoordinatorRegistryEvents); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + assert.isFunction('callback', callback); + const subscriptionToken = this._subscriptionManager.subscribe( + this.address, + eventName, + indexFilterValues, + CoordinatorRegistryContract.ABI(), + callback, + isVerbose, + blockPollingIntervalMs, + ); + return subscriptionToken; + } + /** + * Cancel a subscription + * @param subscriptionToken Subscription token returned by `subscribe()` + */ + public unsubscribe(subscriptionToken: string): void { + this._subscriptionManager.unsubscribe(subscriptionToken); + } + /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + this._subscriptionManager.unsubscribeAll(); + } + /** + * Gets historical logs without creating a subscription + * @param eventName The CoordinatorRegistry contract event you would like to subscribe to. + * @param blockRange Block range to get logs from. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` + * @return Array of logs that match the parameters + */ + public async getLogsAsync( + eventName: CoordinatorRegistryEvents, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, + ): Promise>> { + assert.doesBelongToStringEnum('eventName', eventName, CoordinatorRegistryEvents); + assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + const logs = await this._subscriptionManager.getLogsAsync( + this.address, + eventName, + blockRange, + indexFilterValues, + CoordinatorRegistryContract.ABI(), + ); + return logs; + } + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super( + 'CoordinatorRegistry', + CoordinatorRegistryContract.ABI(), + address, + supportedProvider, + txDefaults, + logDecodeDependencies, + ); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); + this._subscriptionManager = new SubscriptionManager( + CoordinatorRegistryContract.ABI(), + this._web3Wrapper, + ); } } diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/dummy_erc20_token.ts b/packages/abi-gen-wrappers/src/generated-wrappers/dummy_erc20_token.ts index 7e8446a127..9bb53267bb 100644 --- a/packages/abi-gen-wrappers/src/generated-wrappers/dummy_erc20_token.ts +++ b/packages/abi-gen-wrappers/src/generated-wrappers/dummy_erc20_token.ts @@ -1,7 +1,14 @@ // tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma // tslint:disable:whitespace no-unbound-method no-trailing-whitespace // tslint:disable:no-unused-variable -import { BaseContract, PromiseWithTransactionHash } from '@0x/base-contract'; +import { + BaseContract, + BlockRange, + EventCallback, + IndexedFilterValues, + SubscriptionManager, + PromiseWithTransactionHash, +} from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { BlockParam, @@ -10,6 +17,7 @@ import { ContractAbi, ContractArtifact, DecodedLogArgs, + LogWithDecodedArgs, MethodAbi, TransactionReceiptWithDecodedLogs, TxData, @@ -47,6 +55,11 @@ export interface DummyERC20TokenApprovalEventArgs extends DecodedLogArgs { // tslint:disable-next-line:class-name export class DummyERC20TokenContract extends BaseContract { public name = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -83,13 +96,43 @@ export class DummyERC20TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as DummyERC20TokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('name()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('name()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('name()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * `msg.sender` approves `_spender` to spend `_value` tokens + */ public approve = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _spender The address of the account able to transfer the tokens + * @param _value The amount of wei to be approved for transfer + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _spender: string, _value: BigNumber, @@ -119,6 +162,15 @@ export class DummyERC20TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _spender The address of the account able to transfer the tokens + * @param _value The amount of wei to be approved for transfer + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _spender: string, _value: BigNumber, @@ -142,6 +194,13 @@ export class DummyERC20TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _spender The address of the account able to transfer the tokens + * @param _value The amount of wei to be approved for transfer + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( _spender: string, _value: BigNumber, @@ -170,6 +229,14 @@ export class DummyERC20TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _spender The address of the account able to transfer the tokens + * @param _value The amount of wei to be approved for transfer + * @returns Always true if the call has enough gas to complete execution + */ async callAsync( _spender: string, _value: BigNumber, @@ -216,6 +283,13 @@ export class DummyERC20TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _spender The address of the account able to transfer the tokens + * @param _value The amount of wei to be approved for transfer + */ getABIEncodedTransactionData(_spender: string, _value: BigNumber): string { assert.isString('_spender', _spender); assert.isBigNumber('_value', _value); @@ -226,8 +300,40 @@ export class DummyERC20TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('approve(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('approve(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _spender: string, + _value: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).approve.callAsync(_spender, _value, txData); + const txHash = await (this as any).approve.sendTransactionAsync(_spender, _value, txData); + return txHash; + }, }; + /** + * Query total supply of token + */ public totalSupply = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @returns Total supply of token + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -264,13 +370,44 @@ export class DummyERC20TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as DummyERC20TokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('totalSupply()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('totalSupply()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('totalSupply()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance. See https://github.com/ethereum/EIPs/issues/717 + */ public transferFrom = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _from Address to transfer from. + * @param _to Address to transfer to. + * @param _value Amount to transfer. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _from: string, _to: string, @@ -305,6 +442,16 @@ export class DummyERC20TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _from Address to transfer from. + * @param _to Address to transfer to. + * @param _value Amount to transfer. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _from: string, _to: string, @@ -335,6 +482,14 @@ export class DummyERC20TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _from Address to transfer from. + * @param _to Address to transfer to. + * @param _value Amount to transfer. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( _from: string, _to: string, @@ -368,6 +523,15 @@ export class DummyERC20TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _from Address to transfer from. + * @param _to Address to transfer to. + * @param _value Amount to transfer. + * @returns Success of transfer. + */ async callAsync( _from: string, _to: string, @@ -417,6 +581,14 @@ export class DummyERC20TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _from Address to transfer from. + * @param _to Address to transfer to. + * @param _value Amount to transfer. + */ getABIEncodedTransactionData(_from: string, _to: string, _value: BigNumber): string { assert.isString('_from', _from); assert.isString('_to', _to); @@ -429,8 +601,37 @@ export class DummyERC20TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('transferFrom(address,address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('transferFrom(address,address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _from: string, + _to: string, + _value: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).transferFrom.callAsync(_from, _to, _value, txData); + const txHash = await (this as any).transferFrom.sendTransactionAsync(_from, _to, _value, txData); + return txHash; + }, }; public decimals = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -467,13 +668,42 @@ export class DummyERC20TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as DummyERC20TokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('decimals()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('decimals()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('decimals()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Query the balance of owner + */ public balanceOf = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _owner The address from which the balance will be retrieved + * @returns Balance of owner + */ async callAsync( _owner: string, callData: Partial = {}, @@ -515,14 +745,39 @@ export class DummyERC20TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _owner The address from which the balance will be retrieved + */ getABIEncodedTransactionData(_owner: string): string { assert.isString('_owner', _owner); const self = (this as any) as DummyERC20TokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('balanceOf(address)', [_owner.toLowerCase()]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('balanceOf(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('balanceOf(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public owner = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -559,13 +814,37 @@ export class DummyERC20TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as DummyERC20TokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('owner()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('owner()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('owner()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public symbol = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -602,13 +881,42 @@ export class DummyERC20TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as DummyERC20TokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('symbol()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('symbol()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('symbol()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Mints new tokens for sender + */ public mint = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _value Amount of tokens to mint + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(_value: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as DummyERC20TokenContract; const encodedData = self._strictEncodeArguments('mint(uint256)', [_value]); @@ -634,6 +942,14 @@ export class DummyERC20TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _value Amount of tokens to mint + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _value: BigNumber, txData?: Partial, @@ -655,6 +971,12 @@ export class DummyERC20TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _value Amount of tokens to mint + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(_value: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as DummyERC20TokenContract; const encodedData = self._strictEncodeArguments('mint(uint256)', [_value]); @@ -679,6 +1001,12 @@ export class DummyERC20TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _value Amount of tokens to mint + */ async callAsync(_value: BigNumber, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isBigNumber('_value', _value); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -716,14 +1044,53 @@ export class DummyERC20TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _value Amount of tokens to mint + */ getABIEncodedTransactionData(_value: BigNumber): string { assert.isBigNumber('_value', _value); const self = (this as any) as DummyERC20TokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('mint(uint256)', [_value]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('mint(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('mint(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _value: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).mint.callAsync(_value, txData); + const txHash = await (this as any).mint.sendTransactionAsync(_value, txData); + return txHash; + }, }; + /** + * send `value` token to `to` from `msg.sender` + */ public transfer = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _to The address of the recipient + * @param _value The amount of token to be transferred + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _to: string, _value: BigNumber, @@ -753,6 +1120,15 @@ export class DummyERC20TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _to The address of the recipient + * @param _value The amount of token to be transferred + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _to: string, _value: BigNumber, @@ -776,6 +1152,13 @@ export class DummyERC20TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _to The address of the recipient + * @param _value The amount of token to be transferred + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(_to: string, _value: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as DummyERC20TokenContract; const encodedData = self._strictEncodeArguments('transfer(address,uint256)', [_to, _value]); @@ -800,6 +1183,14 @@ export class DummyERC20TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _to The address of the recipient + * @param _value The amount of token to be transferred + * @returns True if transfer was successful + */ async callAsync( _to: string, _value: BigNumber, @@ -843,6 +1234,13 @@ export class DummyERC20TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _to The address of the recipient + * @param _value The amount of token to be transferred + */ getABIEncodedTransactionData(_to: string, _value: BigNumber): string { assert.isString('_to', _to); assert.isBigNumber('_value', _value); @@ -853,8 +1251,39 @@ export class DummyERC20TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('transfer(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('transfer(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _to: string, + _value: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).transfer.callAsync(_to, _value, txData); + const txHash = await (this as any).transfer.sendTransactionAsync(_to, _value, txData); + return txHash; + }, }; public allowance = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _owner The address of the account owning tokens + * @param _spender The address of the account able to transfer the tokens + * @returns Amount of remaining tokens allowed to spent + */ async callAsync( _owner: string, _spender: string, @@ -901,6 +1330,13 @@ export class DummyERC20TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _owner The address of the account owning tokens + * @param _spender The address of the account able to transfer the tokens + */ getABIEncodedTransactionData(_owner: string, _spender: string): string { assert.isString('_owner', _owner); assert.isString('_spender', _spender); @@ -911,8 +1347,33 @@ export class DummyERC20TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('allowance(address,address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('allowance(address,address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Sets the balance of target address + */ public setBalance = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _target Address or which balance will be updated + * @param _value New balance of target address + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _target: string, _value: BigNumber, @@ -942,6 +1403,15 @@ export class DummyERC20TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _target Address or which balance will be updated + * @param _value New balance of target address + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _target: string, _value: BigNumber, @@ -965,6 +1435,13 @@ export class DummyERC20TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _target Address or which balance will be updated + * @param _value New balance of target address + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( _target: string, _value: BigNumber, @@ -993,6 +1470,13 @@ export class DummyERC20TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _target Address or which balance will be updated + * @param _value New balance of target address + */ async callAsync( _target: string, _value: BigNumber, @@ -1039,6 +1523,13 @@ export class DummyERC20TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _target Address or which balance will be updated + * @param _value New balance of target address + */ getABIEncodedTransactionData(_target: string, _value: BigNumber): string { assert.isString('_target', _target); assert.isBigNumber('_value', _value); @@ -1049,8 +1540,37 @@ export class DummyERC20TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('setBalance(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('setBalance(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _target: string, + _value: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).setBalance.callAsync(_target, _value, txData); + const txHash = await (this as any).setBalance.sendTransactionAsync(_target, _value, txData); + return txHash; + }, }; public transferOwnership = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(newOwner: string, txData?: Partial | undefined): Promise { const self = (this as any) as DummyERC20TokenContract; const encodedData = self._strictEncodeArguments('transferOwnership(address)', [newOwner]); @@ -1076,6 +1596,13 @@ export class DummyERC20TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( newOwner: string, txData?: Partial, @@ -1097,6 +1624,11 @@ export class DummyERC20TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(newOwner: string, txData?: Partial | undefined): Promise { const self = (this as any) as DummyERC20TokenContract; const encodedData = self._strictEncodeArguments('transferOwnership(address)', [newOwner]); @@ -1121,6 +1653,11 @@ export class DummyERC20TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(newOwner: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isString('newOwner', newOwner); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -1158,6 +1695,11 @@ export class DummyERC20TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(newOwner: string): string { assert.isString('newOwner', newOwner); const self = (this as any) as DummyERC20TokenContract; @@ -1166,8 +1708,32 @@ export class DummyERC20TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('transferOwnership(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('transferOwnership(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(newOwner: string, txData?: Partial | undefined): Promise { + await (this as any).transferOwnership.callAsync(newOwner, txData); + const txHash = await (this as any).transferOwnership.sendTransactionAsync(newOwner, txData); + return txHash; + }, }; public MAX_MINT_AMOUNT = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -1204,16 +1770,37 @@ export class DummyERC20TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as DummyERC20TokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('MAX_MINT_AMOUNT()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('MAX_MINT_AMOUNT()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as DummyERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('MAX_MINT_AMOUNT()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + private readonly _subscriptionManager: SubscriptionManager; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, _name: string, _symbol: string, _decimals: BigNumber, @@ -1230,11 +1817,18 @@ export class DummyERC20TokenContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } return DummyERC20TokenContract.deployAsync( bytecode, abi, provider, txDefaults, + logDecodeDependenciesAbiOnly, _name, _symbol, _decimals, @@ -1246,6 +1840,7 @@ export class DummyERC20TokenContract extends BaseContract { abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, _name: string, _symbol: string, _decimals: BigNumber, @@ -1277,7 +1872,12 @@ export class DummyERC20TokenContract extends BaseContract { logUtils.log(`transactionHash: ${txHash}`); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); logUtils.log(`DummyERC20Token successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new DummyERC20TokenContract(txReceipt.contractAddress as string, provider, txDefaults); + const contractInstance = new DummyERC20TokenContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); contractInstance.constructorArgs = [_name, _symbol, _decimals, _totalSupply]; return contractInstance; } @@ -1605,9 +2205,93 @@ export class DummyERC20TokenContract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('DummyERC20Token', DummyERC20TokenContract.ABI(), address, supportedProvider, txDefaults); + /** + * Subscribe to an event type emitted by the DummyERC20Token contract. + * @param eventName The DummyERC20Token contract event you would like to subscribe to. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` + * @param callback Callback that gets called when a log is added/removed + * @param isVerbose Enable verbose subscription warnings (e.g recoverable network issues encountered) + * @return Subscription token used later to unsubscribe + */ + public subscribe( + eventName: DummyERC20TokenEvents, + indexFilterValues: IndexedFilterValues, + callback: EventCallback, + isVerbose: boolean = false, + blockPollingIntervalMs?: number, + ): string { + assert.doesBelongToStringEnum('eventName', eventName, DummyERC20TokenEvents); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + assert.isFunction('callback', callback); + const subscriptionToken = this._subscriptionManager.subscribe( + this.address, + eventName, + indexFilterValues, + DummyERC20TokenContract.ABI(), + callback, + isVerbose, + blockPollingIntervalMs, + ); + return subscriptionToken; + } + /** + * Cancel a subscription + * @param subscriptionToken Subscription token returned by `subscribe()` + */ + public unsubscribe(subscriptionToken: string): void { + this._subscriptionManager.unsubscribe(subscriptionToken); + } + /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + this._subscriptionManager.unsubscribeAll(); + } + /** + * Gets historical logs without creating a subscription + * @param eventName The DummyERC20Token contract event you would like to subscribe to. + * @param blockRange Block range to get logs from. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` + * @return Array of logs that match the parameters + */ + public async getLogsAsync( + eventName: DummyERC20TokenEvents, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, + ): Promise>> { + assert.doesBelongToStringEnum('eventName', eventName, DummyERC20TokenEvents); + assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + const logs = await this._subscriptionManager.getLogsAsync( + this.address, + eventName, + blockRange, + indexFilterValues, + DummyERC20TokenContract.ABI(), + ); + return logs; + } + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super( + 'DummyERC20Token', + DummyERC20TokenContract.ABI(), + address, + supportedProvider, + txDefaults, + logDecodeDependencies, + ); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); + this._subscriptionManager = new SubscriptionManager( + DummyERC20TokenContract.ABI(), + this._web3Wrapper, + ); } } diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/dummy_erc721_token.ts b/packages/abi-gen-wrappers/src/generated-wrappers/dummy_erc721_token.ts index 1e33b24e7d..b2bd545d2f 100644 --- a/packages/abi-gen-wrappers/src/generated-wrappers/dummy_erc721_token.ts +++ b/packages/abi-gen-wrappers/src/generated-wrappers/dummy_erc721_token.ts @@ -1,7 +1,14 @@ // tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma // tslint:disable:whitespace no-unbound-method no-trailing-whitespace // tslint:disable:no-unused-variable -import { BaseContract, PromiseWithTransactionHash } from '@0x/base-contract'; +import { + BaseContract, + BlockRange, + EventCallback, + IndexedFilterValues, + SubscriptionManager, + PromiseWithTransactionHash, +} from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { BlockParam, @@ -10,6 +17,7 @@ import { ContractAbi, ContractArtifact, DecodedLogArgs, + LogWithDecodedArgs, MethodAbi, TransactionReceiptWithDecodedLogs, TxData, @@ -57,6 +65,11 @@ export interface DummyERC721TokenApprovalForAllEventArgs extends DecodedLogArgs // tslint:disable-next-line:class-name export class DummyERC721TokenContract extends BaseContract { public name = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -93,13 +106,42 @@ export class DummyERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as DummyERC721TokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('name()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('name()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('name()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Throws if `_tokenId` is not a valid NFT. + */ public getApproved = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _tokenId The NFT to find the approved address for + * @returns The approved address for this NFT, or the zero address if there is none + */ async callAsync( _tokenId: BigNumber, callData: Partial = {}, @@ -141,14 +183,47 @@ export class DummyERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _tokenId The NFT to find the approved address for + */ getABIEncodedTransactionData(_tokenId: BigNumber): string { assert.isBigNumber('_tokenId', _tokenId); const self = (this as any) as DummyERC721TokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('getApproved(uint256)', [_tokenId]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('getApproved(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('getApproved(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * The zero address indicates there is no approved address. + * Throws unless `msg.sender` is the current NFT owner, or an authorized + * operator of the current owner. + */ public approve = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _approved The new approved NFT controller + * @param _tokenId The NFT to approve + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _approved: string, _tokenId: BigNumber, @@ -178,6 +253,15 @@ export class DummyERC721TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _approved The new approved NFT controller + * @param _tokenId The NFT to approve + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _approved: string, _tokenId: BigNumber, @@ -201,6 +285,13 @@ export class DummyERC721TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _approved The new approved NFT controller + * @param _tokenId The NFT to approve + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( _approved: string, _tokenId: BigNumber, @@ -229,6 +320,13 @@ export class DummyERC721TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _approved The new approved NFT controller + * @param _tokenId The NFT to approve + */ async callAsync( _approved: string, _tokenId: BigNumber, @@ -275,6 +373,13 @@ export class DummyERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _approved The new approved NFT controller + * @param _tokenId The NFT to approve + */ getABIEncodedTransactionData(_approved: string, _tokenId: BigNumber): string { assert.isString('_approved', _approved); assert.isBigNumber('_tokenId', _tokenId); @@ -285,8 +390,46 @@ export class DummyERC721TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('approve(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('approve(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _approved: string, + _tokenId: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).approve.callAsync(_approved, _tokenId, txData); + const txHash = await (this as any).approve.sendTransactionAsync(_approved, _tokenId, txData); + return txHash; + }, }; + /** + * Throws unless `msg.sender` is the current owner, an authorized + * operator, or the approved address for this NFT. Throws if `_from` is + * not the current owner. Throws if `_to` is the zero address. Throws if + * `_tokenId` is not a valid NFT. + */ public transferFrom = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _from: string, _to: string, @@ -321,6 +464,16 @@ export class DummyERC721TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _from: string, _to: string, @@ -351,6 +504,14 @@ export class DummyERC721TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( _from: string, _to: string, @@ -384,6 +545,14 @@ export class DummyERC721TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + */ async callAsync( _from: string, _to: string, @@ -433,6 +602,14 @@ export class DummyERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + */ getABIEncodedTransactionData(_from: string, _to: string, _tokenId: BigNumber): string { assert.isString('_from', _from); assert.isString('_to', _to); @@ -445,8 +622,44 @@ export class DummyERC721TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('transferFrom(address,address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('transferFrom(address,address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _from: string, + _to: string, + _tokenId: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).transferFrom.callAsync(_from, _to, _tokenId, txData); + const txHash = await (this as any).transferFrom.sendTransactionAsync(_from, _to, _tokenId, txData); + return txHash; + }, }; + /** + * Function to mint a new token + * Reverts if the given token ID already exists + */ public mint = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _to Address of the beneficiary that will own the minted token + * @param _tokenId ID of the token to be minted by the msg.sender + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _to: string, _tokenId: BigNumber, @@ -476,6 +689,15 @@ export class DummyERC721TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _to Address of the beneficiary that will own the minted token + * @param _tokenId ID of the token to be minted by the msg.sender + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _to: string, _tokenId: BigNumber, @@ -499,6 +721,13 @@ export class DummyERC721TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _to Address of the beneficiary that will own the minted token + * @param _tokenId ID of the token to be minted by the msg.sender + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( _to: string, _tokenId: BigNumber, @@ -527,6 +756,13 @@ export class DummyERC721TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _to Address of the beneficiary that will own the minted token + * @param _tokenId ID of the token to be minted by the msg.sender + */ async callAsync( _to: string, _tokenId: BigNumber, @@ -570,6 +806,13 @@ export class DummyERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _to Address of the beneficiary that will own the minted token + * @param _tokenId ID of the token to be minted by the msg.sender + */ getABIEncodedTransactionData(_to: string, _tokenId: BigNumber): string { assert.isString('_to', _to); assert.isBigNumber('_tokenId', _tokenId); @@ -580,8 +823,44 @@ export class DummyERC721TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('mint(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('mint(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _to: string, + _tokenId: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).mint.callAsync(_to, _tokenId, txData); + const txHash = await (this as any).mint.sendTransactionAsync(_to, _tokenId, txData); + return txHash; + }, }; + /** + * This works identically to the other function with an extra data parameter, + * except this function just sets data to "". + */ public safeTransferFrom1 = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _from: string, _to: string, @@ -616,6 +895,16 @@ export class DummyERC721TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _from: string, _to: string, @@ -646,6 +935,14 @@ export class DummyERC721TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( _from: string, _to: string, @@ -679,6 +976,14 @@ export class DummyERC721TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + */ async callAsync( _from: string, _to: string, @@ -728,6 +1033,14 @@ export class DummyERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + */ getABIEncodedTransactionData(_from: string, _to: string, _tokenId: BigNumber): string { assert.isString('_from', _from); assert.isString('_to', _to); @@ -740,8 +1053,43 @@ export class DummyERC721TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('safeTransferFrom(address,address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('safeTransferFrom(address,address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _from: string, + _to: string, + _tokenId: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).safeTransferFrom1.callAsync(_from, _to, _tokenId, txData); + const txHash = await (this as any).safeTransferFrom1.sendTransactionAsync(_from, _to, _tokenId, txData); + return txHash; + }, }; + /** + * NFTs assigned to zero address are considered invalid, and queries + * about them do throw. + */ public ownerOf = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _tokenId The identifier for an NFT + * @returns The address of the owner of the NFT + */ async callAsync( _tokenId: BigNumber, callData: Partial = {}, @@ -783,14 +1131,45 @@ export class DummyERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _tokenId The identifier for an NFT + */ getABIEncodedTransactionData(_tokenId: BigNumber): string { assert.isBigNumber('_tokenId', _tokenId); const self = (this as any) as DummyERC721TokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('ownerOf(uint256)', [_tokenId]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('ownerOf(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('ownerOf(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * NFTs assigned to the zero address are considered invalid, and this + * function throws for queries about the zero address. + */ public balanceOf = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _owner An address for whom to query the balance + * @returns The number of NFTs owned by `_owner`, possibly zero + */ async callAsync( _owner: string, callData: Partial = {}, @@ -832,14 +1211,39 @@ export class DummyERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _owner An address for whom to query the balance + */ getABIEncodedTransactionData(_owner: string): string { assert.isString('_owner', _owner); const self = (this as any) as DummyERC721TokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('balanceOf(address)', [_owner.toLowerCase()]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('balanceOf(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('balanceOf(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public owner = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -876,13 +1280,37 @@ export class DummyERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as DummyERC721TokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('owner()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('owner()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('owner()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public symbol = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -919,13 +1347,44 @@ export class DummyERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as DummyERC721TokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('symbol()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('symbol()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('symbol()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Function to burn a token + * Reverts if the given token ID doesn't exist or not called by contract owner + */ public burn = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _owner Owner of token with given token ID + * @param _tokenId ID of the token to be burned by the msg.sender + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _owner: string, _tokenId: BigNumber, @@ -955,6 +1414,15 @@ export class DummyERC721TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _owner Owner of token with given token ID + * @param _tokenId ID of the token to be burned by the msg.sender + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _owner: string, _tokenId: BigNumber, @@ -978,6 +1446,13 @@ export class DummyERC721TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _owner Owner of token with given token ID + * @param _tokenId ID of the token to be burned by the msg.sender + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( _owner: string, _tokenId: BigNumber, @@ -1006,6 +1481,13 @@ export class DummyERC721TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _owner Owner of token with given token ID + * @param _tokenId ID of the token to be burned by the msg.sender + */ async callAsync( _owner: string, _tokenId: BigNumber, @@ -1049,6 +1531,13 @@ export class DummyERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _owner Owner of token with given token ID + * @param _tokenId ID of the token to be burned by the msg.sender + */ getABIEncodedTransactionData(_owner: string, _tokenId: BigNumber): string { assert.isString('_owner', _owner); assert.isBigNumber('_tokenId', _tokenId); @@ -1059,8 +1548,43 @@ export class DummyERC721TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('burn(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('burn(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _owner: string, + _tokenId: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).burn.callAsync(_owner, _tokenId, txData); + const txHash = await (this as any).burn.sendTransactionAsync(_owner, _tokenId, txData); + return txHash; + }, }; + /** + * Emits the ApprovalForAll event. The contract MUST allow + * multiple operators per owner. + */ public setApprovalForAll = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _operator Address to add to the set of authorized operators + * @param _approved True if the operator is approved, false to revoke approval + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _operator: string, _approved: boolean, @@ -1090,6 +1614,15 @@ export class DummyERC721TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _operator Address to add to the set of authorized operators + * @param _approved True if the operator is approved, false to revoke approval + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _operator: string, _approved: boolean, @@ -1117,6 +1650,13 @@ export class DummyERC721TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _operator Address to add to the set of authorized operators + * @param _approved True if the operator is approved, false to revoke approval + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( _operator: string, _approved: boolean, @@ -1145,6 +1685,13 @@ export class DummyERC721TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _operator Address to add to the set of authorized operators + * @param _approved True if the operator is approved, false to revoke approval + */ async callAsync( _operator: string, _approved: boolean, @@ -1191,6 +1738,13 @@ export class DummyERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _operator Address to add to the set of authorized operators + * @param _approved True if the operator is approved, false to revoke approval + */ getABIEncodedTransactionData(_operator: string, _approved: boolean): string { assert.isString('_operator', _operator); assert.isBoolean('_approved', _approved); @@ -1201,8 +1755,50 @@ export class DummyERC721TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('setApprovalForAll(address,bool)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('setApprovalForAll(address,bool)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _operator: string, + _approved: boolean, + txData?: Partial | undefined, + ): Promise { + await (this as any).setApprovalForAll.callAsync(_operator, _approved, txData); + const txHash = await (this as any).setApprovalForAll.sendTransactionAsync(_operator, _approved, txData); + return txHash; + }, }; + /** + * Throws unless `msg.sender` is the current owner, an authorized + * operator, or the approved address for this NFT. Throws if `_from` is + * not the current owner. Throws if `_to` is the zero address. Throws if + * `_tokenId` is not a valid NFT. When transfer is complete, this function + * checks if `_to` is a smart contract (code size > 0). If so, it calls + * `onERC721Received` on `_to` and throws if the return value is not + * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`. + */ public safeTransferFrom2 = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param _data Additional data with no specified format, sent in call to `_to` + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _from: string, _to: string, @@ -1239,6 +1835,17 @@ export class DummyERC721TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param _data Additional data with no specified format, sent in call to `_to` + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _from: string, _to: string, @@ -1272,6 +1879,15 @@ export class DummyERC721TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param _data Additional data with no specified format, sent in call to `_to` + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( _from: string, _to: string, @@ -1307,6 +1923,15 @@ export class DummyERC721TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param _data Additional data with no specified format, sent in call to `_to` + */ async callAsync( _from: string, _to: string, @@ -1359,6 +1984,15 @@ export class DummyERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param _data Additional data with no specified format, sent in call to `_to` + */ getABIEncodedTransactionData(_from: string, _to: string, _tokenId: BigNumber, _data: string): string { assert.isString('_from', _from); assert.isString('_to', _to); @@ -1371,8 +2005,47 @@ export class DummyERC721TokenContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('safeTransferFrom(address,address,uint256,bytes)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('safeTransferFrom(address,address,uint256,bytes)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _from: string, + _to: string, + _tokenId: BigNumber, + _data: string, + txData?: Partial | undefined, + ): Promise { + await (this as any).safeTransferFrom2.callAsync(_from, _to, _tokenId, _data, txData); + const txHash = await (this as any).safeTransferFrom2.sendTransactionAsync( + _from, + _to, + _tokenId, + _data, + txData, + ); + return txHash; + }, }; public isApprovedForAll = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _owner The address that owns the NFTs + * @param _operator The address that acts on behalf of the owner + * @returns True if `_operator` is an approved operator for `_owner`, false otherwise + */ async callAsync( _owner: string, _operator: string, @@ -1419,6 +2092,13 @@ export class DummyERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _owner The address that owns the NFTs + * @param _operator The address that acts on behalf of the owner + */ getABIEncodedTransactionData(_owner: string, _operator: string): string { assert.isString('_owner', _owner); assert.isString('_operator', _operator); @@ -1429,8 +2109,28 @@ export class DummyERC721TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('isApprovedForAll(address,address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('isApprovedForAll(address,address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public transferOwnership = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(newOwner: string, txData?: Partial | undefined): Promise { const self = (this as any) as DummyERC721TokenContract; const encodedData = self._strictEncodeArguments('transferOwnership(address)', [newOwner]); @@ -1456,6 +2156,13 @@ export class DummyERC721TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( newOwner: string, txData?: Partial, @@ -1477,6 +2184,11 @@ export class DummyERC721TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(newOwner: string, txData?: Partial | undefined): Promise { const self = (this as any) as DummyERC721TokenContract; const encodedData = self._strictEncodeArguments('transferOwnership(address)', [newOwner]); @@ -1501,6 +2213,11 @@ export class DummyERC721TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(newOwner: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isString('newOwner', newOwner); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -1538,6 +2255,11 @@ export class DummyERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(newOwner: string): string { assert.isString('newOwner', newOwner); const self = (this as any) as DummyERC721TokenContract; @@ -1546,11 +2268,32 @@ export class DummyERC721TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('transferOwnership(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as DummyERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('transferOwnership(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(newOwner: string, txData?: Partial | undefined): Promise { + await (this as any).transferOwnership.callAsync(newOwner, txData); + const txHash = await (this as any).transferOwnership.sendTransactionAsync(newOwner, txData); + return txHash; + }, }; + private readonly _subscriptionManager: SubscriptionManager; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, _name: string, _symbol: string, ): Promise { @@ -1565,13 +2308,28 @@ export class DummyERC721TokenContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; - return DummyERC721TokenContract.deployAsync(bytecode, abi, provider, txDefaults, _name, _symbol); + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return DummyERC721TokenContract.deployAsync( + bytecode, + abi, + provider, + txDefaults, + logDecodeDependenciesAbiOnly, + _name, + _symbol, + ); } public static async deployAsync( bytecode: string, abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, _name: string, _symbol: string, ): Promise { @@ -1605,6 +2363,7 @@ export class DummyERC721TokenContract extends BaseContract { txReceipt.contractAddress as string, provider, txDefaults, + logDecodeDependencies, ); contractInstance.constructorArgs = [_name, _symbol]; return contractInstance; @@ -1981,9 +2740,93 @@ export class DummyERC721TokenContract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('DummyERC721Token', DummyERC721TokenContract.ABI(), address, supportedProvider, txDefaults); + /** + * Subscribe to an event type emitted by the DummyERC721Token contract. + * @param eventName The DummyERC721Token contract event you would like to subscribe to. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` + * @param callback Callback that gets called when a log is added/removed + * @param isVerbose Enable verbose subscription warnings (e.g recoverable network issues encountered) + * @return Subscription token used later to unsubscribe + */ + public subscribe( + eventName: DummyERC721TokenEvents, + indexFilterValues: IndexedFilterValues, + callback: EventCallback, + isVerbose: boolean = false, + blockPollingIntervalMs?: number, + ): string { + assert.doesBelongToStringEnum('eventName', eventName, DummyERC721TokenEvents); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + assert.isFunction('callback', callback); + const subscriptionToken = this._subscriptionManager.subscribe( + this.address, + eventName, + indexFilterValues, + DummyERC721TokenContract.ABI(), + callback, + isVerbose, + blockPollingIntervalMs, + ); + return subscriptionToken; + } + /** + * Cancel a subscription + * @param subscriptionToken Subscription token returned by `subscribe()` + */ + public unsubscribe(subscriptionToken: string): void { + this._subscriptionManager.unsubscribe(subscriptionToken); + } + /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + this._subscriptionManager.unsubscribeAll(); + } + /** + * Gets historical logs without creating a subscription + * @param eventName The DummyERC721Token contract event you would like to subscribe to. + * @param blockRange Block range to get logs from. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` + * @return Array of logs that match the parameters + */ + public async getLogsAsync( + eventName: DummyERC721TokenEvents, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, + ): Promise>> { + assert.doesBelongToStringEnum('eventName', eventName, DummyERC721TokenEvents); + assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + const logs = await this._subscriptionManager.getLogsAsync( + this.address, + eventName, + blockRange, + indexFilterValues, + DummyERC721TokenContract.ABI(), + ); + return logs; + } + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super( + 'DummyERC721Token', + DummyERC721TokenContract.ABI(), + address, + supportedProvider, + txDefaults, + logDecodeDependencies, + ); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); + this._subscriptionManager = new SubscriptionManager( + DummyERC721TokenContract.ABI(), + this._web3Wrapper, + ); } } diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/dutch_auction.ts b/packages/abi-gen-wrappers/src/generated-wrappers/dutch_auction.ts index d9ec1ad1a9..06fcfe755a 100644 --- a/packages/abi-gen-wrappers/src/generated-wrappers/dutch_auction.ts +++ b/packages/abi-gen-wrappers/src/generated-wrappers/dutch_auction.ts @@ -27,7 +27,17 @@ import * as ethers from 'ethers'; // tslint:disable:no-parameter-reassignment // tslint:disable-next-line:class-name export class DutchAuctionContract extends BaseContract { + /** + * Calculates the Auction Details for the given order + */ public getAuctionDetails = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param order The sell order + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( order: { makerAddress: string; @@ -72,6 +82,14 @@ export class DutchAuctionContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param order The sell order + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( order: { makerAddress: string; @@ -105,6 +123,12 @@ export class DutchAuctionContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param order The sell order + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( order: { makerAddress: string; @@ -148,6 +172,13 @@ export class DutchAuctionContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param order The sell order + * @returns AuctionDetails + */ async callAsync( order: { makerAddress: string; @@ -220,6 +251,12 @@ export class DutchAuctionContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param order The sell order + */ getABIEncodedTransactionData(order: { makerAddress: string; takerAddress: string; @@ -241,8 +278,108 @@ export class DutchAuctionContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): { + beginTimeSeconds: BigNumber; + endTimeSeconds: BigNumber; + beginAmount: BigNumber; + endAmount: BigNumber; + currentAmount: BigNumber; + currentTimeSeconds: BigNumber; + } { + const self = (this as any) as DutchAuctionContract; + const abiEncoder = self._lookupAbiEncoder( + 'getAuctionDetails((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<{ + beginTimeSeconds: BigNumber; + endTimeSeconds: BigNumber; + beginAmount: BigNumber; + endAmount: BigNumber; + currentAmount: BigNumber; + currentTimeSeconds: BigNumber; + }>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): { + beginTimeSeconds: BigNumber; + endTimeSeconds: BigNumber; + beginAmount: BigNumber; + endAmount: BigNumber; + currentAmount: BigNumber; + currentTimeSeconds: BigNumber; + } { + const self = (this as any) as DutchAuctionContract; + const abiEncoder = self._lookupAbiEncoder( + 'getAuctionDetails((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<{ + beginTimeSeconds: BigNumber; + endTimeSeconds: BigNumber; + beginAmount: BigNumber; + endAmount: BigNumber; + currentAmount: BigNumber; + currentTimeSeconds: BigNumber; + }>(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + order: { + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }, + txData?: Partial | undefined, + ): Promise { + await (this as any).getAuctionDetails.callAsync(order, txData); + const txHash = await (this as any).getAuctionDetails.sendTransactionAsync(order, txData); + return txHash; + }, }; + /** + * Matches the buy and sell orders at an amount given the following: the current block time, the auction + * start time and the auction begin amount. The sell order is a an order at the lowest amount + * at the end of the auction. Excess from the match is transferred to the seller. + * Over time the price moves from beginAmount to endAmount given the current block.timestamp. + * sellOrder.expiryTimeSeconds is the end time of the auction. + * sellOrder.takerAssetAmount is the end amount of the auction (lowest possible amount). + * sellOrder.makerAssetData is the ABI encoded Asset Proxy data with the following data appended + * buyOrder.makerAssetData is the buyers bid on the auction, must meet the amount for the current block timestamp + * (uint256 beginTimeSeconds, uint256 beginAmount). + * This function reverts in the following scenarios: + * * Auction has not started (auctionDetails.currentTimeSeconds < auctionDetails.beginTimeSeconds) + * * Auction has expired (auctionDetails.endTimeSeconds < auctionDetails.currentTimeSeconds) + * * Amount is invalid: Buy order amount is too low (buyOrder.makerAssetAmount < auctionDetails.currentAmount) + * * Amount is invalid: Invalid begin amount (auctionDetails.beginAmount > auctionDetails.endAmount) + * * Any failure in the 0x Match Orders + */ public matchOrders = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param buyOrder The Buyer's order. This order is for the current expected + * price of the auction. + * @param sellOrder The Seller's order. This order is for the lowest amount (at + * the end of the auction). + * @param buySignature Proof that order was created by the buyer. + * @param sellSignature Proof that order was created by the seller. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( buyOrder: { makerAddress: string; @@ -303,6 +440,19 @@ export class DutchAuctionContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param buyOrder The Buyer's order. This order is for the current expected + * price of the auction. + * @param sellOrder The Seller's order. This order is for the lowest amount (at + * the end of the auction). + * @param buySignature Proof that order was created by the buyer. + * @param sellSignature Proof that order was created by the seller. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( buyOrder: { makerAddress: string; @@ -360,6 +510,17 @@ export class DutchAuctionContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param buyOrder The Buyer's order. This order is for the current expected + * price of the auction. + * @param sellOrder The Seller's order. This order is for the lowest amount (at + * the end of the auction). + * @param buySignature Proof that order was created by the buyer. + * @param sellSignature Proof that order was created by the seller. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( buyOrder: { makerAddress: string; @@ -419,6 +580,18 @@ export class DutchAuctionContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param buyOrder The Buyer's order. This order is for the current expected + * price of the auction. + * @param sellOrder The Seller's order. This order is for the lowest amount (at + * the end of the auction). + * @param buySignature Proof that order was created by the buyer. + * @param sellSignature Proof that order was created by the seller. + * @returns matchedFillResults amounts filled and fees paid by maker and taker of matched orders. + */ async callAsync( buyOrder: { makerAddress: string; @@ -523,6 +696,17 @@ export class DutchAuctionContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param buyOrder The Buyer's order. This order is for the current expected + * price of the auction. + * @param sellOrder The Seller's order. This order is for the lowest amount (at + * the end of the auction). + * @param buySignature Proof that order was created by the buyer. + * @param sellSignature Proof that order was created by the seller. + */ getABIEncodedTransactionData( buyOrder: { makerAddress: string; @@ -564,11 +748,133 @@ export class DutchAuctionContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): { + left: { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }; + right: { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }; + leftMakerAssetSpreadAmount: BigNumber; + } { + const self = (this as any) as DutchAuctionContract; + const abiEncoder = self._lookupAbiEncoder( + 'matchOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes,bytes)', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<{ + left: { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }; + right: { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }; + leftMakerAssetSpreadAmount: BigNumber; + }>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): { + left: { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }; + right: { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }; + leftMakerAssetSpreadAmount: BigNumber; + } { + const self = (this as any) as DutchAuctionContract; + const abiEncoder = self._lookupAbiEncoder( + 'matchOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes,bytes)', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<{ + left: { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }; + right: { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }; + leftMakerAssetSpreadAmount: BigNumber; + }>(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + buyOrder: { + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }, + sellOrder: { + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }, + buySignature: string, + sellSignature: string, + txData?: Partial | undefined, + ): Promise { + await (this as any).matchOrders.callAsync(buyOrder, sellOrder, buySignature, sellSignature, txData); + const txHash = await (this as any).matchOrders.sendTransactionAsync( + buyOrder, + sellOrder, + buySignature, + sellSignature, + txData, + ); + return txHash; + }, }; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, _exchange: string, ): Promise { assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ @@ -582,13 +888,27 @@ export class DutchAuctionContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; - return DutchAuctionContract.deployAsync(bytecode, abi, provider, txDefaults, _exchange); + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return DutchAuctionContract.deployAsync( + bytecode, + abi, + provider, + txDefaults, + logDecodeDependenciesAbiOnly, + _exchange, + ); } public static async deployAsync( bytecode: string, abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, _exchange: string, ): Promise { assert.isHexString('bytecode', bytecode); @@ -617,7 +937,12 @@ export class DutchAuctionContract extends BaseContract { logUtils.log(`transactionHash: ${txHash}`); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); logUtils.log(`DutchAuction successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new DutchAuctionContract(txReceipt.contractAddress as string, provider, txDefaults); + const contractInstance = new DutchAuctionContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); contractInstance.constructorArgs = [_exchange]; return contractInstance; } @@ -918,8 +1243,20 @@ export class DutchAuctionContract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('DutchAuction', DutchAuctionContract.ABI(), address, supportedProvider, txDefaults); + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super( + 'DutchAuction', + DutchAuctionContract.ABI(), + address, + supportedProvider, + txDefaults, + logDecodeDependencies, + ); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); } } diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/erc20_proxy.ts b/packages/abi-gen-wrappers/src/generated-wrappers/erc20_proxy.ts index 4f24e36cff..8f625dc52b 100644 --- a/packages/abi-gen-wrappers/src/generated-wrappers/erc20_proxy.ts +++ b/packages/abi-gen-wrappers/src/generated-wrappers/erc20_proxy.ts @@ -1,7 +1,14 @@ // tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma // tslint:disable:whitespace no-unbound-method no-trailing-whitespace // tslint:disable:no-unused-variable -import { BaseContract, PromiseWithTransactionHash } from '@0x/base-contract'; +import { + BaseContract, + BlockRange, + EventCallback, + IndexedFilterValues, + SubscriptionManager, + PromiseWithTransactionHash, +} from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { BlockParam, @@ -10,6 +17,7 @@ import { ContractAbi, ContractArtifact, DecodedLogArgs, + LogWithDecodedArgs, MethodAbi, TransactionReceiptWithDecodedLogs, TxData, @@ -46,7 +54,17 @@ export interface ERC20ProxyAuthorizedAddressRemovedEventArgs extends DecodedLogA // tslint:disable:no-parameter-reassignment // tslint:disable-next-line:class-name export class ERC20ProxyContract extends BaseContract { + /** + * Authorizes an address. + */ public addAuthorizedAddress = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param target Address to authorize. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(target: string, txData?: Partial | undefined): Promise { const self = (this as any) as ERC20ProxyContract; const encodedData = self._strictEncodeArguments('addAuthorizedAddress(address)', [target]); @@ -72,6 +90,14 @@ export class ERC20ProxyContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param target Address to authorize. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( target: string, txData?: Partial, @@ -93,6 +119,12 @@ export class ERC20ProxyContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param target Address to authorize. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(target: string, txData?: Partial | undefined): Promise { const self = (this as any) as ERC20ProxyContract; const encodedData = self._strictEncodeArguments('addAuthorizedAddress(address)', [target]); @@ -117,6 +149,12 @@ export class ERC20ProxyContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param target Address to authorize. + */ async callAsync(target: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isString('target', target); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -154,6 +192,12 @@ export class ERC20ProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param target Address to authorize. + */ getABIEncodedTransactionData(target: string): string { assert.isString('target', target); const self = (this as any) as ERC20ProxyContract; @@ -162,8 +206,32 @@ export class ERC20ProxyContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ERC20ProxyContract; + const abiEncoder = self._lookupAbiEncoder('addAuthorizedAddress(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ERC20ProxyContract; + const abiEncoder = self._lookupAbiEncoder('addAuthorizedAddress(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(target: string, txData?: Partial | undefined): Promise { + await (this as any).addAuthorizedAddress.callAsync(target, txData); + const txHash = await (this as any).addAuthorizedAddress.sendTransactionAsync(target, txData); + return txHash; + }, }; public authorities = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( index_0: BigNumber, callData: Partial = {}, @@ -205,14 +273,43 @@ export class ERC20ProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: BigNumber): string { assert.isBigNumber('index_0', index_0); const self = (this as any) as ERC20ProxyContract; const abiEncodedTransactionData = self._strictEncodeArguments('authorities(uint256)', [index_0]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as ERC20ProxyContract; + const abiEncoder = self._lookupAbiEncoder('authorities(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as ERC20ProxyContract; + const abiEncoder = self._lookupAbiEncoder('authorities(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Removes authorizion of an address. + */ public removeAuthorizedAddress = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param target Address to remove authorization from. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(target: string, txData?: Partial | undefined): Promise { const self = (this as any) as ERC20ProxyContract; const encodedData = self._strictEncodeArguments('removeAuthorizedAddress(address)', [target]); @@ -238,6 +335,14 @@ export class ERC20ProxyContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param target Address to remove authorization from. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( target: string, txData?: Partial, @@ -259,6 +364,12 @@ export class ERC20ProxyContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param target Address to remove authorization from. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(target: string, txData?: Partial | undefined): Promise { const self = (this as any) as ERC20ProxyContract; const encodedData = self._strictEncodeArguments('removeAuthorizedAddress(address)', [target]); @@ -283,6 +394,12 @@ export class ERC20ProxyContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param target Address to remove authorization from. + */ async callAsync(target: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isString('target', target); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -320,6 +437,12 @@ export class ERC20ProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param target Address to remove authorization from. + */ getABIEncodedTransactionData(target: string): string { assert.isString('target', target); const self = (this as any) as ERC20ProxyContract; @@ -328,8 +451,32 @@ export class ERC20ProxyContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ERC20ProxyContract; + const abiEncoder = self._lookupAbiEncoder('removeAuthorizedAddress(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ERC20ProxyContract; + const abiEncoder = self._lookupAbiEncoder('removeAuthorizedAddress(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(target: string, txData?: Partial | undefined): Promise { + await (this as any).removeAuthorizedAddress.callAsync(target, txData); + const txHash = await (this as any).removeAuthorizedAddress.sendTransactionAsync(target, txData); + return txHash; + }, }; public owner = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -366,13 +513,43 @@ export class ERC20ProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as ERC20ProxyContract; const abiEncodedTransactionData = self._strictEncodeArguments('owner()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as ERC20ProxyContract; + const abiEncoder = self._lookupAbiEncoder('owner()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as ERC20ProxyContract; + const abiEncoder = self._lookupAbiEncoder('owner()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Removes authorizion of an address. + */ public removeAuthorizedAddressAtIndex = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param target Address to remove authorization from. + * @param index Index of target in authorities array. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( target: string, index: BigNumber, @@ -405,6 +582,15 @@ export class ERC20ProxyContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param target Address to remove authorization from. + * @param index Index of target in authorities array. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( target: string, index: BigNumber, @@ -432,6 +618,13 @@ export class ERC20ProxyContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param target Address to remove authorization from. + * @param index Index of target in authorities array. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( target: string, index: BigNumber, @@ -463,6 +656,13 @@ export class ERC20ProxyContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param target Address to remove authorization from. + * @param index Index of target in authorities array. + */ async callAsync( target: string, index: BigNumber, @@ -509,6 +709,13 @@ export class ERC20ProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param target Address to remove authorization from. + * @param index Index of target in authorities array. + */ getABIEncodedTransactionData(target: string, index: BigNumber): string { assert.isString('target', target); assert.isBigNumber('index', index); @@ -519,8 +726,44 @@ export class ERC20ProxyContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ERC20ProxyContract; + const abiEncoder = self._lookupAbiEncoder('removeAuthorizedAddressAtIndex(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ERC20ProxyContract; + const abiEncoder = self._lookupAbiEncoder('removeAuthorizedAddressAtIndex(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + target: string, + index: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).removeAuthorizedAddressAtIndex.callAsync(target, index, txData); + const txHash = await (this as any).removeAuthorizedAddressAtIndex.sendTransactionAsync( + target, + index, + txData, + ); + return txHash; + }, }; + /** + * Gets the proxy id associated with the proxy address. + */ public getProxyId = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @returns Proxy id. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -557,13 +800,37 @@ export class ERC20ProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as ERC20ProxyContract; const abiEncodedTransactionData = self._strictEncodeArguments('getProxyId()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as ERC20ProxyContract; + const abiEncoder = self._lookupAbiEncoder('getProxyId()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as ERC20ProxyContract; + const abiEncoder = self._lookupAbiEncoder('getProxyId()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public authorized = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( index_0: string, callData: Partial = {}, @@ -605,6 +872,11 @@ export class ERC20ProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: string): string { assert.isString('index_0', index_0); const self = (this as any) as ERC20ProxyContract; @@ -613,8 +885,31 @@ export class ERC20ProxyContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as ERC20ProxyContract; + const abiEncoder = self._lookupAbiEncoder('authorized(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as ERC20ProxyContract; + const abiEncoder = self._lookupAbiEncoder('authorized(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Gets all authorized addresses. + */ public getAuthorizedAddresses = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @returns Array of authorized addresses. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -651,13 +946,38 @@ export class ERC20ProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as ERC20ProxyContract; const abiEncodedTransactionData = self._strictEncodeArguments('getAuthorizedAddresses()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string[] { + const self = (this as any) as ERC20ProxyContract; + const abiEncoder = self._lookupAbiEncoder('getAuthorizedAddresses()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string[] { + const self = (this as any) as ERC20ProxyContract; + const abiEncoder = self._lookupAbiEncoder('getAuthorizedAddresses()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public transferOwnership = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(newOwner: string, txData?: Partial | undefined): Promise { const self = (this as any) as ERC20ProxyContract; const encodedData = self._strictEncodeArguments('transferOwnership(address)', [newOwner]); @@ -683,6 +1003,13 @@ export class ERC20ProxyContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( newOwner: string, txData?: Partial, @@ -704,6 +1031,11 @@ export class ERC20ProxyContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(newOwner: string, txData?: Partial | undefined): Promise { const self = (this as any) as ERC20ProxyContract; const encodedData = self._strictEncodeArguments('transferOwnership(address)', [newOwner]); @@ -728,6 +1060,11 @@ export class ERC20ProxyContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(newOwner: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isString('newOwner', newOwner); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -765,6 +1102,11 @@ export class ERC20ProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(newOwner: string): string { assert.isString('newOwner', newOwner); const self = (this as any) as ERC20ProxyContract; @@ -773,11 +1115,32 @@ export class ERC20ProxyContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ERC20ProxyContract; + const abiEncoder = self._lookupAbiEncoder('transferOwnership(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ERC20ProxyContract; + const abiEncoder = self._lookupAbiEncoder('transferOwnership(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(newOwner: string, txData?: Partial | undefined): Promise { + await (this as any).transferOwnership.callAsync(newOwner, txData); + const txHash = await (this as any).transferOwnership.sendTransactionAsync(newOwner, txData); + return txHash; + }, }; + private readonly _subscriptionManager: SubscriptionManager; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, ): Promise { assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ schemas.addressSchema, @@ -790,13 +1153,20 @@ export class ERC20ProxyContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; - return ERC20ProxyContract.deployAsync(bytecode, abi, provider, txDefaults); + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return ERC20ProxyContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); } public static async deployAsync( bytecode: string, abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, ): Promise { assert.isHexString('bytecode', bytecode); assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ @@ -820,7 +1190,12 @@ export class ERC20ProxyContract extends BaseContract { logUtils.log(`transactionHash: ${txHash}`); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); logUtils.log(`ERC20Proxy successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new ERC20ProxyContract(txReceipt.contractAddress as string, provider, txDefaults); + const contractInstance = new ERC20ProxyContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); contractInstance.constructorArgs = []; return contractInstance; } @@ -1016,9 +1391,86 @@ export class ERC20ProxyContract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('ERC20Proxy', ERC20ProxyContract.ABI(), address, supportedProvider, txDefaults); + /** + * Subscribe to an event type emitted by the ERC20Proxy contract. + * @param eventName The ERC20Proxy contract event you would like to subscribe to. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` + * @param callback Callback that gets called when a log is added/removed + * @param isVerbose Enable verbose subscription warnings (e.g recoverable network issues encountered) + * @return Subscription token used later to unsubscribe + */ + public subscribe( + eventName: ERC20ProxyEvents, + indexFilterValues: IndexedFilterValues, + callback: EventCallback, + isVerbose: boolean = false, + blockPollingIntervalMs?: number, + ): string { + assert.doesBelongToStringEnum('eventName', eventName, ERC20ProxyEvents); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + assert.isFunction('callback', callback); + const subscriptionToken = this._subscriptionManager.subscribe( + this.address, + eventName, + indexFilterValues, + ERC20ProxyContract.ABI(), + callback, + isVerbose, + blockPollingIntervalMs, + ); + return subscriptionToken; + } + /** + * Cancel a subscription + * @param subscriptionToken Subscription token returned by `subscribe()` + */ + public unsubscribe(subscriptionToken: string): void { + this._subscriptionManager.unsubscribe(subscriptionToken); + } + /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + this._subscriptionManager.unsubscribeAll(); + } + /** + * Gets historical logs without creating a subscription + * @param eventName The ERC20Proxy contract event you would like to subscribe to. + * @param blockRange Block range to get logs from. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` + * @return Array of logs that match the parameters + */ + public async getLogsAsync( + eventName: ERC20ProxyEvents, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, + ): Promise>> { + assert.doesBelongToStringEnum('eventName', eventName, ERC20ProxyEvents); + assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + const logs = await this._subscriptionManager.getLogsAsync( + this.address, + eventName, + blockRange, + indexFilterValues, + ERC20ProxyContract.ABI(), + ); + return logs; + } + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super('ERC20Proxy', ERC20ProxyContract.ABI(), address, supportedProvider, txDefaults, logDecodeDependencies); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); + this._subscriptionManager = new SubscriptionManager( + ERC20ProxyContract.ABI(), + this._web3Wrapper, + ); } } diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/erc20_token.ts b/packages/abi-gen-wrappers/src/generated-wrappers/erc20_token.ts index 33a49051fc..f9315da18b 100644 --- a/packages/abi-gen-wrappers/src/generated-wrappers/erc20_token.ts +++ b/packages/abi-gen-wrappers/src/generated-wrappers/erc20_token.ts @@ -1,7 +1,14 @@ // tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma // tslint:disable:whitespace no-unbound-method no-trailing-whitespace // tslint:disable:no-unused-variable -import { BaseContract, PromiseWithTransactionHash } from '@0x/base-contract'; +import { + BaseContract, + BlockRange, + EventCallback, + IndexedFilterValues, + SubscriptionManager, + PromiseWithTransactionHash, +} from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { BlockParam, @@ -10,6 +17,7 @@ import { ContractAbi, ContractArtifact, DecodedLogArgs, + LogWithDecodedArgs, MethodAbi, TransactionReceiptWithDecodedLogs, TxData, @@ -46,7 +54,18 @@ export interface ERC20TokenApprovalEventArgs extends DecodedLogArgs { // tslint:disable:no-parameter-reassignment // tslint:disable-next-line:class-name export class ERC20TokenContract extends BaseContract { + /** + * `msg.sender` approves `_spender` to spend `_value` tokens + */ public approve = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _spender The address of the account able to transfer the tokens + * @param _value The amount of wei to be approved for transfer + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _spender: string, _value: BigNumber, @@ -76,6 +95,15 @@ export class ERC20TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _spender The address of the account able to transfer the tokens + * @param _value The amount of wei to be approved for transfer + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _spender: string, _value: BigNumber, @@ -99,6 +127,13 @@ export class ERC20TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _spender The address of the account able to transfer the tokens + * @param _value The amount of wei to be approved for transfer + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( _spender: string, _value: BigNumber, @@ -127,6 +162,14 @@ export class ERC20TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _spender The address of the account able to transfer the tokens + * @param _value The amount of wei to be approved for transfer + * @returns Always true if the call has enough gas to complete execution + */ async callAsync( _spender: string, _value: BigNumber, @@ -173,6 +216,13 @@ export class ERC20TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _spender The address of the account able to transfer the tokens + * @param _value The amount of wei to be approved for transfer + */ getABIEncodedTransactionData(_spender: string, _value: BigNumber): string { assert.isString('_spender', _spender); assert.isBigNumber('_value', _value); @@ -183,8 +233,40 @@ export class ERC20TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as ERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('approve(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as ERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('approve(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _spender: string, + _value: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).approve.callAsync(_spender, _value, txData); + const txHash = await (this as any).approve.sendTransactionAsync(_spender, _value, txData); + return txHash; + }, }; + /** + * Query total supply of token + */ public totalSupply = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @returns Total supply of token + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -221,13 +303,44 @@ export class ERC20TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as ERC20TokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('totalSupply()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as ERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('totalSupply()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as ERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('totalSupply()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * send `value` token to `to` from `from` on the condition it is approved by `from` + */ public transferFrom = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _from The address of the sender + * @param _to The address of the recipient + * @param _value The amount of token to be transferred + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _from: string, _to: string, @@ -262,6 +375,16 @@ export class ERC20TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _from The address of the sender + * @param _to The address of the recipient + * @param _value The amount of token to be transferred + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _from: string, _to: string, @@ -292,6 +415,14 @@ export class ERC20TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _from The address of the sender + * @param _to The address of the recipient + * @param _value The amount of token to be transferred + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( _from: string, _to: string, @@ -325,6 +456,15 @@ export class ERC20TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _from The address of the sender + * @param _to The address of the recipient + * @param _value The amount of token to be transferred + * @returns True if transfer was successful + */ async callAsync( _from: string, _to: string, @@ -374,6 +514,14 @@ export class ERC20TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _from The address of the sender + * @param _to The address of the recipient + * @param _value The amount of token to be transferred + */ getABIEncodedTransactionData(_from: string, _to: string, _value: BigNumber): string { assert.isString('_from', _from); assert.isString('_to', _to); @@ -386,8 +534,42 @@ export class ERC20TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as ERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('transferFrom(address,address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as ERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('transferFrom(address,address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _from: string, + _to: string, + _value: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).transferFrom.callAsync(_from, _to, _value, txData); + const txHash = await (this as any).transferFrom.sendTransactionAsync(_from, _to, _value, txData); + return txHash; + }, }; + /** + * Query the balance of owner + */ public balanceOf = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _owner The address from which the balance will be retrieved + * @returns Balance of owner + */ async callAsync( _owner: string, callData: Partial = {}, @@ -429,14 +611,45 @@ export class ERC20TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _owner The address from which the balance will be retrieved + */ getABIEncodedTransactionData(_owner: string): string { assert.isString('_owner', _owner); const self = (this as any) as ERC20TokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('balanceOf(address)', [_owner.toLowerCase()]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as ERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('balanceOf(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as ERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('balanceOf(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * send `value` token to `to` from `msg.sender` + */ public transfer = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _to The address of the recipient + * @param _value The amount of token to be transferred + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _to: string, _value: BigNumber, @@ -466,6 +679,15 @@ export class ERC20TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _to The address of the recipient + * @param _value The amount of token to be transferred + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _to: string, _value: BigNumber, @@ -489,6 +711,13 @@ export class ERC20TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _to The address of the recipient + * @param _value The amount of token to be transferred + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(_to: string, _value: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as ERC20TokenContract; const encodedData = self._strictEncodeArguments('transfer(address,uint256)', [_to, _value]); @@ -513,6 +742,14 @@ export class ERC20TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _to The address of the recipient + * @param _value The amount of token to be transferred + * @returns True if transfer was successful + */ async callAsync( _to: string, _value: BigNumber, @@ -556,6 +793,13 @@ export class ERC20TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _to The address of the recipient + * @param _value The amount of token to be transferred + */ getABIEncodedTransactionData(_to: string, _value: BigNumber): string { assert.isString('_to', _to); assert.isBigNumber('_value', _value); @@ -566,8 +810,39 @@ export class ERC20TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as ERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('transfer(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as ERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('transfer(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _to: string, + _value: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).transfer.callAsync(_to, _value, txData); + const txHash = await (this as any).transfer.sendTransactionAsync(_to, _value, txData); + return txHash; + }, }; public allowance = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _owner The address of the account owning tokens + * @param _spender The address of the account able to transfer the tokens + * @returns Amount of remaining tokens allowed to spent + */ async callAsync( _owner: string, _spender: string, @@ -614,6 +889,13 @@ export class ERC20TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _owner The address of the account owning tokens + * @param _spender The address of the account able to transfer the tokens + */ getABIEncodedTransactionData(_owner: string, _spender: string): string { assert.isString('_owner', _owner); assert.isString('_spender', _spender); @@ -624,11 +906,27 @@ export class ERC20TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as ERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('allowance(address,address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as ERC20TokenContract; + const abiEncoder = self._lookupAbiEncoder('allowance(address,address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + private readonly _subscriptionManager: SubscriptionManager; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, ): Promise { assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ schemas.addressSchema, @@ -641,13 +939,20 @@ export class ERC20TokenContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; - return ERC20TokenContract.deployAsync(bytecode, abi, provider, txDefaults); + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return ERC20TokenContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); } public static async deployAsync( bytecode: string, abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, ): Promise { assert.isHexString('bytecode', bytecode); assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ @@ -671,7 +976,12 @@ export class ERC20TokenContract extends BaseContract { logUtils.log(`transactionHash: ${txHash}`); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); logUtils.log(`ERC20Token successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new ERC20TokenContract(txReceipt.contractAddress as string, provider, txDefaults); + const contractInstance = new ERC20TokenContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); contractInstance.constructorArgs = []; return contractInstance; } @@ -859,9 +1169,86 @@ export class ERC20TokenContract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('ERC20Token', ERC20TokenContract.ABI(), address, supportedProvider, txDefaults); + /** + * Subscribe to an event type emitted by the ERC20Token contract. + * @param eventName The ERC20Token contract event you would like to subscribe to. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` + * @param callback Callback that gets called when a log is added/removed + * @param isVerbose Enable verbose subscription warnings (e.g recoverable network issues encountered) + * @return Subscription token used later to unsubscribe + */ + public subscribe( + eventName: ERC20TokenEvents, + indexFilterValues: IndexedFilterValues, + callback: EventCallback, + isVerbose: boolean = false, + blockPollingIntervalMs?: number, + ): string { + assert.doesBelongToStringEnum('eventName', eventName, ERC20TokenEvents); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + assert.isFunction('callback', callback); + const subscriptionToken = this._subscriptionManager.subscribe( + this.address, + eventName, + indexFilterValues, + ERC20TokenContract.ABI(), + callback, + isVerbose, + blockPollingIntervalMs, + ); + return subscriptionToken; + } + /** + * Cancel a subscription + * @param subscriptionToken Subscription token returned by `subscribe()` + */ + public unsubscribe(subscriptionToken: string): void { + this._subscriptionManager.unsubscribe(subscriptionToken); + } + /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + this._subscriptionManager.unsubscribeAll(); + } + /** + * Gets historical logs without creating a subscription + * @param eventName The ERC20Token contract event you would like to subscribe to. + * @param blockRange Block range to get logs from. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` + * @return Array of logs that match the parameters + */ + public async getLogsAsync( + eventName: ERC20TokenEvents, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, + ): Promise>> { + assert.doesBelongToStringEnum('eventName', eventName, ERC20TokenEvents); + assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + const logs = await this._subscriptionManager.getLogsAsync( + this.address, + eventName, + blockRange, + indexFilterValues, + ERC20TokenContract.ABI(), + ); + return logs; + } + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super('ERC20Token', ERC20TokenContract.ABI(), address, supportedProvider, txDefaults, logDecodeDependencies); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); + this._subscriptionManager = new SubscriptionManager( + ERC20TokenContract.ABI(), + this._web3Wrapper, + ); } } diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/erc721_proxy.ts b/packages/abi-gen-wrappers/src/generated-wrappers/erc721_proxy.ts index 7b8da252a0..8716ecb60b 100644 --- a/packages/abi-gen-wrappers/src/generated-wrappers/erc721_proxy.ts +++ b/packages/abi-gen-wrappers/src/generated-wrappers/erc721_proxy.ts @@ -1,7 +1,14 @@ // tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma // tslint:disable:whitespace no-unbound-method no-trailing-whitespace // tslint:disable:no-unused-variable -import { BaseContract, PromiseWithTransactionHash } from '@0x/base-contract'; +import { + BaseContract, + BlockRange, + EventCallback, + IndexedFilterValues, + SubscriptionManager, + PromiseWithTransactionHash, +} from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { BlockParam, @@ -10,6 +17,7 @@ import { ContractAbi, ContractArtifact, DecodedLogArgs, + LogWithDecodedArgs, MethodAbi, TransactionReceiptWithDecodedLogs, TxData, @@ -46,7 +54,17 @@ export interface ERC721ProxyAuthorizedAddressRemovedEventArgs extends DecodedLog // tslint:disable:no-parameter-reassignment // tslint:disable-next-line:class-name export class ERC721ProxyContract extends BaseContract { + /** + * Authorizes an address. + */ public addAuthorizedAddress = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param target Address to authorize. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(target: string, txData?: Partial | undefined): Promise { const self = (this as any) as ERC721ProxyContract; const encodedData = self._strictEncodeArguments('addAuthorizedAddress(address)', [target]); @@ -72,6 +90,14 @@ export class ERC721ProxyContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param target Address to authorize. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( target: string, txData?: Partial, @@ -93,6 +119,12 @@ export class ERC721ProxyContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param target Address to authorize. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(target: string, txData?: Partial | undefined): Promise { const self = (this as any) as ERC721ProxyContract; const encodedData = self._strictEncodeArguments('addAuthorizedAddress(address)', [target]); @@ -117,6 +149,12 @@ export class ERC721ProxyContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param target Address to authorize. + */ async callAsync(target: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isString('target', target); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -154,6 +192,12 @@ export class ERC721ProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param target Address to authorize. + */ getABIEncodedTransactionData(target: string): string { assert.isString('target', target); const self = (this as any) as ERC721ProxyContract; @@ -162,8 +206,32 @@ export class ERC721ProxyContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ERC721ProxyContract; + const abiEncoder = self._lookupAbiEncoder('addAuthorizedAddress(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ERC721ProxyContract; + const abiEncoder = self._lookupAbiEncoder('addAuthorizedAddress(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(target: string, txData?: Partial | undefined): Promise { + await (this as any).addAuthorizedAddress.callAsync(target, txData); + const txHash = await (this as any).addAuthorizedAddress.sendTransactionAsync(target, txData); + return txHash; + }, }; public authorities = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( index_0: BigNumber, callData: Partial = {}, @@ -205,14 +273,43 @@ export class ERC721ProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: BigNumber): string { assert.isBigNumber('index_0', index_0); const self = (this as any) as ERC721ProxyContract; const abiEncodedTransactionData = self._strictEncodeArguments('authorities(uint256)', [index_0]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as ERC721ProxyContract; + const abiEncoder = self._lookupAbiEncoder('authorities(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as ERC721ProxyContract; + const abiEncoder = self._lookupAbiEncoder('authorities(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Removes authorizion of an address. + */ public removeAuthorizedAddress = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param target Address to remove authorization from. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(target: string, txData?: Partial | undefined): Promise { const self = (this as any) as ERC721ProxyContract; const encodedData = self._strictEncodeArguments('removeAuthorizedAddress(address)', [target]); @@ -238,6 +335,14 @@ export class ERC721ProxyContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param target Address to remove authorization from. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( target: string, txData?: Partial, @@ -259,6 +364,12 @@ export class ERC721ProxyContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param target Address to remove authorization from. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(target: string, txData?: Partial | undefined): Promise { const self = (this as any) as ERC721ProxyContract; const encodedData = self._strictEncodeArguments('removeAuthorizedAddress(address)', [target]); @@ -283,6 +394,12 @@ export class ERC721ProxyContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param target Address to remove authorization from. + */ async callAsync(target: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isString('target', target); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -320,6 +437,12 @@ export class ERC721ProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param target Address to remove authorization from. + */ getABIEncodedTransactionData(target: string): string { assert.isString('target', target); const self = (this as any) as ERC721ProxyContract; @@ -328,8 +451,32 @@ export class ERC721ProxyContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ERC721ProxyContract; + const abiEncoder = self._lookupAbiEncoder('removeAuthorizedAddress(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ERC721ProxyContract; + const abiEncoder = self._lookupAbiEncoder('removeAuthorizedAddress(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(target: string, txData?: Partial | undefined): Promise { + await (this as any).removeAuthorizedAddress.callAsync(target, txData); + const txHash = await (this as any).removeAuthorizedAddress.sendTransactionAsync(target, txData); + return txHash; + }, }; public owner = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -366,13 +513,43 @@ export class ERC721ProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as ERC721ProxyContract; const abiEncodedTransactionData = self._strictEncodeArguments('owner()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as ERC721ProxyContract; + const abiEncoder = self._lookupAbiEncoder('owner()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as ERC721ProxyContract; + const abiEncoder = self._lookupAbiEncoder('owner()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Removes authorizion of an address. + */ public removeAuthorizedAddressAtIndex = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param target Address to remove authorization from. + * @param index Index of target in authorities array. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( target: string, index: BigNumber, @@ -405,6 +582,15 @@ export class ERC721ProxyContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param target Address to remove authorization from. + * @param index Index of target in authorities array. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( target: string, index: BigNumber, @@ -432,6 +618,13 @@ export class ERC721ProxyContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param target Address to remove authorization from. + * @param index Index of target in authorities array. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( target: string, index: BigNumber, @@ -463,6 +656,13 @@ export class ERC721ProxyContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param target Address to remove authorization from. + * @param index Index of target in authorities array. + */ async callAsync( target: string, index: BigNumber, @@ -509,6 +709,13 @@ export class ERC721ProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param target Address to remove authorization from. + * @param index Index of target in authorities array. + */ getABIEncodedTransactionData(target: string, index: BigNumber): string { assert.isString('target', target); assert.isBigNumber('index', index); @@ -519,8 +726,44 @@ export class ERC721ProxyContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ERC721ProxyContract; + const abiEncoder = self._lookupAbiEncoder('removeAuthorizedAddressAtIndex(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ERC721ProxyContract; + const abiEncoder = self._lookupAbiEncoder('removeAuthorizedAddressAtIndex(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + target: string, + index: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).removeAuthorizedAddressAtIndex.callAsync(target, index, txData); + const txHash = await (this as any).removeAuthorizedAddressAtIndex.sendTransactionAsync( + target, + index, + txData, + ); + return txHash; + }, }; + /** + * Gets the proxy id associated with the proxy address. + */ public getProxyId = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @returns Proxy id. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -557,13 +800,37 @@ export class ERC721ProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as ERC721ProxyContract; const abiEncodedTransactionData = self._strictEncodeArguments('getProxyId()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as ERC721ProxyContract; + const abiEncoder = self._lookupAbiEncoder('getProxyId()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as ERC721ProxyContract; + const abiEncoder = self._lookupAbiEncoder('getProxyId()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public authorized = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( index_0: string, callData: Partial = {}, @@ -605,6 +872,11 @@ export class ERC721ProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: string): string { assert.isString('index_0', index_0); const self = (this as any) as ERC721ProxyContract; @@ -613,8 +885,31 @@ export class ERC721ProxyContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as ERC721ProxyContract; + const abiEncoder = self._lookupAbiEncoder('authorized(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as ERC721ProxyContract; + const abiEncoder = self._lookupAbiEncoder('authorized(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Gets all authorized addresses. + */ public getAuthorizedAddresses = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @returns Array of authorized addresses. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -651,13 +946,38 @@ export class ERC721ProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as ERC721ProxyContract; const abiEncodedTransactionData = self._strictEncodeArguments('getAuthorizedAddresses()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string[] { + const self = (this as any) as ERC721ProxyContract; + const abiEncoder = self._lookupAbiEncoder('getAuthorizedAddresses()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string[] { + const self = (this as any) as ERC721ProxyContract; + const abiEncoder = self._lookupAbiEncoder('getAuthorizedAddresses()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public transferOwnership = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(newOwner: string, txData?: Partial | undefined): Promise { const self = (this as any) as ERC721ProxyContract; const encodedData = self._strictEncodeArguments('transferOwnership(address)', [newOwner]); @@ -683,6 +1003,13 @@ export class ERC721ProxyContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( newOwner: string, txData?: Partial, @@ -704,6 +1031,11 @@ export class ERC721ProxyContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(newOwner: string, txData?: Partial | undefined): Promise { const self = (this as any) as ERC721ProxyContract; const encodedData = self._strictEncodeArguments('transferOwnership(address)', [newOwner]); @@ -728,6 +1060,11 @@ export class ERC721ProxyContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(newOwner: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isString('newOwner', newOwner); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -765,6 +1102,11 @@ export class ERC721ProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(newOwner: string): string { assert.isString('newOwner', newOwner); const self = (this as any) as ERC721ProxyContract; @@ -773,11 +1115,32 @@ export class ERC721ProxyContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ERC721ProxyContract; + const abiEncoder = self._lookupAbiEncoder('transferOwnership(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ERC721ProxyContract; + const abiEncoder = self._lookupAbiEncoder('transferOwnership(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(newOwner: string, txData?: Partial | undefined): Promise { + await (this as any).transferOwnership.callAsync(newOwner, txData); + const txHash = await (this as any).transferOwnership.sendTransactionAsync(newOwner, txData); + return txHash; + }, }; + private readonly _subscriptionManager: SubscriptionManager; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, ): Promise { assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ schemas.addressSchema, @@ -790,13 +1153,20 @@ export class ERC721ProxyContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; - return ERC721ProxyContract.deployAsync(bytecode, abi, provider, txDefaults); + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return ERC721ProxyContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); } public static async deployAsync( bytecode: string, abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, ): Promise { assert.isHexString('bytecode', bytecode); assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ @@ -820,7 +1190,12 @@ export class ERC721ProxyContract extends BaseContract { logUtils.log(`transactionHash: ${txHash}`); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); logUtils.log(`ERC721Proxy successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new ERC721ProxyContract(txReceipt.contractAddress as string, provider, txDefaults); + const contractInstance = new ERC721ProxyContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); contractInstance.constructorArgs = []; return contractInstance; } @@ -1016,9 +1391,86 @@ export class ERC721ProxyContract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('ERC721Proxy', ERC721ProxyContract.ABI(), address, supportedProvider, txDefaults); + /** + * Subscribe to an event type emitted by the ERC721Proxy contract. + * @param eventName The ERC721Proxy contract event you would like to subscribe to. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` + * @param callback Callback that gets called when a log is added/removed + * @param isVerbose Enable verbose subscription warnings (e.g recoverable network issues encountered) + * @return Subscription token used later to unsubscribe + */ + public subscribe( + eventName: ERC721ProxyEvents, + indexFilterValues: IndexedFilterValues, + callback: EventCallback, + isVerbose: boolean = false, + blockPollingIntervalMs?: number, + ): string { + assert.doesBelongToStringEnum('eventName', eventName, ERC721ProxyEvents); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + assert.isFunction('callback', callback); + const subscriptionToken = this._subscriptionManager.subscribe( + this.address, + eventName, + indexFilterValues, + ERC721ProxyContract.ABI(), + callback, + isVerbose, + blockPollingIntervalMs, + ); + return subscriptionToken; + } + /** + * Cancel a subscription + * @param subscriptionToken Subscription token returned by `subscribe()` + */ + public unsubscribe(subscriptionToken: string): void { + this._subscriptionManager.unsubscribe(subscriptionToken); + } + /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + this._subscriptionManager.unsubscribeAll(); + } + /** + * Gets historical logs without creating a subscription + * @param eventName The ERC721Proxy contract event you would like to subscribe to. + * @param blockRange Block range to get logs from. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` + * @return Array of logs that match the parameters + */ + public async getLogsAsync( + eventName: ERC721ProxyEvents, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, + ): Promise>> { + assert.doesBelongToStringEnum('eventName', eventName, ERC721ProxyEvents); + assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + const logs = await this._subscriptionManager.getLogsAsync( + this.address, + eventName, + blockRange, + indexFilterValues, + ERC721ProxyContract.ABI(), + ); + return logs; + } + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super('ERC721Proxy', ERC721ProxyContract.ABI(), address, supportedProvider, txDefaults, logDecodeDependencies); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); + this._subscriptionManager = new SubscriptionManager( + ERC721ProxyContract.ABI(), + this._web3Wrapper, + ); } } diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/erc721_token.ts b/packages/abi-gen-wrappers/src/generated-wrappers/erc721_token.ts index 2b9aeceb75..1222775973 100644 --- a/packages/abi-gen-wrappers/src/generated-wrappers/erc721_token.ts +++ b/packages/abi-gen-wrappers/src/generated-wrappers/erc721_token.ts @@ -1,7 +1,14 @@ // tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma // tslint:disable:whitespace no-unbound-method no-trailing-whitespace // tslint:disable:no-unused-variable -import { BaseContract, PromiseWithTransactionHash } from '@0x/base-contract'; +import { + BaseContract, + BlockRange, + EventCallback, + IndexedFilterValues, + SubscriptionManager, + PromiseWithTransactionHash, +} from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { BlockParam, @@ -10,6 +17,7 @@ import { ContractAbi, ContractArtifact, DecodedLogArgs, + LogWithDecodedArgs, MethodAbi, TransactionReceiptWithDecodedLogs, TxData, @@ -56,7 +64,17 @@ export interface ERC721TokenApprovalForAllEventArgs extends DecodedLogArgs { // tslint:disable:no-parameter-reassignment // tslint:disable-next-line:class-name export class ERC721TokenContract extends BaseContract { + /** + * Throws if `_tokenId` is not a valid NFT. + */ public getApproved = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _tokenId The NFT to find the approved address for + * @returns The approved address for this NFT, or the zero address if there is none + */ async callAsync( _tokenId: BigNumber, callData: Partial = {}, @@ -98,14 +116,47 @@ export class ERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _tokenId The NFT to find the approved address for + */ getABIEncodedTransactionData(_tokenId: BigNumber): string { assert.isBigNumber('_tokenId', _tokenId); const self = (this as any) as ERC721TokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('getApproved(uint256)', [_tokenId]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as ERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('getApproved(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as ERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('getApproved(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * The zero address indicates there is no approved address. + * Throws unless `msg.sender` is the current NFT owner, or an authorized + * operator of the current owner. + */ public approve = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _approved The new approved NFT controller + * @param _tokenId The NFT to approve + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _approved: string, _tokenId: BigNumber, @@ -135,6 +186,15 @@ export class ERC721TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _approved The new approved NFT controller + * @param _tokenId The NFT to approve + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _approved: string, _tokenId: BigNumber, @@ -158,6 +218,13 @@ export class ERC721TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _approved The new approved NFT controller + * @param _tokenId The NFT to approve + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( _approved: string, _tokenId: BigNumber, @@ -186,6 +253,13 @@ export class ERC721TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _approved The new approved NFT controller + * @param _tokenId The NFT to approve + */ async callAsync( _approved: string, _tokenId: BigNumber, @@ -232,6 +306,13 @@ export class ERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _approved The new approved NFT controller + * @param _tokenId The NFT to approve + */ getABIEncodedTransactionData(_approved: string, _tokenId: BigNumber): string { assert.isString('_approved', _approved); assert.isBigNumber('_tokenId', _tokenId); @@ -242,8 +323,46 @@ export class ERC721TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('approve(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('approve(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _approved: string, + _tokenId: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).approve.callAsync(_approved, _tokenId, txData); + const txHash = await (this as any).approve.sendTransactionAsync(_approved, _tokenId, txData); + return txHash; + }, }; + /** + * Throws unless `msg.sender` is the current owner, an authorized + * operator, or the approved address for this NFT. Throws if `_from` is + * not the current owner. Throws if `_to` is the zero address. Throws if + * `_tokenId` is not a valid NFT. + */ public transferFrom = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _from: string, _to: string, @@ -278,6 +397,16 @@ export class ERC721TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _from: string, _to: string, @@ -308,6 +437,14 @@ export class ERC721TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( _from: string, _to: string, @@ -341,6 +478,14 @@ export class ERC721TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + */ async callAsync( _from: string, _to: string, @@ -390,6 +535,14 @@ export class ERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + */ getABIEncodedTransactionData(_from: string, _to: string, _tokenId: BigNumber): string { assert.isString('_from', _from); assert.isString('_to', _to); @@ -402,8 +555,45 @@ export class ERC721TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('transferFrom(address,address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('transferFrom(address,address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _from: string, + _to: string, + _tokenId: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).transferFrom.callAsync(_from, _to, _tokenId, txData); + const txHash = await (this as any).transferFrom.sendTransactionAsync(_from, _to, _tokenId, txData); + return txHash; + }, }; + /** + * This works identically to the other function with an extra data parameter, + * except this function just sets data to "". + */ public safeTransferFrom1 = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _from: string, _to: string, @@ -438,6 +628,16 @@ export class ERC721TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _from: string, _to: string, @@ -468,6 +668,14 @@ export class ERC721TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( _from: string, _to: string, @@ -501,6 +709,14 @@ export class ERC721TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + */ async callAsync( _from: string, _to: string, @@ -550,6 +766,14 @@ export class ERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + */ getABIEncodedTransactionData(_from: string, _to: string, _tokenId: BigNumber): string { assert.isString('_from', _from); assert.isString('_to', _to); @@ -562,8 +786,43 @@ export class ERC721TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('safeTransferFrom(address,address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('safeTransferFrom(address,address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _from: string, + _to: string, + _tokenId: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).safeTransferFrom1.callAsync(_from, _to, _tokenId, txData); + const txHash = await (this as any).safeTransferFrom1.sendTransactionAsync(_from, _to, _tokenId, txData); + return txHash; + }, }; + /** + * NFTs assigned to zero address are considered invalid, and queries + * about them do throw. + */ public ownerOf = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _tokenId The identifier for an NFT + * @returns The address of the owner of the NFT + */ async callAsync( _tokenId: BigNumber, callData: Partial = {}, @@ -605,14 +864,45 @@ export class ERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _tokenId The identifier for an NFT + */ getABIEncodedTransactionData(_tokenId: BigNumber): string { assert.isBigNumber('_tokenId', _tokenId); const self = (this as any) as ERC721TokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('ownerOf(uint256)', [_tokenId]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as ERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('ownerOf(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as ERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('ownerOf(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * NFTs assigned to the zero address are considered invalid, and this + * function throws for queries about the zero address. + */ public balanceOf = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _owner An address for whom to query the balance + * @returns The number of NFTs owned by `_owner`, possibly zero + */ async callAsync( _owner: string, callData: Partial = {}, @@ -654,14 +944,46 @@ export class ERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _owner An address for whom to query the balance + */ getABIEncodedTransactionData(_owner: string): string { assert.isString('_owner', _owner); const self = (this as any) as ERC721TokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('balanceOf(address)', [_owner.toLowerCase()]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as ERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('balanceOf(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as ERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('balanceOf(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Emits the ApprovalForAll event. The contract MUST allow + * multiple operators per owner. + */ public setApprovalForAll = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _operator Address to add to the set of authorized operators + * @param _approved True if the operator is approved, false to revoke approval + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _operator: string, _approved: boolean, @@ -691,6 +1013,15 @@ export class ERC721TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _operator Address to add to the set of authorized operators + * @param _approved True if the operator is approved, false to revoke approval + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _operator: string, _approved: boolean, @@ -718,6 +1049,13 @@ export class ERC721TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _operator Address to add to the set of authorized operators + * @param _approved True if the operator is approved, false to revoke approval + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( _operator: string, _approved: boolean, @@ -746,6 +1084,13 @@ export class ERC721TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _operator Address to add to the set of authorized operators + * @param _approved True if the operator is approved, false to revoke approval + */ async callAsync( _operator: string, _approved: boolean, @@ -792,6 +1137,13 @@ export class ERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _operator Address to add to the set of authorized operators + * @param _approved True if the operator is approved, false to revoke approval + */ getABIEncodedTransactionData(_operator: string, _approved: boolean): string { assert.isString('_operator', _operator); assert.isBoolean('_approved', _approved); @@ -802,8 +1154,50 @@ export class ERC721TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('setApprovalForAll(address,bool)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('setApprovalForAll(address,bool)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _operator: string, + _approved: boolean, + txData?: Partial | undefined, + ): Promise { + await (this as any).setApprovalForAll.callAsync(_operator, _approved, txData); + const txHash = await (this as any).setApprovalForAll.sendTransactionAsync(_operator, _approved, txData); + return txHash; + }, }; + /** + * Throws unless `msg.sender` is the current owner, an authorized + * operator, or the approved address for this NFT. Throws if `_from` is + * not the current owner. Throws if `_to` is the zero address. Throws if + * `_tokenId` is not a valid NFT. When transfer is complete, this function + * checks if `_to` is a smart contract (code size > 0). If so, it calls + * `onERC721Received` on `_to` and throws if the return value is not + * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`. + */ public safeTransferFrom2 = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param _data Additional data with no specified format, sent in call to `_to` + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _from: string, _to: string, @@ -840,6 +1234,17 @@ export class ERC721TokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param _data Additional data with no specified format, sent in call to `_to` + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _from: string, _to: string, @@ -873,6 +1278,15 @@ export class ERC721TokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param _data Additional data with no specified format, sent in call to `_to` + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( _from: string, _to: string, @@ -908,6 +1322,15 @@ export class ERC721TokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param _data Additional data with no specified format, sent in call to `_to` + */ async callAsync( _from: string, _to: string, @@ -960,6 +1383,15 @@ export class ERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _from The current owner of the NFT + * @param _to The new owner + * @param _tokenId The NFT to transfer + * @param _data Additional data with no specified format, sent in call to `_to` + */ getABIEncodedTransactionData(_from: string, _to: string, _tokenId: BigNumber, _data: string): string { assert.isString('_from', _from); assert.isString('_to', _to); @@ -972,8 +1404,47 @@ export class ERC721TokenContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('safeTransferFrom(address,address,uint256,bytes)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('safeTransferFrom(address,address,uint256,bytes)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _from: string, + _to: string, + _tokenId: BigNumber, + _data: string, + txData?: Partial | undefined, + ): Promise { + await (this as any).safeTransferFrom2.callAsync(_from, _to, _tokenId, _data, txData); + const txHash = await (this as any).safeTransferFrom2.sendTransactionAsync( + _from, + _to, + _tokenId, + _data, + txData, + ); + return txHash; + }, }; public isApprovedForAll = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _owner The address that owns the NFTs + * @param _operator The address that acts on behalf of the owner + * @returns True if `_operator` is an approved operator for `_owner`, false otherwise + */ async callAsync( _owner: string, _operator: string, @@ -1020,6 +1491,13 @@ export class ERC721TokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _owner The address that owns the NFTs + * @param _operator The address that acts on behalf of the owner + */ getABIEncodedTransactionData(_owner: string, _operator: string): string { assert.isString('_owner', _owner); assert.isString('_operator', _operator); @@ -1030,11 +1508,27 @@ export class ERC721TokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as ERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('isApprovedForAll(address,address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as ERC721TokenContract; + const abiEncoder = self._lookupAbiEncoder('isApprovedForAll(address,address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + private readonly _subscriptionManager: SubscriptionManager; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, ): Promise { assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ schemas.addressSchema, @@ -1047,13 +1541,20 @@ export class ERC721TokenContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; - return ERC721TokenContract.deployAsync(bytecode, abi, provider, txDefaults); + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return ERC721TokenContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); } public static async deployAsync( bytecode: string, abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, ): Promise { assert.isHexString('bytecode', bytecode); assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ @@ -1077,7 +1578,12 @@ export class ERC721TokenContract extends BaseContract { logUtils.log(`transactionHash: ${txHash}`); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); logUtils.log(`ERC721Token successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new ERC721TokenContract(txReceipt.contractAddress as string, provider, txDefaults); + const contractInstance = new ERC721TokenContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); contractInstance.constructorArgs = []; return contractInstance; } @@ -1345,9 +1851,86 @@ export class ERC721TokenContract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('ERC721Token', ERC721TokenContract.ABI(), address, supportedProvider, txDefaults); + /** + * Subscribe to an event type emitted by the ERC721Token contract. + * @param eventName The ERC721Token contract event you would like to subscribe to. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` + * @param callback Callback that gets called when a log is added/removed + * @param isVerbose Enable verbose subscription warnings (e.g recoverable network issues encountered) + * @return Subscription token used later to unsubscribe + */ + public subscribe( + eventName: ERC721TokenEvents, + indexFilterValues: IndexedFilterValues, + callback: EventCallback, + isVerbose: boolean = false, + blockPollingIntervalMs?: number, + ): string { + assert.doesBelongToStringEnum('eventName', eventName, ERC721TokenEvents); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + assert.isFunction('callback', callback); + const subscriptionToken = this._subscriptionManager.subscribe( + this.address, + eventName, + indexFilterValues, + ERC721TokenContract.ABI(), + callback, + isVerbose, + blockPollingIntervalMs, + ); + return subscriptionToken; + } + /** + * Cancel a subscription + * @param subscriptionToken Subscription token returned by `subscribe()` + */ + public unsubscribe(subscriptionToken: string): void { + this._subscriptionManager.unsubscribe(subscriptionToken); + } + /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + this._subscriptionManager.unsubscribeAll(); + } + /** + * Gets historical logs without creating a subscription + * @param eventName The ERC721Token contract event you would like to subscribe to. + * @param blockRange Block range to get logs from. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` + * @return Array of logs that match the parameters + */ + public async getLogsAsync( + eventName: ERC721TokenEvents, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, + ): Promise>> { + assert.doesBelongToStringEnum('eventName', eventName, ERC721TokenEvents); + assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + const logs = await this._subscriptionManager.getLogsAsync( + this.address, + eventName, + blockRange, + indexFilterValues, + ERC721TokenContract.ABI(), + ); + return logs; + } + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super('ERC721Token', ERC721TokenContract.ABI(), address, supportedProvider, txDefaults, logDecodeDependencies); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); + this._subscriptionManager = new SubscriptionManager( + ERC721TokenContract.ABI(), + this._web3Wrapper, + ); } } diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/eth_balance_checker.ts b/packages/abi-gen-wrappers/src/generated-wrappers/eth_balance_checker.ts index edb8dae235..a638b24ca6 100644 --- a/packages/abi-gen-wrappers/src/generated-wrappers/eth_balance_checker.ts +++ b/packages/abi-gen-wrappers/src/generated-wrappers/eth_balance_checker.ts @@ -27,7 +27,17 @@ import * as ethers from 'ethers'; // tslint:disable:no-parameter-reassignment // tslint:disable-next-line:class-name export class EthBalanceCheckerContract extends BaseContract { + /** + * Batch fetches ETH balances + */ public getEthBalances = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param addresses Array of addresses. + * @returns Array of ETH balances. + */ async callAsync( addresses: string[], callData: Partial = {}, @@ -69,17 +79,38 @@ export class EthBalanceCheckerContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param addresses Array of addresses. + */ getABIEncodedTransactionData(addresses: string[]): string { assert.isArray('addresses', addresses); const self = (this as any) as EthBalanceCheckerContract; const abiEncodedTransactionData = self._strictEncodeArguments('getEthBalances(address[])', [addresses]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber[] { + const self = (this as any) as EthBalanceCheckerContract; + const abiEncoder = self._lookupAbiEncoder('getEthBalances(address[])'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber[] { + const self = (this as any) as EthBalanceCheckerContract; + const abiEncoder = self._lookupAbiEncoder('getEthBalances(address[])'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, ): Promise { assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ schemas.addressSchema, @@ -92,13 +123,20 @@ export class EthBalanceCheckerContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; - return EthBalanceCheckerContract.deployAsync(bytecode, abi, provider, txDefaults); + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return EthBalanceCheckerContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); } public static async deployAsync( bytecode: string, abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, ): Promise { assert.isHexString('bytecode', bytecode); assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ @@ -126,6 +164,7 @@ export class EthBalanceCheckerContract extends BaseContract { txReceipt.contractAddress as string, provider, txDefaults, + logDecodeDependencies, ); contractInstance.constructorArgs = []; return contractInstance; @@ -158,8 +197,20 @@ export class EthBalanceCheckerContract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('EthBalanceChecker', EthBalanceCheckerContract.ABI(), address, supportedProvider, txDefaults); + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super( + 'EthBalanceChecker', + EthBalanceCheckerContract.ABI(), + address, + supportedProvider, + txDefaults, + logDecodeDependencies, + ); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); } } diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/exchange.ts b/packages/abi-gen-wrappers/src/generated-wrappers/exchange.ts index f00695c6e8..1628d0d5a2 100644 --- a/packages/abi-gen-wrappers/src/generated-wrappers/exchange.ts +++ b/packages/abi-gen-wrappers/src/generated-wrappers/exchange.ts @@ -1,7 +1,14 @@ // tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma // tslint:disable:whitespace no-unbound-method no-trailing-whitespace // tslint:disable:no-unused-variable -import { BaseContract, PromiseWithTransactionHash } from '@0x/base-contract'; +import { + BaseContract, + BlockRange, + EventCallback, + IndexedFilterValues, + SubscriptionManager, + PromiseWithTransactionHash, +} from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { BlockParam, @@ -10,6 +17,7 @@ import { ContractAbi, ContractArtifact, DecodedLogArgs, + LogWithDecodedArgs, MethodAbi, TransactionReceiptWithDecodedLogs, TxData, @@ -83,6 +91,11 @@ export interface ExchangeAssetProxyRegisteredEventArgs extends DecodedLogArgs { // tslint:disable-next-line:class-name export class ExchangeContract extends BaseContract { public filled = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( index_0: string, callData: Partial = {}, @@ -124,14 +137,46 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: string): string { assert.isString('index_0', index_0); const self = (this as any) as ExchangeContract; const abiEncodedTransactionData = self._strictEncodeArguments('filled(bytes32)', [index_0]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('filled(bytes32)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('filled(bytes32)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Synchronously executes multiple calls of fillOrder. + */ public batchFillOrders = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param orders Array of order specifications. + * @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell + * in orders. + * @param signatures Proofs that orders have been created by makers. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( orders: Array<{ makerAddress: string; @@ -178,6 +223,17 @@ export class ExchangeContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param orders Array of order specifications. + * @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell + * in orders. + * @param signatures Proofs that orders have been created by makers. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( orders: Array<{ makerAddress: string; @@ -221,6 +277,15 @@ export class ExchangeContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param orders Array of order specifications. + * @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell + * in orders. + * @param signatures Proofs that orders have been created by makers. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( orders: Array<{ makerAddress: string; @@ -266,6 +331,16 @@ export class ExchangeContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param orders Array of order specifications. + * @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell + * in orders. + * @param signatures Proofs that orders have been created by makers. + * @returns Amounts filled and fees paid by makers and taker. NOTE: makerAssetFilledAmount and takerAssetFilledAmount may include amounts filled of different assets. + */ async callAsync( orders: Array<{ makerAddress: string; @@ -339,6 +414,15 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param orders Array of order specifications. + * @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell + * in orders. + * @param signatures Proofs that orders have been created by makers. + */ getABIEncodedTransactionData( orders: Array<{ makerAddress: string; @@ -367,8 +451,83 @@ export class ExchangeContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'batchFillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<{ + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'batchFillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<{ + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }>(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + orders: Array<{ + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }>, + takerAssetFillAmounts: BigNumber[], + signatures: string[], + txData?: Partial | undefined, + ): Promise { + await (this as any).batchFillOrders.callAsync(orders, takerAssetFillAmounts, signatures, txData); + const txHash = await (this as any).batchFillOrders.sendTransactionAsync( + orders, + takerAssetFillAmounts, + signatures, + txData, + ); + return txHash; + }, }; public cancelled = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( index_0: string, callData: Partial = {}, @@ -410,14 +569,45 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: string): string { assert.isString('index_0', index_0); const self = (this as any) as ExchangeContract; const abiEncodedTransactionData = self._strictEncodeArguments('cancelled(bytes32)', [index_0]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('cancelled(bytes32)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('cancelled(bytes32)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Approves a hash on-chain using any valid signature type. + * After presigning a hash, the preSign signature type will become valid for that hash and signer. + */ public preSign = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param signerAddress Address that should have signed the given hash. + * @param signature Proof that the hash has been signed by signer. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( hash: string, signerAddress: string, @@ -452,6 +642,15 @@ export class ExchangeContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param signerAddress Address that should have signed the given hash. + * @param signature Proof that the hash has been signed by signer. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( hash: string, signerAddress: string, @@ -482,6 +681,13 @@ export class ExchangeContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param signerAddress Address that should have signed the given hash. + * @param signature Proof that the hash has been signed by signer. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( hash: string, signerAddress: string, @@ -515,6 +721,13 @@ export class ExchangeContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param signerAddress Address that should have signed the given hash. + * @param signature Proof that the hash has been signed by signer. + */ async callAsync( hash: string, signerAddress: string, @@ -564,6 +777,13 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param signerAddress Address that should have signed the given hash. + * @param signature Proof that the hash has been signed by signer. + */ getABIEncodedTransactionData(hash: string, signerAddress: string, signature: string): string { assert.isString('hash', hash); assert.isString('signerAddress', signerAddress); @@ -576,8 +796,48 @@ export class ExchangeContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('preSign(bytes32,address,bytes)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('preSign(bytes32,address,bytes)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + hash: string, + signerAddress: string, + signature: string, + txData?: Partial | undefined, + ): Promise { + await (this as any).preSign.callAsync(hash, signerAddress, signature, txData); + const txHash = await (this as any).preSign.sendTransactionAsync(hash, signerAddress, signature, txData); + return txHash; + }, }; + /** + * Match two complementary orders that have a profitable spread. + * Each order is filled at their respective price point. However, the calculations are + * carried out as though the orders are both being filled at the right order's price point. + * The profit made by the left order goes to the taker (who matched the two orders). + */ public matchOrders = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param leftOrder First order to match. + * @param rightOrder Second order to match. + * @param leftSignature Proof that order was created by the left maker. + * @param rightSignature Proof that order was created by the right maker. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( leftOrder: { makerAddress: string; @@ -638,6 +898,17 @@ export class ExchangeContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param leftOrder First order to match. + * @param rightOrder Second order to match. + * @param leftSignature Proof that order was created by the left maker. + * @param rightSignature Proof that order was created by the right maker. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( leftOrder: { makerAddress: string; @@ -695,6 +966,15 @@ export class ExchangeContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param leftOrder First order to match. + * @param rightOrder Second order to match. + * @param leftSignature Proof that order was created by the left maker. + * @param rightSignature Proof that order was created by the right maker. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( leftOrder: { makerAddress: string; @@ -754,6 +1034,16 @@ export class ExchangeContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param leftOrder First order to match. + * @param rightOrder Second order to match. + * @param leftSignature Proof that order was created by the left maker. + * @param rightSignature Proof that order was created by the right maker. + * @returns matchedFillResults Amounts filled and fees paid by maker and taker of matched orders. + */ async callAsync( leftOrder: { makerAddress: string; @@ -858,6 +1148,15 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param leftOrder First order to match. + * @param rightOrder Second order to match. + * @param leftSignature Proof that order was created by the left maker. + * @param rightSignature Proof that order was created by the right maker. + */ getABIEncodedTransactionData( leftOrder: { makerAddress: string; @@ -899,8 +1198,142 @@ export class ExchangeContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): { + left: { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }; + right: { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }; + leftMakerAssetSpreadAmount: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'matchOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes,bytes)', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<{ + left: { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }; + right: { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }; + leftMakerAssetSpreadAmount: BigNumber; + }>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): { + left: { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }; + right: { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }; + leftMakerAssetSpreadAmount: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'matchOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes,bytes)', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<{ + left: { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }; + right: { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }; + leftMakerAssetSpreadAmount: BigNumber; + }>(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + leftOrder: { + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }, + rightOrder: { + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }, + leftSignature: string, + rightSignature: string, + txData?: Partial | undefined, + ): Promise { + await (this as any).matchOrders.callAsync(leftOrder, rightOrder, leftSignature, rightSignature, txData); + const txHash = await (this as any).matchOrders.sendTransactionAsync( + leftOrder, + rightOrder, + leftSignature, + rightSignature, + txData, + ); + return txHash; + }, }; + /** + * Fills the input order. + * Returns false if the transaction would otherwise revert. + */ public fillOrderNoThrow = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @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. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( order: { makerAddress: string; @@ -947,6 +1380,16 @@ export class ExchangeContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @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. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( order: { makerAddress: string; @@ -989,6 +1432,14 @@ export class ExchangeContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @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. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( order: { makerAddress: string; @@ -1034,6 +1485,15 @@ export class ExchangeContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @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. + * @returns Amounts filled and fees paid by maker and taker. + */ async callAsync( order: { makerAddress: string; @@ -1106,6 +1566,14 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @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. + */ getABIEncodedTransactionData( order: { makerAddress: string; @@ -1133,8 +1601,83 @@ export class ExchangeContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'fillOrderNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<{ + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'fillOrderNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<{ + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }>(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + order: { + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }, + takerAssetFillAmount: BigNumber, + signature: string, + txData?: Partial | undefined, + ): Promise { + await (this as any).fillOrderNoThrow.callAsync(order, takerAssetFillAmount, signature, txData); + const txHash = await (this as any).fillOrderNoThrow.sendTransactionAsync( + order, + takerAssetFillAmount, + signature, + txData, + ); + return txHash; + }, }; public assetProxies = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(index_0: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isString('index_0', index_0); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -1172,14 +1715,43 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: string): string { assert.isString('index_0', index_0); const self = (this as any) as ExchangeContract; const abiEncodedTransactionData = self._strictEncodeArguments('assetProxies(bytes4)', [index_0]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('assetProxies(bytes4)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('assetProxies(bytes4)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Synchronously cancels multiple orders in a single transaction. + */ public batchCancelOrders = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param orders Array of order specifications. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( orders: Array<{ makerAddress: string; @@ -1224,6 +1796,14 @@ export class ExchangeContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param orders Array of order specifications. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( orders: Array<{ makerAddress: string; @@ -1258,6 +1838,12 @@ export class ExchangeContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param orders Array of order specifications. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( orders: Array<{ makerAddress: string; @@ -1301,6 +1887,12 @@ export class ExchangeContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param orders Array of order specifications. + */ async callAsync( orders: Array<{ makerAddress: string; @@ -1360,6 +1952,12 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param orders Array of order specifications. + */ getABIEncodedTransactionData( orders: Array<{ makerAddress: string; @@ -1384,8 +1982,60 @@ export class ExchangeContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'batchCancelOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'batchCancelOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + orders: Array<{ + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }>, + txData?: Partial | undefined, + ): Promise { + await (this as any).batchCancelOrders.callAsync(orders, txData); + const txHash = await (this as any).batchCancelOrders.sendTransactionAsync(orders, txData); + return txHash; + }, }; + /** + * Synchronously executes multiple calls of fillOrKill. + */ public batchFillOrKillOrders = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param orders Array of order specifications. + * @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell + * in orders. + * @param signatures Proofs that orders have been created by makers. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( orders: Array<{ makerAddress: string; @@ -1432,6 +2082,17 @@ export class ExchangeContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param orders Array of order specifications. + * @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell + * in orders. + * @param signatures Proofs that orders have been created by makers. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( orders: Array<{ makerAddress: string; @@ -1475,6 +2136,15 @@ export class ExchangeContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param orders Array of order specifications. + * @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell + * in orders. + * @param signatures Proofs that orders have been created by makers. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( orders: Array<{ makerAddress: string; @@ -1520,6 +2190,16 @@ export class ExchangeContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param orders Array of order specifications. + * @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell + * in orders. + * @param signatures Proofs that orders have been created by makers. + * @returns Amounts filled and fees paid by makers and taker. NOTE: makerAssetFilledAmount and takerAssetFilledAmount may include amounts filled of different assets. + */ async callAsync( orders: Array<{ makerAddress: string; @@ -1593,6 +2273,15 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param orders Array of order specifications. + * @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell + * in orders. + * @param signatures Proofs that orders have been created by makers. + */ getABIEncodedTransactionData( orders: Array<{ makerAddress: string; @@ -1621,8 +2310,90 @@ export class ExchangeContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'batchFillOrKillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<{ + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'batchFillOrKillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<{ + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }>(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + orders: Array<{ + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }>, + takerAssetFillAmounts: BigNumber[], + signatures: string[], + txData?: Partial | undefined, + ): Promise { + await (this as any).batchFillOrKillOrders.callAsync(orders, takerAssetFillAmounts, signatures, txData); + const txHash = await (this as any).batchFillOrKillOrders.sendTransactionAsync( + orders, + takerAssetFillAmounts, + signatures, + txData, + ); + return txHash; + }, }; + /** + * Cancels all orders created by makerAddress with a salt less than or equal to the targetOrderEpoch + * and senderAddress equal to msg.sender (or null address if msg.sender == makerAddress). + */ public cancelOrdersUpTo = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param targetOrderEpoch Orders created with a salt less or equal to this + * value will be cancelled. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(targetOrderEpoch: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as ExchangeContract; const encodedData = self._strictEncodeArguments('cancelOrdersUpTo(uint256)', [targetOrderEpoch]); @@ -1648,6 +2419,15 @@ export class ExchangeContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param targetOrderEpoch Orders created with a salt less or equal to this + * value will be cancelled. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( targetOrderEpoch: BigNumber, txData?: Partial, @@ -1669,6 +2449,13 @@ export class ExchangeContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param targetOrderEpoch Orders created with a salt less or equal to this + * value will be cancelled. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(targetOrderEpoch: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as ExchangeContract; const encodedData = self._strictEncodeArguments('cancelOrdersUpTo(uint256)', [targetOrderEpoch]); @@ -1693,6 +2480,13 @@ export class ExchangeContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param targetOrderEpoch Orders created with a salt less or equal to this + * value will be cancelled. + */ async callAsync( targetOrderEpoch: BigNumber, callData: Partial = {}, @@ -1734,6 +2528,13 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param targetOrderEpoch Orders created with a salt less or equal to this + * value will be cancelled. + */ getABIEncodedTransactionData(targetOrderEpoch: BigNumber): string { assert.isBigNumber('targetOrderEpoch', targetOrderEpoch); const self = (this as any) as ExchangeContract; @@ -1742,8 +2543,44 @@ export class ExchangeContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('cancelOrdersUpTo(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('cancelOrdersUpTo(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + targetOrderEpoch: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).cancelOrdersUpTo.callAsync(targetOrderEpoch, txData); + const txHash = await (this as any).cancelOrdersUpTo.sendTransactionAsync(targetOrderEpoch, txData); + return txHash; + }, }; + /** + * Fills an order with specified parameters and ECDSA signature. + * Returns false if the transaction would otherwise revert. + */ public batchFillOrdersNoThrow = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param orders Array of order specifications. + * @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell + * in orders. + * @param signatures Proofs that orders have been created by makers. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( orders: Array<{ makerAddress: string; @@ -1790,6 +2627,17 @@ export class ExchangeContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param orders Array of order specifications. + * @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell + * in orders. + * @param signatures Proofs that orders have been created by makers. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( orders: Array<{ makerAddress: string; @@ -1833,6 +2681,15 @@ export class ExchangeContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param orders Array of order specifications. + * @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell + * in orders. + * @param signatures Proofs that orders have been created by makers. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( orders: Array<{ makerAddress: string; @@ -1878,6 +2735,16 @@ export class ExchangeContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param orders Array of order specifications. + * @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell + * in orders. + * @param signatures Proofs that orders have been created by makers. + * @returns Amounts filled and fees paid by makers and taker. NOTE: makerAssetFilledAmount and takerAssetFilledAmount may include amounts filled of different assets. + */ async callAsync( orders: Array<{ makerAddress: string; @@ -1951,6 +2818,15 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param orders Array of order specifications. + * @param takerAssetFillAmounts Array of desired amounts of takerAsset to sell + * in orders. + * @param signatures Proofs that orders have been created by makers. + */ getABIEncodedTransactionData( orders: Array<{ makerAddress: string; @@ -1979,8 +2855,88 @@ export class ExchangeContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'batchFillOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<{ + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'batchFillOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<{ + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }>(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + orders: Array<{ + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }>, + takerAssetFillAmounts: BigNumber[], + signatures: string[], + txData?: Partial | undefined, + ): Promise { + await (this as any).batchFillOrdersNoThrow.callAsync(orders, takerAssetFillAmounts, signatures, txData); + const txHash = await (this as any).batchFillOrdersNoThrow.sendTransactionAsync( + orders, + takerAssetFillAmounts, + signatures, + txData, + ); + return txHash; + }, }; + /** + * Gets an asset proxy. + */ public getAssetProxy = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param assetProxyId Id of the asset proxy. + * @returns The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered. + */ async callAsync( assetProxyId: string, callData: Partial = {}, @@ -2022,14 +2978,39 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param assetProxyId Id of the asset proxy. + */ getABIEncodedTransactionData(assetProxyId: string): string { assert.isString('assetProxyId', assetProxyId); const self = (this as any) as ExchangeContract; const abiEncodedTransactionData = self._strictEncodeArguments('getAssetProxy(bytes4)', [assetProxyId]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('getAssetProxy(bytes4)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('getAssetProxy(bytes4)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public transactions = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( index_0: string, callData: Partial = {}, @@ -2071,14 +3052,45 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: string): string { assert.isString('index_0', index_0); const self = (this as any) as ExchangeContract; const abiEncodedTransactionData = self._strictEncodeArguments('transactions(bytes32)', [index_0]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('transactions(bytes32)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('transactions(bytes32)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Fills the input order. Reverts if exact takerAssetFillAmount not filled. + */ public fillOrKillOrder = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @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. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( order: { makerAddress: string; @@ -2125,6 +3137,16 @@ export class ExchangeContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @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. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( order: { makerAddress: string; @@ -2167,6 +3189,14 @@ export class ExchangeContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @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. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( order: { makerAddress: string; @@ -2212,6 +3242,14 @@ export class ExchangeContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @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. + */ async callAsync( order: { makerAddress: string; @@ -2284,6 +3322,14 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @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. + */ getABIEncodedTransactionData( order: { makerAddress: string; @@ -2311,8 +3357,89 @@ export class ExchangeContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'fillOrKillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<{ + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'fillOrKillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<{ + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }>(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + order: { + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }, + takerAssetFillAmount: BigNumber, + signature: string, + txData?: Partial | undefined, + ): Promise { + await (this as any).fillOrKillOrder.callAsync(order, takerAssetFillAmount, signature, txData); + const txHash = await (this as any).fillOrKillOrder.sendTransactionAsync( + order, + takerAssetFillAmount, + signature, + txData, + ); + return txHash; + }, }; + /** + * Approves/unnapproves a Validator contract to verify signatures on signer's behalf. + */ public setSignatureValidatorApproval = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param validatorAddress Address of Validator contract. + * @param approval Approval or disapproval of Validator contract. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( validatorAddress: string, approval: boolean, @@ -2345,6 +3472,15 @@ export class ExchangeContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param validatorAddress Address of Validator contract. + * @param approval Approval or disapproval of Validator contract. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( validatorAddress: string, approval: boolean, @@ -2372,6 +3508,13 @@ export class ExchangeContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param validatorAddress Address of Validator contract. + * @param approval Approval or disapproval of Validator contract. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( validatorAddress: string, approval: boolean, @@ -2403,6 +3546,13 @@ export class ExchangeContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param validatorAddress Address of Validator contract. + * @param approval Approval or disapproval of Validator contract. + */ async callAsync( validatorAddress: string, approval: boolean, @@ -2449,6 +3599,13 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param validatorAddress Address of Validator contract. + * @param approval Approval or disapproval of Validator contract. + */ getABIEncodedTransactionData(validatorAddress: string, approval: boolean): string { assert.isString('validatorAddress', validatorAddress); assert.isBoolean('approval', approval); @@ -2459,8 +3616,40 @@ export class ExchangeContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('setSignatureValidatorApproval(address,bool)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('setSignatureValidatorApproval(address,bool)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + validatorAddress: string, + approval: boolean, + txData?: Partial | undefined, + ): Promise { + await (this as any).setSignatureValidatorApproval.callAsync(validatorAddress, approval, txData); + const txHash = await (this as any).setSignatureValidatorApproval.sendTransactionAsync( + validatorAddress, + approval, + txData, + ); + return txHash; + }, }; public allowedValidators = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( index_0: string, index_1: string, @@ -2507,6 +3696,11 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: string, index_1: string): string { assert.isString('index_0', index_0); assert.isString('index_1', index_1); @@ -2517,8 +3711,34 @@ export class ExchangeContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('allowedValidators(address,address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('allowedValidators(address,address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker. + */ public marketSellOrders = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param orders Array of order specifications. + * @param takerAssetFillAmount Desired amount of takerAsset to sell. + * @param signatures Proofs that orders have been created by makers. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( orders: Array<{ makerAddress: string; @@ -2565,6 +3785,16 @@ export class ExchangeContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param orders Array of order specifications. + * @param takerAssetFillAmount Desired amount of takerAsset to sell. + * @param signatures Proofs that orders have been created by makers. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( orders: Array<{ makerAddress: string; @@ -2608,6 +3838,14 @@ export class ExchangeContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param orders Array of order specifications. + * @param takerAssetFillAmount Desired amount of takerAsset to sell. + * @param signatures Proofs that orders have been created by makers. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( orders: Array<{ makerAddress: string; @@ -2653,6 +3891,15 @@ export class ExchangeContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param orders Array of order specifications. + * @param takerAssetFillAmount Desired amount of takerAsset to sell. + * @param signatures Proofs that orders have been created by makers. + * @returns Amounts filled and fees paid by makers and taker. + */ async callAsync( orders: Array<{ makerAddress: string; @@ -2726,6 +3973,14 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param orders Array of order specifications. + * @param takerAssetFillAmount Desired amount of takerAsset to sell. + * @param signatures Proofs that orders have been created by makers. + */ getABIEncodedTransactionData( orders: Array<{ makerAddress: string; @@ -2754,8 +4009,88 @@ export class ExchangeContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'marketSellOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<{ + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'marketSellOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<{ + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }>(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + orders: Array<{ + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }>, + takerAssetFillAmount: BigNumber, + signatures: string[], + txData?: Partial | undefined, + ): Promise { + await (this as any).marketSellOrders.callAsync(orders, takerAssetFillAmount, signatures, txData); + const txHash = await (this as any).marketSellOrders.sendTransactionAsync( + orders, + takerAssetFillAmount, + signatures, + txData, + ); + return txHash; + }, }; + /** + * Fetches information for all passed in orders. + */ public getOrdersInfo = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param orders Array of order specifications. + * @returns Array of OrderInfo instances that correspond to each order. + */ async callAsync( orders: Array<{ makerAddress: string; @@ -2817,6 +4152,12 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param orders Array of order specifications. + */ getABIEncodedTransactionData( orders: Array<{ makerAddress: string; @@ -2841,8 +4182,39 @@ export class ExchangeContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): Array<{ orderStatus: number; orderHash: string; orderTakerAssetFilledAmount: BigNumber }> { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'getOrdersInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode< + Array<{ orderStatus: number; orderHash: string; orderTakerAssetFilledAmount: BigNumber }> + >(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): Array<{ orderStatus: number; orderHash: string; orderTakerAssetFilledAmount: BigNumber }> { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'getOrdersInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue< + Array<{ orderStatus: number; orderHash: string; orderTakerAssetFilledAmount: BigNumber }> + >(returnData); + return abiDecodedReturnData; + }, }; public preSigned = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( index_0: string, index_1: string, @@ -2889,6 +4261,11 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: string, index_1: string): string { assert.isString('index_0', index_0); assert.isString('index_1', index_1); @@ -2899,8 +4276,27 @@ export class ExchangeContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('preSigned(bytes32,address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('preSigned(bytes32,address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public owner = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -2937,13 +4333,44 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as ExchangeContract; const abiEncodedTransactionData = self._strictEncodeArguments('owner()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('owner()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('owner()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Verifies that a hash has been signed by the given signer. + */ public isValidSignature = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @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. + * @returns True if the address recovered from the provided signature matches the input signer address. + */ async callAsync( hash: string, signerAddress: string, @@ -2993,6 +4420,14 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @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. + */ getABIEncodedTransactionData(hash: string, signerAddress: string, signature: string): string { assert.isString('hash', hash); assert.isString('signerAddress', signerAddress); @@ -3005,8 +4440,35 @@ export class ExchangeContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('isValidSignature(bytes32,address,bytes)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('isValidSignature(bytes32,address,bytes)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Synchronously executes multiple fill orders in a single transaction until total amount is bought by taker. + * Returns false if the transaction would otherwise revert. + */ public marketBuyOrdersNoThrow = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param orders Array of order specifications. + * @param makerAssetFillAmount Desired amount of makerAsset to buy. + * @param signatures Proofs that orders have been signed by makers. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( orders: Array<{ makerAddress: string; @@ -3053,6 +4515,16 @@ export class ExchangeContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param orders Array of order specifications. + * @param makerAssetFillAmount Desired amount of makerAsset to buy. + * @param signatures Proofs that orders have been signed by makers. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( orders: Array<{ makerAddress: string; @@ -3096,6 +4568,14 @@ export class ExchangeContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param orders Array of order specifications. + * @param makerAssetFillAmount Desired amount of makerAsset to buy. + * @param signatures Proofs that orders have been signed by makers. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( orders: Array<{ makerAddress: string; @@ -3141,6 +4621,15 @@ export class ExchangeContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param orders Array of order specifications. + * @param makerAssetFillAmount Desired amount of makerAsset to buy. + * @param signatures Proofs that orders have been signed by makers. + * @returns Amounts filled and fees paid by makers and taker. + */ async callAsync( orders: Array<{ makerAddress: string; @@ -3214,6 +4703,14 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param orders Array of order specifications. + * @param makerAssetFillAmount Desired amount of makerAsset to buy. + * @param signatures Proofs that orders have been signed by makers. + */ getABIEncodedTransactionData( orders: Array<{ makerAddress: string; @@ -3242,8 +4739,90 @@ export class ExchangeContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'marketBuyOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<{ + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'marketBuyOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<{ + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }>(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + orders: Array<{ + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }>, + makerAssetFillAmount: BigNumber, + signatures: string[], + txData?: Partial | undefined, + ): Promise { + await (this as any).marketBuyOrdersNoThrow.callAsync(orders, makerAssetFillAmount, signatures, txData); + const txHash = await (this as any).marketBuyOrdersNoThrow.sendTransactionAsync( + orders, + makerAssetFillAmount, + signatures, + txData, + ); + return txHash; + }, }; + /** + * Fills the input order. + */ public fillOrder = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @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. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( order: { makerAddress: string; @@ -3290,6 +4869,16 @@ export class ExchangeContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @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. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( order: { makerAddress: string; @@ -3327,6 +4916,14 @@ export class ExchangeContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @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. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( order: { makerAddress: string; @@ -3372,6 +4969,15 @@ export class ExchangeContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @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. + * @returns Amounts filled and fees paid by maker and taker. + */ async callAsync( order: { makerAddress: string; @@ -3444,6 +5050,14 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @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. + */ getABIEncodedTransactionData( order: { makerAddress: string; @@ -3471,8 +5085,91 @@ export class ExchangeContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<{ + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<{ + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }>(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + order: { + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }, + takerAssetFillAmount: BigNumber, + signature: string, + txData?: Partial | undefined, + ): Promise { + await (this as any).fillOrder.callAsync(order, takerAssetFillAmount, signature, txData); + const txHash = await (this as any).fillOrder.sendTransactionAsync( + order, + takerAssetFillAmount, + signature, + txData, + ); + return txHash; + }, }; + /** + * Executes an exchange method call in the context of signer. + */ public executeTransaction = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param salt Arbitrary number to ensure uniqueness of transaction hash. + * @param signerAddress Address of transaction signer. + * @param data AbiV2 encoded calldata. + * @param signature Proof of signer transaction by signer. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( salt: BigNumber, signerAddress: string, @@ -3509,6 +5206,17 @@ export class ExchangeContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param salt Arbitrary number to ensure uniqueness of transaction hash. + * @param signerAddress Address of transaction signer. + * @param data AbiV2 encoded calldata. + * @param signature Proof of signer transaction by signer. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( salt: BigNumber, signerAddress: string, @@ -3542,6 +5250,15 @@ export class ExchangeContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param salt Arbitrary number to ensure uniqueness of transaction hash. + * @param signerAddress Address of transaction signer. + * @param data AbiV2 encoded calldata. + * @param signature Proof of signer transaction by signer. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( salt: BigNumber, signerAddress: string, @@ -3577,6 +5294,15 @@ export class ExchangeContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param salt Arbitrary number to ensure uniqueness of transaction hash. + * @param signerAddress Address of transaction signer. + * @param data AbiV2 encoded calldata. + * @param signature Proof of signer transaction by signer. + */ async callAsync( salt: BigNumber, signerAddress: string, @@ -3629,6 +5355,15 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param salt Arbitrary number to ensure uniqueness of transaction hash. + * @param signerAddress Address of transaction signer. + * @param data AbiV2 encoded calldata. + * @param signature Proof of signer transaction by signer. + */ getABIEncodedTransactionData(salt: BigNumber, signerAddress: string, data: string, signature: string): string { assert.isBigNumber('salt', salt); assert.isString('signerAddress', signerAddress); @@ -3641,8 +5376,50 @@ export class ExchangeContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('executeTransaction(uint256,address,bytes,bytes)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('executeTransaction(uint256,address,bytes,bytes)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + salt: BigNumber, + signerAddress: string, + data: string, + signature: string, + txData?: Partial | undefined, + ): Promise { + await (this as any).executeTransaction.callAsync(salt, signerAddress, data, signature, txData); + const txHash = await (this as any).executeTransaction.sendTransactionAsync( + salt, + signerAddress, + data, + signature, + txData, + ); + return txHash; + }, }; + /** + * Registers an asset proxy to its asset proxy id. + * Once an asset proxy is registered, it cannot be unregistered. + */ public registerAssetProxy = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param assetProxy Address of new asset proxy to register. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(assetProxy: string, txData?: Partial | undefined): Promise { const self = (this as any) as ExchangeContract; const encodedData = self._strictEncodeArguments('registerAssetProxy(address)', [assetProxy]); @@ -3668,6 +5445,14 @@ export class ExchangeContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param assetProxy Address of new asset proxy to register. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( assetProxy: string, txData?: Partial, @@ -3689,6 +5474,12 @@ export class ExchangeContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param assetProxy Address of new asset proxy to register. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(assetProxy: string, txData?: Partial | undefined): Promise { const self = (this as any) as ExchangeContract; const encodedData = self._strictEncodeArguments('registerAssetProxy(address)', [assetProxy]); @@ -3713,6 +5504,12 @@ export class ExchangeContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param assetProxy Address of new asset proxy to register. + */ async callAsync( assetProxy: string, callData: Partial = {}, @@ -3754,6 +5551,12 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param assetProxy Address of new asset proxy to register. + */ getABIEncodedTransactionData(assetProxy: string): string { assert.isString('assetProxy', assetProxy); const self = (this as any) as ExchangeContract; @@ -3762,8 +5565,40 @@ export class ExchangeContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('registerAssetProxy(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('registerAssetProxy(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + assetProxy: string, + txData?: Partial | undefined, + ): Promise { + await (this as any).registerAssetProxy.callAsync(assetProxy, txData); + const txHash = await (this as any).registerAssetProxy.sendTransactionAsync(assetProxy, txData); + return txHash; + }, }; + /** + * Gets information about an order: status, hash, and amount filled. + */ public getOrderInfo = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param order Order to gather information on. + * @returns OrderInfo Information about the order and its state. See LibOrder.OrderInfo for a complete description. + */ async callAsync( order: { makerAddress: string; @@ -3826,6 +5661,12 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param order Order to gather information on. + */ getABIEncodedTransactionData(order: { makerAddress: string; takerAddress: string; @@ -3847,8 +5688,49 @@ export class ExchangeContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): { orderStatus: number; orderHash: string; orderTakerAssetFilledAmount: BigNumber } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'getOrderInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<{ + orderStatus: number; + orderHash: string; + orderTakerAssetFilledAmount: BigNumber; + }>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): { orderStatus: number; orderHash: string; orderTakerAssetFilledAmount: BigNumber } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'getOrderInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<{ + orderStatus: number; + orderHash: string; + orderTakerAssetFilledAmount: BigNumber; + }>(returnData); + return abiDecodedReturnData; + }, }; + /** + * After calling, the order can not be filled anymore. + * Throws if order is invalid or sender does not have permission to cancel. + */ public cancelOrder = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param order Order to cancel. Order must be OrderStatus.FILLABLE. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( order: { makerAddress: string; @@ -3893,6 +5775,14 @@ export class ExchangeContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param order Order to cancel. Order must be OrderStatus.FILLABLE. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( order: { makerAddress: string; @@ -3926,6 +5816,12 @@ export class ExchangeContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param order Order to cancel. Order must be OrderStatus.FILLABLE. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( order: { makerAddress: string; @@ -3969,6 +5865,12 @@ export class ExchangeContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param order Order to cancel. Order must be OrderStatus.FILLABLE. + */ async callAsync( order: { makerAddress: string; @@ -4027,6 +5929,12 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param order Order to cancel. Order must be OrderStatus.FILLABLE. + */ getABIEncodedTransactionData(order: { makerAddress: string; takerAddress: string; @@ -4048,8 +5956,52 @@ export class ExchangeContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'cancelOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'cancelOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + order: { + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }, + txData?: Partial | undefined, + ): Promise { + await (this as any).cancelOrder.callAsync(order, txData); + const txHash = await (this as any).cancelOrder.sendTransactionAsync(order, txData); + return txHash; + }, }; public orderEpoch = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( index_0: string, index_1: string, @@ -4096,6 +6048,11 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: string, index_1: string): string { assert.isString('index_0', index_0); assert.isString('index_1', index_1); @@ -4106,8 +6063,27 @@ export class ExchangeContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('orderEpoch(address,address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('orderEpoch(address,address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public ZRX_ASSET_DATA = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -4144,13 +6120,45 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as ExchangeContract; const abiEncodedTransactionData = self._strictEncodeArguments('ZRX_ASSET_DATA()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('ZRX_ASSET_DATA()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('ZRX_ASSET_DATA()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Synchronously executes multiple calls of fillOrder until total amount of takerAsset is sold by taker. + * Returns false if the transaction would otherwise revert. + */ public marketSellOrdersNoThrow = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param orders Array of order specifications. + * @param takerAssetFillAmount Desired amount of takerAsset to sell. + * @param signatures Proofs that orders have been signed by makers. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( orders: Array<{ makerAddress: string; @@ -4197,6 +6205,16 @@ export class ExchangeContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param orders Array of order specifications. + * @param takerAssetFillAmount Desired amount of takerAsset to sell. + * @param signatures Proofs that orders have been signed by makers. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( orders: Array<{ makerAddress: string; @@ -4240,6 +6258,14 @@ export class ExchangeContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param orders Array of order specifications. + * @param takerAssetFillAmount Desired amount of takerAsset to sell. + * @param signatures Proofs that orders have been signed by makers. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( orders: Array<{ makerAddress: string; @@ -4285,6 +6311,15 @@ export class ExchangeContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param orders Array of order specifications. + * @param takerAssetFillAmount Desired amount of takerAsset to sell. + * @param signatures Proofs that orders have been signed by makers. + * @returns Amounts filled and fees paid by makers and taker. + */ async callAsync( orders: Array<{ makerAddress: string; @@ -4358,6 +6393,14 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param orders Array of order specifications. + * @param takerAssetFillAmount Desired amount of takerAsset to sell. + * @param signatures Proofs that orders have been signed by makers. + */ getABIEncodedTransactionData( orders: Array<{ makerAddress: string; @@ -4386,8 +6429,83 @@ export class ExchangeContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'marketSellOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<{ + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'marketSellOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<{ + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }>(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + orders: Array<{ + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }>, + takerAssetFillAmount: BigNumber, + signatures: string[], + txData?: Partial | undefined, + ): Promise { + await (this as any).marketSellOrdersNoThrow.callAsync(orders, takerAssetFillAmount, signatures, txData); + const txHash = await (this as any).marketSellOrdersNoThrow.sendTransactionAsync( + orders, + takerAssetFillAmount, + signatures, + txData, + ); + return txHash; + }, }; public EIP712_DOMAIN_HASH = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -4424,13 +6542,44 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as ExchangeContract; const abiEncodedTransactionData = self._strictEncodeArguments('EIP712_DOMAIN_HASH()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('EIP712_DOMAIN_HASH()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('EIP712_DOMAIN_HASH()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Synchronously executes multiple calls of fillOrder until total amount of makerAsset is bought by taker. + */ public marketBuyOrders = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param orders Array of order specifications. + * @param makerAssetFillAmount Desired amount of makerAsset to buy. + * @param signatures Proofs that orders have been signed by makers. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( orders: Array<{ makerAddress: string; @@ -4477,6 +6626,16 @@ export class ExchangeContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param orders Array of order specifications. + * @param makerAssetFillAmount Desired amount of makerAsset to buy. + * @param signatures Proofs that orders have been signed by makers. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( orders: Array<{ makerAddress: string; @@ -4520,6 +6679,14 @@ export class ExchangeContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param orders Array of order specifications. + * @param makerAssetFillAmount Desired amount of makerAsset to buy. + * @param signatures Proofs that orders have been signed by makers. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( orders: Array<{ makerAddress: string; @@ -4565,6 +6732,15 @@ export class ExchangeContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param orders Array of order specifications. + * @param makerAssetFillAmount Desired amount of makerAsset to buy. + * @param signatures Proofs that orders have been signed by makers. + * @returns Amounts filled and fees paid by makers and taker. + */ async callAsync( orders: Array<{ makerAddress: string; @@ -4638,6 +6814,14 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param orders Array of order specifications. + * @param makerAssetFillAmount Desired amount of makerAsset to buy. + * @param signatures Proofs that orders have been signed by makers. + */ getABIEncodedTransactionData( orders: Array<{ makerAddress: string; @@ -4666,8 +6850,83 @@ export class ExchangeContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'marketBuyOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<{ + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder( + 'marketBuyOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<{ + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }>(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + orders: Array<{ + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }>, + makerAssetFillAmount: BigNumber, + signatures: string[], + txData?: Partial | undefined, + ): Promise { + await (this as any).marketBuyOrders.callAsync(orders, makerAssetFillAmount, signatures, txData); + const txHash = await (this as any).marketBuyOrders.sendTransactionAsync( + orders, + makerAssetFillAmount, + signatures, + txData, + ); + return txHash; + }, }; public currentContextAddress = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -4704,13 +6963,38 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as ExchangeContract; const abiEncodedTransactionData = self._strictEncodeArguments('currentContextAddress()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('currentContextAddress()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('currentContextAddress()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public transferOwnership = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(newOwner: string, txData?: Partial | undefined): Promise { const self = (this as any) as ExchangeContract; const encodedData = self._strictEncodeArguments('transferOwnership(address)', [newOwner]); @@ -4736,6 +7020,13 @@ export class ExchangeContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( newOwner: string, txData?: Partial, @@ -4757,6 +7048,11 @@ export class ExchangeContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(newOwner: string, txData?: Partial | undefined): Promise { const self = (this as any) as ExchangeContract; const encodedData = self._strictEncodeArguments('transferOwnership(address)', [newOwner]); @@ -4781,6 +7077,11 @@ export class ExchangeContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(newOwner: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isString('newOwner', newOwner); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -4818,6 +7119,11 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(newOwner: string): string { assert.isString('newOwner', newOwner); const self = (this as any) as ExchangeContract; @@ -4826,8 +7132,32 @@ export class ExchangeContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('transferOwnership(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('transferOwnership(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(newOwner: string, txData?: Partial | undefined): Promise { + await (this as any).transferOwnership.callAsync(newOwner, txData); + const txHash = await (this as any).transferOwnership.sendTransactionAsync(newOwner, txData); + return txHash; + }, }; public VERSION = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -4864,16 +7194,37 @@ export class ExchangeContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as ExchangeContract; const abiEncodedTransactionData = self._strictEncodeArguments('VERSION()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('VERSION()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as ExchangeContract; + const abiEncoder = self._lookupAbiEncoder('VERSION()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + private readonly _subscriptionManager: SubscriptionManager; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, _zrxAssetData: string, ): Promise { assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ @@ -4887,13 +7238,27 @@ export class ExchangeContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; - return ExchangeContract.deployAsync(bytecode, abi, provider, txDefaults, _zrxAssetData); + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return ExchangeContract.deployAsync( + bytecode, + abi, + provider, + txDefaults, + logDecodeDependenciesAbiOnly, + _zrxAssetData, + ); } public static async deployAsync( bytecode: string, abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, _zrxAssetData: string, ): Promise { assert.isHexString('bytecode', bytecode); @@ -4922,7 +7287,12 @@ export class ExchangeContract extends BaseContract { logUtils.log(`transactionHash: ${txHash}`); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); logUtils.log(`Exchange successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new ExchangeContract(txReceipt.contractAddress as string, provider, txDefaults); + const contractInstance = new ExchangeContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); contractInstance.constructorArgs = [_zrxAssetData]; return contractInstance; } @@ -6906,9 +9276,86 @@ export class ExchangeContract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('Exchange', ExchangeContract.ABI(), address, supportedProvider, txDefaults); + /** + * Subscribe to an event type emitted by the Exchange contract. + * @param eventName The Exchange contract event you would like to subscribe to. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` + * @param callback Callback that gets called when a log is added/removed + * @param isVerbose Enable verbose subscription warnings (e.g recoverable network issues encountered) + * @return Subscription token used later to unsubscribe + */ + public subscribe( + eventName: ExchangeEvents, + indexFilterValues: IndexedFilterValues, + callback: EventCallback, + isVerbose: boolean = false, + blockPollingIntervalMs?: number, + ): string { + assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + assert.isFunction('callback', callback); + const subscriptionToken = this._subscriptionManager.subscribe( + this.address, + eventName, + indexFilterValues, + ExchangeContract.ABI(), + callback, + isVerbose, + blockPollingIntervalMs, + ); + return subscriptionToken; + } + /** + * Cancel a subscription + * @param subscriptionToken Subscription token returned by `subscribe()` + */ + public unsubscribe(subscriptionToken: string): void { + this._subscriptionManager.unsubscribe(subscriptionToken); + } + /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + this._subscriptionManager.unsubscribeAll(); + } + /** + * Gets historical logs without creating a subscription + * @param eventName The Exchange contract event you would like to subscribe to. + * @param blockRange Block range to get logs from. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` + * @return Array of logs that match the parameters + */ + public async getLogsAsync( + eventName: ExchangeEvents, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, + ): Promise>> { + assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents); + assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + const logs = await this._subscriptionManager.getLogsAsync( + this.address, + eventName, + blockRange, + indexFilterValues, + ExchangeContract.ABI(), + ); + return logs; + } + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super('Exchange', ExchangeContract.ABI(), address, supportedProvider, txDefaults, logDecodeDependencies); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); + this._subscriptionManager = new SubscriptionManager( + ExchangeContract.ABI(), + this._web3Wrapper, + ); } } diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/forwarder.ts b/packages/abi-gen-wrappers/src/generated-wrappers/forwarder.ts index 842d2ea229..1c04a104bc 100644 --- a/packages/abi-gen-wrappers/src/generated-wrappers/forwarder.ts +++ b/packages/abi-gen-wrappers/src/generated-wrappers/forwarder.ts @@ -27,7 +27,28 @@ import * as ethers from 'ethers'; // tslint:disable:no-parameter-reassignment // tslint:disable-next-line:class-name export class ForwarderContract extends BaseContract { + /** + * Attempt to purchase makerAssetFillAmount of makerAsset by selling ETH provided with transaction. + * Any ZRX required to pay fees for primary orders will automatically be purchased by this contract. + * Any ETH not spent will be refunded to sender. + */ public marketBuyOrdersWithEth = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param orders Array of order specifications used containing desired + * makerAsset and WETH as takerAsset. + * @param makerAssetFillAmount Desired amount of makerAsset to purchase. + * @param signatures Proofs that orders have been created by makers. + * @param feeOrders Array of order specifications containing ZRX as makerAsset + * and WETH as takerAsset. Used to purchase ZRX for primary order fees. + * @param feeSignatures Proofs that feeOrders have been created by makers. + * @param feePercentage Percentage of WETH sold that will payed as fee to + * forwarding contract feeRecipient. + * @param feeRecipient Address that will receive ETH when orders are filled. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( orders: Array<{ makerAddress: string; @@ -100,6 +121,23 @@ export class ForwarderContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param orders Array of order specifications used containing desired + * makerAsset and WETH as takerAsset. + * @param makerAssetFillAmount Desired amount of makerAsset to purchase. + * @param signatures Proofs that orders have been created by makers. + * @param feeOrders Array of order specifications containing ZRX as makerAsset + * and WETH as takerAsset. Used to purchase ZRX for primary order fees. + * @param feeSignatures Proofs that feeOrders have been created by makers. + * @param feePercentage Percentage of WETH sold that will payed as fee to + * forwarding contract feeRecipient. + * @param feeRecipient Address that will receive ETH when orders are filled. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( orders: Array<{ makerAddress: string; @@ -168,6 +206,21 @@ export class ForwarderContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param orders Array of order specifications used containing desired + * makerAsset and WETH as takerAsset. + * @param makerAssetFillAmount Desired amount of makerAsset to purchase. + * @param signatures Proofs that orders have been created by makers. + * @param feeOrders Array of order specifications containing ZRX as makerAsset + * and WETH as takerAsset. Used to purchase ZRX for primary order fees. + * @param feeSignatures Proofs that feeOrders have been created by makers. + * @param feePercentage Percentage of WETH sold that will payed as fee to + * forwarding contract feeRecipient. + * @param feeRecipient Address that will receive ETH when orders are filled. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( orders: Array<{ makerAddress: string; @@ -230,6 +283,22 @@ export class ForwarderContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param orders Array of order specifications used containing desired + * makerAsset and WETH as takerAsset. + * @param makerAssetFillAmount Desired amount of makerAsset to purchase. + * @param signatures Proofs that orders have been created by makers. + * @param feeOrders Array of order specifications containing ZRX as makerAsset + * and WETH as takerAsset. Used to purchase ZRX for primary order fees. + * @param feeSignatures Proofs that feeOrders have been created by makers. + * @param feePercentage Percentage of WETH sold that will payed as fee to + * forwarding contract feeRecipient. + * @param feeRecipient Address that will receive ETH when orders are filled. + * @returns Amounts filled and fees paid by maker and taker for both sets of orders. + */ async callAsync( orders: Array<{ makerAddress: string; @@ -352,6 +421,21 @@ export class ForwarderContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param orders Array of order specifications used containing desired + * makerAsset and WETH as takerAsset. + * @param makerAssetFillAmount Desired amount of makerAsset to purchase. + * @param signatures Proofs that orders have been created by makers. + * @param feeOrders Array of order specifications containing ZRX as makerAsset + * and WETH as takerAsset. Used to purchase ZRX for primary order fees. + * @param feeSignatures Proofs that feeOrders have been created by makers. + * @param feePercentage Percentage of WETH sold that will payed as fee to + * forwarding contract feeRecipient. + * @param feeRecipient Address that will receive ETH when orders are filled. + */ getABIEncodedTransactionData( orders: Array<{ makerAddress: string; @@ -409,8 +493,157 @@ export class ForwarderContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): [ + { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }, + { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } + ] { + const self = (this as any) as ForwarderContract; + const abiEncoder = self._lookupAbiEncoder( + 'marketBuyOrdersWithEth((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[],(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],bytes[],uint256,address)', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode< + [ + { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }, + { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } + ] + >(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): [ + { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }, + { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } + ] { + const self = (this as any) as ForwarderContract; + const abiEncoder = self._lookupAbiEncoder( + 'marketBuyOrdersWithEth((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[],(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],bytes[],uint256,address)', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue< + [ + { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }, + { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } + ] + >(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + orders: Array<{ + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }>, + makerAssetFillAmount: BigNumber, + signatures: string[], + feeOrders: Array<{ + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }>, + feeSignatures: string[], + feePercentage: BigNumber, + feeRecipient: string, + txData?: Partial | undefined, + ): Promise { + await (this as any).marketBuyOrdersWithEth.callAsync( + orders, + makerAssetFillAmount, + signatures, + feeOrders, + feeSignatures, + feePercentage, + feeRecipient, + txData, + ); + const txHash = await (this as any).marketBuyOrdersWithEth.sendTransactionAsync( + orders, + makerAssetFillAmount, + signatures, + feeOrders, + feeSignatures, + feePercentage, + feeRecipient, + txData, + ); + return txHash; + }, }; + /** + * Withdraws assets from this contract. The contract requires a ZRX balance in order to + * function optimally, and this function allows the ZRX to be withdrawn by owner. It may also be + * used to withdraw assets that were accidentally sent to this contract. + */ public withdrawAsset = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param assetData Byte array encoded for the respective asset proxy. + * @param amount Amount of ERC20 token to withdraw. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( assetData: string, amount: BigNumber, @@ -440,6 +673,15 @@ export class ForwarderContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param assetData Byte array encoded for the respective asset proxy. + * @param amount Amount of ERC20 token to withdraw. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( assetData: string, amount: BigNumber, @@ -463,6 +705,13 @@ export class ForwarderContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param assetData Byte array encoded for the respective asset proxy. + * @param amount Amount of ERC20 token to withdraw. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( assetData: string, amount: BigNumber, @@ -491,6 +740,13 @@ export class ForwarderContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param assetData Byte array encoded for the respective asset proxy. + * @param amount Amount of ERC20 token to withdraw. + */ async callAsync( assetData: string, amount: BigNumber, @@ -534,6 +790,13 @@ export class ForwarderContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param assetData Byte array encoded for the respective asset proxy. + * @param amount Amount of ERC20 token to withdraw. + */ getABIEncodedTransactionData(assetData: string, amount: BigNumber): string { assert.isString('assetData', assetData); assert.isBigNumber('amount', amount); @@ -544,8 +807,36 @@ export class ForwarderContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ForwarderContract; + const abiEncoder = self._lookupAbiEncoder('withdrawAsset(bytes,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ForwarderContract; + const abiEncoder = self._lookupAbiEncoder('withdrawAsset(bytes,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + assetData: string, + amount: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).withdrawAsset.callAsync(assetData, amount, txData); + const txHash = await (this as any).withdrawAsset.sendTransactionAsync(assetData, amount, txData); + return txHash; + }, }; public owner = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -582,13 +873,53 @@ export class ForwarderContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as ForwarderContract; const abiEncodedTransactionData = self._strictEncodeArguments('owner()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as ForwarderContract; + const abiEncoder = self._lookupAbiEncoder('owner()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as ForwarderContract; + const abiEncoder = self._lookupAbiEncoder('owner()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Purchases as much of orders' makerAssets as possible by selling up to 95% of transaction's ETH value. + * Any ZRX required to pay fees for primary orders will automatically be purchased by this contract. + * 5% of ETH value is reserved for paying fees to order feeRecipients (in ZRX) and forwarding contract feeRecipient (in ETH). + * Any ETH not spent will be refunded to sender. + */ public marketSellOrdersWithEth = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param orders Array of order specifications used containing desired + * makerAsset and WETH as takerAsset. + * @param signatures Proofs that orders have been created by makers. + * @param feeOrders Array of order specifications containing ZRX as makerAsset + * and WETH as takerAsset. Used to purchase ZRX for primary order fees. + * @param feeSignatures Proofs that feeOrders have been created by makers. + * @param feePercentage Percentage of WETH sold that will payed as fee to + * forwarding contract feeRecipient. + * @param feeRecipient Address that will receive ETH when orders are filled. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( orders: Array<{ makerAddress: string; @@ -659,6 +990,22 @@ export class ForwarderContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param orders Array of order specifications used containing desired + * makerAsset and WETH as takerAsset. + * @param signatures Proofs that orders have been created by makers. + * @param feeOrders Array of order specifications containing ZRX as makerAsset + * and WETH as takerAsset. Used to purchase ZRX for primary order fees. + * @param feeSignatures Proofs that feeOrders have been created by makers. + * @param feePercentage Percentage of WETH sold that will payed as fee to + * forwarding contract feeRecipient. + * @param feeRecipient Address that will receive ETH when orders are filled. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( orders: Array<{ makerAddress: string; @@ -724,6 +1071,20 @@ export class ForwarderContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param orders Array of order specifications used containing desired + * makerAsset and WETH as takerAsset. + * @param signatures Proofs that orders have been created by makers. + * @param feeOrders Array of order specifications containing ZRX as makerAsset + * and WETH as takerAsset. Used to purchase ZRX for primary order fees. + * @param feeSignatures Proofs that feeOrders have been created by makers. + * @param feePercentage Percentage of WETH sold that will payed as fee to + * forwarding contract feeRecipient. + * @param feeRecipient Address that will receive ETH when orders are filled. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( orders: Array<{ makerAddress: string; @@ -785,6 +1146,21 @@ export class ForwarderContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param orders Array of order specifications used containing desired + * makerAsset and WETH as takerAsset. + * @param signatures Proofs that orders have been created by makers. + * @param feeOrders Array of order specifications containing ZRX as makerAsset + * and WETH as takerAsset. Used to purchase ZRX for primary order fees. + * @param feeSignatures Proofs that feeOrders have been created by makers. + * @param feePercentage Percentage of WETH sold that will payed as fee to + * forwarding contract feeRecipient. + * @param feeRecipient Address that will receive ETH when orders are filled. + * @returns Amounts filled and fees paid by maker and taker for both sets of orders. + */ async callAsync( orders: Array<{ makerAddress: string; @@ -897,6 +1273,20 @@ export class ForwarderContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param orders Array of order specifications used containing desired + * makerAsset and WETH as takerAsset. + * @param signatures Proofs that orders have been created by makers. + * @param feeOrders Array of order specifications containing ZRX as makerAsset + * and WETH as takerAsset. Used to purchase ZRX for primary order fees. + * @param feeSignatures Proofs that feeOrders have been created by makers. + * @param feePercentage Percentage of WETH sold that will payed as fee to + * forwarding contract feeRecipient. + * @param feeRecipient Address that will receive ETH when orders are filled. + */ getABIEncodedTransactionData( orders: Array<{ makerAddress: string; @@ -944,8 +1334,147 @@ export class ForwarderContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): [ + { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }, + { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } + ] { + const self = (this as any) as ForwarderContract; + const abiEncoder = self._lookupAbiEncoder( + 'marketSellOrdersWithEth((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],bytes[],(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],bytes[],uint256,address)', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode< + [ + { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }, + { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } + ] + >(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): [ + { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }, + { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } + ] { + const self = (this as any) as ForwarderContract; + const abiEncoder = self._lookupAbiEncoder( + 'marketSellOrdersWithEth((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],bytes[],(address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],bytes[],uint256,address)', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue< + [ + { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + }, + { + makerAssetFilledAmount: BigNumber; + takerAssetFilledAmount: BigNumber; + makerFeePaid: BigNumber; + takerFeePaid: BigNumber; + } + ] + >(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + orders: Array<{ + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }>, + signatures: string[], + feeOrders: Array<{ + makerAddress: string; + takerAddress: string; + feeRecipientAddress: string; + senderAddress: string; + makerAssetAmount: BigNumber; + takerAssetAmount: BigNumber; + makerFee: BigNumber; + takerFee: BigNumber; + expirationTimeSeconds: BigNumber; + salt: BigNumber; + makerAssetData: string; + takerAssetData: string; + }>, + feeSignatures: string[], + feePercentage: BigNumber, + feeRecipient: string, + txData?: Partial | undefined, + ): Promise { + await (this as any).marketSellOrdersWithEth.callAsync( + orders, + signatures, + feeOrders, + feeSignatures, + feePercentage, + feeRecipient, + txData, + ); + const txHash = await (this as any).marketSellOrdersWithEth.sendTransactionAsync( + orders, + signatures, + feeOrders, + feeSignatures, + feePercentage, + feeRecipient, + txData, + ); + return txHash; + }, }; public transferOwnership = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(newOwner: string, txData?: Partial | undefined): Promise { const self = (this as any) as ForwarderContract; const encodedData = self._strictEncodeArguments('transferOwnership(address)', [newOwner]); @@ -971,6 +1500,13 @@ export class ForwarderContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( newOwner: string, txData?: Partial, @@ -992,6 +1528,11 @@ export class ForwarderContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(newOwner: string, txData?: Partial | undefined): Promise { const self = (this as any) as ForwarderContract; const encodedData = self._strictEncodeArguments('transferOwnership(address)', [newOwner]); @@ -1016,6 +1557,11 @@ export class ForwarderContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(newOwner: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isString('newOwner', newOwner); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -1053,6 +1599,11 @@ export class ForwarderContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(newOwner: string): string { assert.isString('newOwner', newOwner); const self = (this as any) as ForwarderContract; @@ -1061,11 +1612,31 @@ export class ForwarderContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as ForwarderContract; + const abiEncoder = self._lookupAbiEncoder('transferOwnership(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as ForwarderContract; + const abiEncoder = self._lookupAbiEncoder('transferOwnership(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(newOwner: string, txData?: Partial | undefined): Promise { + await (this as any).transferOwnership.callAsync(newOwner, txData); + const txHash = await (this as any).transferOwnership.sendTransactionAsync(newOwner, txData); + return txHash; + }, }; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, _exchange: string, _zrxAssetData: string, _wethAssetData: string, @@ -1081,11 +1652,18 @@ export class ForwarderContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } return ForwarderContract.deployAsync( bytecode, abi, provider, txDefaults, + logDecodeDependenciesAbiOnly, _exchange, _zrxAssetData, _wethAssetData, @@ -1096,6 +1674,7 @@ export class ForwarderContract extends BaseContract { abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, _exchange: string, _zrxAssetData: string, _wethAssetData: string, @@ -1126,7 +1705,12 @@ export class ForwarderContract extends BaseContract { logUtils.log(`transactionHash: ${txHash}`); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); logUtils.log(`Forwarder successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new ForwarderContract(txReceipt.contractAddress as string, provider, txDefaults); + const contractInstance = new ForwarderContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); contractInstance.constructorArgs = [_exchange, _zrxAssetData, _wethAssetData]; return contractInstance; } @@ -1574,8 +2158,13 @@ export class ForwarderContract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('Forwarder', ForwarderContract.ABI(), address, supportedProvider, txDefaults); + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super('Forwarder', ForwarderContract.ABI(), address, supportedProvider, txDefaults, logDecodeDependencies); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); } } diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/i_asset_proxy.ts b/packages/abi-gen-wrappers/src/generated-wrappers/i_asset_proxy.ts index cdbb2aaad7..526dea8b74 100644 --- a/packages/abi-gen-wrappers/src/generated-wrappers/i_asset_proxy.ts +++ b/packages/abi-gen-wrappers/src/generated-wrappers/i_asset_proxy.ts @@ -27,7 +27,17 @@ import * as ethers from 'ethers'; // tslint:disable:no-parameter-reassignment // tslint:disable-next-line:class-name export class IAssetProxyContract extends BaseContract { + /** + * Authorizes an address. + */ public addAuthorizedAddress = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param target Address to authorize. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(target: string, txData?: Partial | undefined): Promise { const self = (this as any) as IAssetProxyContract; const encodedData = self._strictEncodeArguments('addAuthorizedAddress(address)', [target]); @@ -53,6 +63,14 @@ export class IAssetProxyContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param target Address to authorize. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( target: string, txData?: Partial, @@ -74,6 +92,12 @@ export class IAssetProxyContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param target Address to authorize. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(target: string, txData?: Partial | undefined): Promise { const self = (this as any) as IAssetProxyContract; const encodedData = self._strictEncodeArguments('addAuthorizedAddress(address)', [target]); @@ -98,6 +122,12 @@ export class IAssetProxyContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param target Address to authorize. + */ async callAsync(target: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isString('target', target); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -135,6 +165,12 @@ export class IAssetProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param target Address to authorize. + */ getABIEncodedTransactionData(target: string): string { assert.isString('target', target); const self = (this as any) as IAssetProxyContract; @@ -143,8 +179,37 @@ export class IAssetProxyContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as IAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('addAuthorizedAddress(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as IAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('addAuthorizedAddress(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(target: string, txData?: Partial | undefined): Promise { + await (this as any).addAuthorizedAddress.callAsync(target, txData); + const txHash = await (this as any).addAuthorizedAddress.sendTransactionAsync(target, txData); + return txHash; + }, }; + /** + * Removes authorizion of an address. + */ public removeAuthorizedAddress = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param target Address to remove authorization from. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(target: string, txData?: Partial | undefined): Promise { const self = (this as any) as IAssetProxyContract; const encodedData = self._strictEncodeArguments('removeAuthorizedAddress(address)', [target]); @@ -170,6 +235,14 @@ export class IAssetProxyContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param target Address to remove authorization from. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( target: string, txData?: Partial, @@ -191,6 +264,12 @@ export class IAssetProxyContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param target Address to remove authorization from. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(target: string, txData?: Partial | undefined): Promise { const self = (this as any) as IAssetProxyContract; const encodedData = self._strictEncodeArguments('removeAuthorizedAddress(address)', [target]); @@ -215,6 +294,12 @@ export class IAssetProxyContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param target Address to remove authorization from. + */ async callAsync(target: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isString('target', target); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -252,6 +337,12 @@ export class IAssetProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param target Address to remove authorization from. + */ getABIEncodedTransactionData(target: string): string { assert.isString('target', target); const self = (this as any) as IAssetProxyContract; @@ -260,8 +351,38 @@ export class IAssetProxyContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as IAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('removeAuthorizedAddress(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as IAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('removeAuthorizedAddress(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(target: string, txData?: Partial | undefined): Promise { + await (this as any).removeAuthorizedAddress.callAsync(target, txData); + const txHash = await (this as any).removeAuthorizedAddress.sendTransactionAsync(target, txData); + return txHash; + }, }; + /** + * Removes authorizion of an address. + */ public removeAuthorizedAddressAtIndex = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param target Address to remove authorization from. + * @param index Index of target in authorities array. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( target: string, index: BigNumber, @@ -294,6 +415,15 @@ export class IAssetProxyContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param target Address to remove authorization from. + * @param index Index of target in authorities array. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( target: string, index: BigNumber, @@ -321,6 +451,13 @@ export class IAssetProxyContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param target Address to remove authorization from. + * @param index Index of target in authorities array. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( target: string, index: BigNumber, @@ -352,6 +489,13 @@ export class IAssetProxyContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param target Address to remove authorization from. + * @param index Index of target in authorities array. + */ async callAsync( target: string, index: BigNumber, @@ -398,6 +542,13 @@ export class IAssetProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param target Address to remove authorization from. + * @param index Index of target in authorities array. + */ getABIEncodedTransactionData(target: string, index: BigNumber): string { assert.isString('target', target); assert.isBigNumber('index', index); @@ -408,8 +559,48 @@ export class IAssetProxyContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as IAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('removeAuthorizedAddressAtIndex(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as IAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('removeAuthorizedAddressAtIndex(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + target: string, + index: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).removeAuthorizedAddressAtIndex.callAsync(target, index, txData); + const txHash = await (this as any).removeAuthorizedAddressAtIndex.sendTransactionAsync( + target, + index, + txData, + ); + return txHash; + }, }; + /** + * Transfers assets. Either succeeds or throws. + */ public transferFrom = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param assetData Byte array encoded for the respective asset proxy. + * @param from Address to transfer asset from. + * @param to Address to transfer asset to. + * @param amount Amount of asset to transfer. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( assetData: string, from: string, @@ -446,6 +637,17 @@ export class IAssetProxyContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param assetData Byte array encoded for the respective asset proxy. + * @param from Address to transfer asset from. + * @param to Address to transfer asset to. + * @param amount Amount of asset to transfer. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( assetData: string, from: string, @@ -479,6 +681,15 @@ export class IAssetProxyContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param assetData Byte array encoded for the respective asset proxy. + * @param from Address to transfer asset from. + * @param to Address to transfer asset to. + * @param amount Amount of asset to transfer. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( assetData: string, from: string, @@ -514,6 +725,15 @@ export class IAssetProxyContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param assetData Byte array encoded for the respective asset proxy. + * @param from Address to transfer asset from. + * @param to Address to transfer asset to. + * @param amount Amount of asset to transfer. + */ async callAsync( assetData: string, from: string, @@ -566,6 +786,15 @@ export class IAssetProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param assetData Byte array encoded for the respective asset proxy. + * @param from Address to transfer asset from. + * @param to Address to transfer asset to. + * @param amount Amount of asset to transfer. + */ getABIEncodedTransactionData(assetData: string, from: string, to: string, amount: BigNumber): string { assert.isString('assetData', assetData); assert.isString('from', from); @@ -578,8 +807,42 @@ export class IAssetProxyContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as IAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('transferFrom(bytes,address,address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as IAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('transferFrom(bytes,address,address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + assetData: string, + from: string, + to: string, + amount: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).transferFrom.callAsync(assetData, from, to, amount, txData); + const txHash = await (this as any).transferFrom.sendTransactionAsync(assetData, from, to, amount, txData); + return txHash; + }, }; + /** + * Gets the proxy id associated with the proxy address. + */ public getProxyId = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @returns Proxy id. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -616,13 +879,41 @@ export class IAssetProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as IAssetProxyContract; const abiEncodedTransactionData = self._strictEncodeArguments('getProxyId()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as IAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('getProxyId()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as IAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('getProxyId()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Gets all authorized addresses. + */ public getAuthorizedAddresses = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @returns Array of authorized addresses. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -659,13 +950,38 @@ export class IAssetProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as IAssetProxyContract; const abiEncodedTransactionData = self._strictEncodeArguments('getAuthorizedAddresses()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string[] { + const self = (this as any) as IAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('getAuthorizedAddresses()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string[] { + const self = (this as any) as IAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('getAuthorizedAddresses()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public transferOwnership = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(newOwner: string, txData?: Partial | undefined): Promise { const self = (this as any) as IAssetProxyContract; const encodedData = self._strictEncodeArguments('transferOwnership(address)', [newOwner]); @@ -691,6 +1007,13 @@ export class IAssetProxyContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( newOwner: string, txData?: Partial, @@ -712,6 +1035,11 @@ export class IAssetProxyContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(newOwner: string, txData?: Partial | undefined): Promise { const self = (this as any) as IAssetProxyContract; const encodedData = self._strictEncodeArguments('transferOwnership(address)', [newOwner]); @@ -736,6 +1064,11 @@ export class IAssetProxyContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(newOwner: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isString('newOwner', newOwner); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -773,6 +1106,11 @@ export class IAssetProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(newOwner: string): string { assert.isString('newOwner', newOwner); const self = (this as any) as IAssetProxyContract; @@ -781,11 +1119,31 @@ export class IAssetProxyContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as IAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('transferOwnership(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as IAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('transferOwnership(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(newOwner: string, txData?: Partial | undefined): Promise { + await (this as any).transferOwnership.callAsync(newOwner, txData); + const txHash = await (this as any).transferOwnership.sendTransactionAsync(newOwner, txData); + return txHash; + }, }; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, ): Promise { assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ schemas.addressSchema, @@ -798,13 +1156,20 @@ export class IAssetProxyContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; - return IAssetProxyContract.deployAsync(bytecode, abi, provider, txDefaults); + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return IAssetProxyContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); } public static async deployAsync( bytecode: string, abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, ): Promise { assert.isHexString('bytecode', bytecode); assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ @@ -828,7 +1193,12 @@ export class IAssetProxyContract extends BaseContract { logUtils.log(`transactionHash: ${txHash}`); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); logUtils.log(`IAssetProxy successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new IAssetProxyContract(txReceipt.contractAddress as string, provider, txDefaults); + const contractInstance = new IAssetProxyContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); contractInstance.constructorArgs = []; return contractInstance; } @@ -955,8 +1325,13 @@ export class IAssetProxyContract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('IAssetProxy', IAssetProxyContract.ABI(), address, supportedProvider, txDefaults); + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super('IAssetProxy', IAssetProxyContract.ABI(), address, supportedProvider, txDefaults, logDecodeDependencies); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); } } diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/i_validator.ts b/packages/abi-gen-wrappers/src/generated-wrappers/i_validator.ts index 3f73f313ae..a7959c75d1 100644 --- a/packages/abi-gen-wrappers/src/generated-wrappers/i_validator.ts +++ b/packages/abi-gen-wrappers/src/generated-wrappers/i_validator.ts @@ -27,7 +27,19 @@ import * as ethers from 'ethers'; // tslint:disable:no-parameter-reassignment // tslint:disable-next-line:class-name export class IValidatorContract extends BaseContract { + /** + * Verifies that a signature is valid. + */ public isValidSignature = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param hash Message hash that is signed. + * @param signerAddress Address that should have signed the given hash. + * @param signature Proof of signing. + * @returns Validity of order signature. + */ async callAsync( hash: string, signerAddress: string, @@ -77,6 +89,14 @@ export class IValidatorContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param hash Message hash that is signed. + * @param signerAddress Address that should have signed the given hash. + * @param signature Proof of signing. + */ getABIEncodedTransactionData(hash: string, signerAddress: string, signature: string): string { assert.isString('hash', hash); assert.isString('signerAddress', signerAddress); @@ -89,11 +109,26 @@ export class IValidatorContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as IValidatorContract; + const abiEncoder = self._lookupAbiEncoder('isValidSignature(bytes32,address,bytes)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as IValidatorContract; + const abiEncoder = self._lookupAbiEncoder('isValidSignature(bytes32,address,bytes)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, ): Promise { assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ schemas.addressSchema, @@ -106,13 +141,20 @@ export class IValidatorContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; - return IValidatorContract.deployAsync(bytecode, abi, provider, txDefaults); + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return IValidatorContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); } public static async deployAsync( bytecode: string, abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, ): Promise { assert.isHexString('bytecode', bytecode); assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ @@ -136,7 +178,12 @@ export class IValidatorContract extends BaseContract { logUtils.log(`transactionHash: ${txHash}`); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); logUtils.log(`IValidator successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new IValidatorContract(txReceipt.contractAddress as string, provider, txDefaults); + const contractInstance = new IValidatorContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); contractInstance.constructorArgs = []; return contractInstance; } @@ -176,8 +223,13 @@ export class IValidatorContract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('IValidator', IValidatorContract.ABI(), address, supportedProvider, txDefaults); + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super('IValidator', IValidatorContract.ABI(), address, supportedProvider, txDefaults, logDecodeDependencies); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); } } diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/i_wallet.ts b/packages/abi-gen-wrappers/src/generated-wrappers/i_wallet.ts index f54cfe1e56..ebe09ce694 100644 --- a/packages/abi-gen-wrappers/src/generated-wrappers/i_wallet.ts +++ b/packages/abi-gen-wrappers/src/generated-wrappers/i_wallet.ts @@ -27,7 +27,18 @@ import * as ethers from 'ethers'; // tslint:disable:no-parameter-reassignment // tslint:disable-next-line:class-name export class IWalletContract extends BaseContract { + /** + * Verifies that a signature is valid. + */ public isValidSignature = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param hash Message hash that is signed. + * @param signature Proof of signing. + * @returns Validity of order signature. + */ async callAsync( hash: string, signature: string, @@ -71,6 +82,13 @@ export class IWalletContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param hash Message hash that is signed. + * @param signature Proof of signing. + */ getABIEncodedTransactionData(hash: string, signature: string): string { assert.isString('hash', hash); assert.isString('signature', signature); @@ -81,11 +99,26 @@ export class IWalletContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as IWalletContract; + const abiEncoder = self._lookupAbiEncoder('isValidSignature(bytes32,bytes)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as IWalletContract; + const abiEncoder = self._lookupAbiEncoder('isValidSignature(bytes32,bytes)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, ): Promise { assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ schemas.addressSchema, @@ -98,13 +131,20 @@ export class IWalletContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; - return IWalletContract.deployAsync(bytecode, abi, provider, txDefaults); + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return IWalletContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); } public static async deployAsync( bytecode: string, abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, ): Promise { assert.isHexString('bytecode', bytecode); assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ @@ -128,7 +168,12 @@ export class IWalletContract extends BaseContract { logUtils.log(`transactionHash: ${txHash}`); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); logUtils.log(`IWallet successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new IWalletContract(txReceipt.contractAddress as string, provider, txDefaults); + const contractInstance = new IWalletContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); contractInstance.constructorArgs = []; return contractInstance; } @@ -164,8 +209,13 @@ export class IWalletContract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('IWallet', IWalletContract.ABI(), address, supportedProvider, txDefaults); + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super('IWallet', IWalletContract.ABI(), address, supportedProvider, txDefaults, logDecodeDependencies); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); } } diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/multi_asset_proxy.ts b/packages/abi-gen-wrappers/src/generated-wrappers/multi_asset_proxy.ts index 683156bddc..1dea615011 100644 --- a/packages/abi-gen-wrappers/src/generated-wrappers/multi_asset_proxy.ts +++ b/packages/abi-gen-wrappers/src/generated-wrappers/multi_asset_proxy.ts @@ -1,7 +1,14 @@ // tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma // tslint:disable:whitespace no-unbound-method no-trailing-whitespace // tslint:disable:no-unused-variable -import { BaseContract, PromiseWithTransactionHash } from '@0x/base-contract'; +import { + BaseContract, + BlockRange, + EventCallback, + IndexedFilterValues, + SubscriptionManager, + PromiseWithTransactionHash, +} from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { BlockParam, @@ -10,6 +17,7 @@ import { ContractAbi, ContractArtifact, DecodedLogArgs, + LogWithDecodedArgs, MethodAbi, TransactionReceiptWithDecodedLogs, TxData, @@ -54,6 +62,11 @@ export interface MultiAssetProxyAssetProxyRegisteredEventArgs extends DecodedLog // tslint:disable-next-line:class-name export class MultiAssetProxyContract extends BaseContract { public assetProxies = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(index_0: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isString('index_0', index_0); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -91,14 +104,43 @@ export class MultiAssetProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: string): string { assert.isString('index_0', index_0); const self = (this as any) as MultiAssetProxyContract; const abiEncodedTransactionData = self._strictEncodeArguments('assetProxies(bytes4)', [index_0]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('assetProxies(bytes4)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('assetProxies(bytes4)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Authorizes an address. + */ public addAuthorizedAddress = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param target Address to authorize. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(target: string, txData?: Partial | undefined): Promise { const self = (this as any) as MultiAssetProxyContract; const encodedData = self._strictEncodeArguments('addAuthorizedAddress(address)', [target]); @@ -124,6 +166,14 @@ export class MultiAssetProxyContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param target Address to authorize. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( target: string, txData?: Partial, @@ -145,6 +195,12 @@ export class MultiAssetProxyContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param target Address to authorize. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(target: string, txData?: Partial | undefined): Promise { const self = (this as any) as MultiAssetProxyContract; const encodedData = self._strictEncodeArguments('addAuthorizedAddress(address)', [target]); @@ -169,6 +225,12 @@ export class MultiAssetProxyContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param target Address to authorize. + */ async callAsync(target: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isString('target', target); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -206,6 +268,12 @@ export class MultiAssetProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param target Address to authorize. + */ getABIEncodedTransactionData(target: string): string { assert.isString('target', target); const self = (this as any) as MultiAssetProxyContract; @@ -214,8 +282,32 @@ export class MultiAssetProxyContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('addAuthorizedAddress(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('addAuthorizedAddress(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(target: string, txData?: Partial | undefined): Promise { + await (this as any).addAuthorizedAddress.callAsync(target, txData); + const txHash = await (this as any).addAuthorizedAddress.sendTransactionAsync(target, txData); + return txHash; + }, }; public authorities = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( index_0: BigNumber, callData: Partial = {}, @@ -257,14 +349,43 @@ export class MultiAssetProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: BigNumber): string { assert.isBigNumber('index_0', index_0); const self = (this as any) as MultiAssetProxyContract; const abiEncodedTransactionData = self._strictEncodeArguments('authorities(uint256)', [index_0]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('authorities(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('authorities(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Gets an asset proxy. + */ public getAssetProxy = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param assetProxyId Id of the asset proxy. + * @returns The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered. + */ async callAsync( assetProxyId: string, callData: Partial = {}, @@ -306,14 +427,44 @@ export class MultiAssetProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param assetProxyId Id of the asset proxy. + */ getABIEncodedTransactionData(assetProxyId: string): string { assert.isString('assetProxyId', assetProxyId); const self = (this as any) as MultiAssetProxyContract; const abiEncodedTransactionData = self._strictEncodeArguments('getAssetProxy(bytes4)', [assetProxyId]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('getAssetProxy(bytes4)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('getAssetProxy(bytes4)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Removes authorizion of an address. + */ public removeAuthorizedAddress = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param target Address to remove authorization from. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(target: string, txData?: Partial | undefined): Promise { const self = (this as any) as MultiAssetProxyContract; const encodedData = self._strictEncodeArguments('removeAuthorizedAddress(address)', [target]); @@ -339,6 +490,14 @@ export class MultiAssetProxyContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param target Address to remove authorization from. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( target: string, txData?: Partial, @@ -360,6 +519,12 @@ export class MultiAssetProxyContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param target Address to remove authorization from. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(target: string, txData?: Partial | undefined): Promise { const self = (this as any) as MultiAssetProxyContract; const encodedData = self._strictEncodeArguments('removeAuthorizedAddress(address)', [target]); @@ -384,6 +549,12 @@ export class MultiAssetProxyContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param target Address to remove authorization from. + */ async callAsync(target: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isString('target', target); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -421,6 +592,12 @@ export class MultiAssetProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param target Address to remove authorization from. + */ getABIEncodedTransactionData(target: string): string { assert.isString('target', target); const self = (this as any) as MultiAssetProxyContract; @@ -429,8 +606,32 @@ export class MultiAssetProxyContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('removeAuthorizedAddress(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('removeAuthorizedAddress(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(target: string, txData?: Partial | undefined): Promise { + await (this as any).removeAuthorizedAddress.callAsync(target, txData); + const txHash = await (this as any).removeAuthorizedAddress.sendTransactionAsync(target, txData); + return txHash; + }, }; public owner = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -467,13 +668,43 @@ export class MultiAssetProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as MultiAssetProxyContract; const abiEncodedTransactionData = self._strictEncodeArguments('owner()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('owner()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('owner()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Removes authorizion of an address. + */ public removeAuthorizedAddressAtIndex = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param target Address to remove authorization from. + * @param index Index of target in authorities array. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( target: string, index: BigNumber, @@ -506,6 +737,15 @@ export class MultiAssetProxyContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param target Address to remove authorization from. + * @param index Index of target in authorities array. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( target: string, index: BigNumber, @@ -533,6 +773,13 @@ export class MultiAssetProxyContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param target Address to remove authorization from. + * @param index Index of target in authorities array. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( target: string, index: BigNumber, @@ -564,6 +811,13 @@ export class MultiAssetProxyContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param target Address to remove authorization from. + * @param index Index of target in authorities array. + */ async callAsync( target: string, index: BigNumber, @@ -610,6 +864,13 @@ export class MultiAssetProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param target Address to remove authorization from. + * @param index Index of target in authorities array. + */ getABIEncodedTransactionData(target: string, index: BigNumber): string { assert.isString('target', target); assert.isBigNumber('index', index); @@ -620,8 +881,44 @@ export class MultiAssetProxyContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('removeAuthorizedAddressAtIndex(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('removeAuthorizedAddressAtIndex(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + target: string, + index: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).removeAuthorizedAddressAtIndex.callAsync(target, index, txData); + const txHash = await (this as any).removeAuthorizedAddressAtIndex.sendTransactionAsync( + target, + index, + txData, + ); + return txHash; + }, }; + /** + * Gets the proxy id associated with the proxy address. + */ public getProxyId = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @returns Proxy id. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -658,13 +955,37 @@ export class MultiAssetProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as MultiAssetProxyContract; const abiEncodedTransactionData = self._strictEncodeArguments('getProxyId()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('getProxyId()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('getProxyId()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public authorized = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( index_0: string, callData: Partial = {}, @@ -706,6 +1027,11 @@ export class MultiAssetProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: string): string { assert.isString('index_0', index_0); const self = (this as any) as MultiAssetProxyContract; @@ -714,8 +1040,33 @@ export class MultiAssetProxyContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('authorized(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('authorized(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Registers an asset proxy to its asset proxy id. + * Once an asset proxy is registered, it cannot be unregistered. + */ public registerAssetProxy = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param assetProxy Address of new asset proxy to register. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(assetProxy: string, txData?: Partial | undefined): Promise { const self = (this as any) as MultiAssetProxyContract; const encodedData = self._strictEncodeArguments('registerAssetProxy(address)', [assetProxy]); @@ -741,6 +1092,14 @@ export class MultiAssetProxyContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param assetProxy Address of new asset proxy to register. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( assetProxy: string, txData?: Partial, @@ -762,6 +1121,12 @@ export class MultiAssetProxyContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param assetProxy Address of new asset proxy to register. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(assetProxy: string, txData?: Partial | undefined): Promise { const self = (this as any) as MultiAssetProxyContract; const encodedData = self._strictEncodeArguments('registerAssetProxy(address)', [assetProxy]); @@ -786,6 +1151,12 @@ export class MultiAssetProxyContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param assetProxy Address of new asset proxy to register. + */ async callAsync( assetProxy: string, callData: Partial = {}, @@ -827,6 +1198,12 @@ export class MultiAssetProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param assetProxy Address of new asset proxy to register. + */ getABIEncodedTransactionData(assetProxy: string): string { assert.isString('assetProxy', assetProxy); const self = (this as any) as MultiAssetProxyContract; @@ -835,8 +1212,39 @@ export class MultiAssetProxyContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('registerAssetProxy(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('registerAssetProxy(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + assetProxy: string, + txData?: Partial | undefined, + ): Promise { + await (this as any).registerAssetProxy.callAsync(assetProxy, txData); + const txHash = await (this as any).registerAssetProxy.sendTransactionAsync(assetProxy, txData); + return txHash; + }, }; + /** + * Gets all authorized addresses. + */ public getAuthorizedAddresses = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @returns Array of authorized addresses. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -873,13 +1281,38 @@ export class MultiAssetProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as MultiAssetProxyContract; const abiEncodedTransactionData = self._strictEncodeArguments('getAuthorizedAddresses()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string[] { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('getAuthorizedAddresses()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string[] { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('getAuthorizedAddresses()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public transferOwnership = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(newOwner: string, txData?: Partial | undefined): Promise { const self = (this as any) as MultiAssetProxyContract; const encodedData = self._strictEncodeArguments('transferOwnership(address)', [newOwner]); @@ -905,6 +1338,13 @@ export class MultiAssetProxyContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( newOwner: string, txData?: Partial, @@ -926,6 +1366,11 @@ export class MultiAssetProxyContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(newOwner: string, txData?: Partial | undefined): Promise { const self = (this as any) as MultiAssetProxyContract; const encodedData = self._strictEncodeArguments('transferOwnership(address)', [newOwner]); @@ -950,6 +1395,11 @@ export class MultiAssetProxyContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(newOwner: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isString('newOwner', newOwner); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -987,6 +1437,11 @@ export class MultiAssetProxyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(newOwner: string): string { assert.isString('newOwner', newOwner); const self = (this as any) as MultiAssetProxyContract; @@ -995,11 +1450,32 @@ export class MultiAssetProxyContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('transferOwnership(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as MultiAssetProxyContract; + const abiEncoder = self._lookupAbiEncoder('transferOwnership(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(newOwner: string, txData?: Partial | undefined): Promise { + await (this as any).transferOwnership.callAsync(newOwner, txData); + const txHash = await (this as any).transferOwnership.sendTransactionAsync(newOwner, txData); + return txHash; + }, }; + private readonly _subscriptionManager: SubscriptionManager; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, ): Promise { assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ schemas.addressSchema, @@ -1012,13 +1488,20 @@ export class MultiAssetProxyContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; - return MultiAssetProxyContract.deployAsync(bytecode, abi, provider, txDefaults); + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return MultiAssetProxyContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); } public static async deployAsync( bytecode: string, abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, ): Promise { assert.isHexString('bytecode', bytecode); assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ @@ -1042,7 +1525,12 @@ export class MultiAssetProxyContract extends BaseContract { logUtils.log(`transactionHash: ${txHash}`); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); logUtils.log(`MultiAssetProxy successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new MultiAssetProxyContract(txReceipt.contractAddress as string, provider, txDefaults); + const contractInstance = new MultiAssetProxyContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); contractInstance.constructorArgs = []; return contractInstance; } @@ -1308,9 +1796,93 @@ export class MultiAssetProxyContract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('MultiAssetProxy', MultiAssetProxyContract.ABI(), address, supportedProvider, txDefaults); + /** + * Subscribe to an event type emitted by the MultiAssetProxy contract. + * @param eventName The MultiAssetProxy contract event you would like to subscribe to. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` + * @param callback Callback that gets called when a log is added/removed + * @param isVerbose Enable verbose subscription warnings (e.g recoverable network issues encountered) + * @return Subscription token used later to unsubscribe + */ + public subscribe( + eventName: MultiAssetProxyEvents, + indexFilterValues: IndexedFilterValues, + callback: EventCallback, + isVerbose: boolean = false, + blockPollingIntervalMs?: number, + ): string { + assert.doesBelongToStringEnum('eventName', eventName, MultiAssetProxyEvents); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + assert.isFunction('callback', callback); + const subscriptionToken = this._subscriptionManager.subscribe( + this.address, + eventName, + indexFilterValues, + MultiAssetProxyContract.ABI(), + callback, + isVerbose, + blockPollingIntervalMs, + ); + return subscriptionToken; + } + /** + * Cancel a subscription + * @param subscriptionToken Subscription token returned by `subscribe()` + */ + public unsubscribe(subscriptionToken: string): void { + this._subscriptionManager.unsubscribe(subscriptionToken); + } + /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + this._subscriptionManager.unsubscribeAll(); + } + /** + * Gets historical logs without creating a subscription + * @param eventName The MultiAssetProxy contract event you would like to subscribe to. + * @param blockRange Block range to get logs from. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` + * @return Array of logs that match the parameters + */ + public async getLogsAsync( + eventName: MultiAssetProxyEvents, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, + ): Promise>> { + assert.doesBelongToStringEnum('eventName', eventName, MultiAssetProxyEvents); + assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + const logs = await this._subscriptionManager.getLogsAsync( + this.address, + eventName, + blockRange, + indexFilterValues, + MultiAssetProxyContract.ABI(), + ); + return logs; + } + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super( + 'MultiAssetProxy', + MultiAssetProxyContract.ABI(), + address, + supportedProvider, + txDefaults, + logDecodeDependencies, + ); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); + this._subscriptionManager = new SubscriptionManager( + MultiAssetProxyContract.ABI(), + this._web3Wrapper, + ); } } diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/order_validator.ts b/packages/abi-gen-wrappers/src/generated-wrappers/order_validator.ts index d39582be81..2d561e1252 100644 --- a/packages/abi-gen-wrappers/src/generated-wrappers/order_validator.ts +++ b/packages/abi-gen-wrappers/src/generated-wrappers/order_validator.ts @@ -28,6 +28,11 @@ import * as ethers from 'ethers'; // tslint:disable-next-line:class-name export class OrderValidatorContract extends BaseContract { public getOrderAndTraderInfo = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( order: { makerAddress: string; @@ -116,6 +121,11 @@ export class OrderValidatorContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData( order: { makerAddress: string; @@ -141,8 +151,87 @@ export class OrderValidatorContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): [ + { orderStatus: number; orderHash: string; orderTakerAssetFilledAmount: BigNumber }, + { + makerBalance: BigNumber; + makerAllowance: BigNumber; + takerBalance: BigNumber; + takerAllowance: BigNumber; + makerZrxBalance: BigNumber; + makerZrxAllowance: BigNumber; + takerZrxBalance: BigNumber; + takerZrxAllowance: BigNumber; + } + ] { + const self = (this as any) as OrderValidatorContract; + const abiEncoder = self._lookupAbiEncoder( + 'getOrderAndTraderInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),address)', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode< + [ + { orderStatus: number; orderHash: string; orderTakerAssetFilledAmount: BigNumber }, + { + makerBalance: BigNumber; + makerAllowance: BigNumber; + takerBalance: BigNumber; + takerAllowance: BigNumber; + makerZrxBalance: BigNumber; + makerZrxAllowance: BigNumber; + takerZrxBalance: BigNumber; + takerZrxAllowance: BigNumber; + } + ] + >(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): [ + { orderStatus: number; orderHash: string; orderTakerAssetFilledAmount: BigNumber }, + { + makerBalance: BigNumber; + makerAllowance: BigNumber; + takerBalance: BigNumber; + takerAllowance: BigNumber; + makerZrxBalance: BigNumber; + makerZrxAllowance: BigNumber; + takerZrxBalance: BigNumber; + takerZrxAllowance: BigNumber; + } + ] { + const self = (this as any) as OrderValidatorContract; + const abiEncoder = self._lookupAbiEncoder( + 'getOrderAndTraderInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),address)', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue< + [ + { orderStatus: number; orderHash: string; orderTakerAssetFilledAmount: BigNumber }, + { + makerBalance: BigNumber; + makerAllowance: BigNumber; + takerBalance: BigNumber; + takerAllowance: BigNumber; + makerZrxBalance: BigNumber; + makerZrxAllowance: BigNumber; + takerZrxBalance: BigNumber; + takerZrxAllowance: BigNumber; + } + ] + >(returnData); + return abiDecodedReturnData; + }, }; public getBalanceAndAllowance = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( target: string, assetData: string, @@ -189,6 +278,11 @@ export class OrderValidatorContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(target: string, assetData: string): string { assert.isString('target', target); assert.isString('assetData', assetData); @@ -199,8 +293,27 @@ export class OrderValidatorContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): [BigNumber, BigNumber] { + const self = (this as any) as OrderValidatorContract; + const abiEncoder = self._lookupAbiEncoder('getBalanceAndAllowance(address,bytes)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<[BigNumber, BigNumber]>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): [BigNumber, BigNumber] { + const self = (this as any) as OrderValidatorContract; + const abiEncoder = self._lookupAbiEncoder('getBalanceAndAllowance(address,bytes)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<[BigNumber, BigNumber]>(returnData); + return abiDecodedReturnData; + }, }; public getOrdersAndTradersInfo = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( orders: Array<{ makerAddress: string; @@ -290,6 +403,11 @@ export class OrderValidatorContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData( orders: Array<{ makerAddress: string; @@ -316,8 +434,87 @@ export class OrderValidatorContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): [ + Array<{ orderStatus: number; orderHash: string; orderTakerAssetFilledAmount: BigNumber }>, + Array<{ + makerBalance: BigNumber; + makerAllowance: BigNumber; + takerBalance: BigNumber; + takerAllowance: BigNumber; + makerZrxBalance: BigNumber; + makerZrxAllowance: BigNumber; + takerZrxBalance: BigNumber; + takerZrxAllowance: BigNumber; + }> + ] { + const self = (this as any) as OrderValidatorContract; + const abiEncoder = self._lookupAbiEncoder( + 'getOrdersAndTradersInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],address[])', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode< + [ + Array<{ orderStatus: number; orderHash: string; orderTakerAssetFilledAmount: BigNumber }>, + Array<{ + makerBalance: BigNumber; + makerAllowance: BigNumber; + takerBalance: BigNumber; + takerAllowance: BigNumber; + makerZrxBalance: BigNumber; + makerZrxAllowance: BigNumber; + takerZrxBalance: BigNumber; + takerZrxAllowance: BigNumber; + }> + ] + >(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): [ + Array<{ orderStatus: number; orderHash: string; orderTakerAssetFilledAmount: BigNumber }>, + Array<{ + makerBalance: BigNumber; + makerAllowance: BigNumber; + takerBalance: BigNumber; + takerAllowance: BigNumber; + makerZrxBalance: BigNumber; + makerZrxAllowance: BigNumber; + takerZrxBalance: BigNumber; + takerZrxAllowance: BigNumber; + }> + ] { + const self = (this as any) as OrderValidatorContract; + const abiEncoder = self._lookupAbiEncoder( + 'getOrdersAndTradersInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],address[])', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue< + [ + Array<{ orderStatus: number; orderHash: string; orderTakerAssetFilledAmount: BigNumber }>, + Array<{ + makerBalance: BigNumber; + makerAllowance: BigNumber; + takerBalance: BigNumber; + takerAllowance: BigNumber; + makerZrxBalance: BigNumber; + makerZrxAllowance: BigNumber; + takerZrxBalance: BigNumber; + takerZrxAllowance: BigNumber; + }> + ] + >(returnData); + return abiDecodedReturnData; + }, }; public getTradersInfo = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( orders: Array<{ makerAddress: string; @@ -401,6 +598,11 @@ export class OrderValidatorContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData( orders: Array<{ makerAddress: string; @@ -427,8 +629,75 @@ export class OrderValidatorContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): Array<{ + makerBalance: BigNumber; + makerAllowance: BigNumber; + takerBalance: BigNumber; + takerAllowance: BigNumber; + makerZrxBalance: BigNumber; + makerZrxAllowance: BigNumber; + takerZrxBalance: BigNumber; + takerZrxAllowance: BigNumber; + }> { + const self = (this as any) as OrderValidatorContract; + const abiEncoder = self._lookupAbiEncoder( + 'getTradersInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],address[])', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode< + Array<{ + makerBalance: BigNumber; + makerAllowance: BigNumber; + takerBalance: BigNumber; + takerAllowance: BigNumber; + makerZrxBalance: BigNumber; + makerZrxAllowance: BigNumber; + takerZrxBalance: BigNumber; + takerZrxAllowance: BigNumber; + }> + >(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): Array<{ + makerBalance: BigNumber; + makerAllowance: BigNumber; + takerBalance: BigNumber; + takerAllowance: BigNumber; + makerZrxBalance: BigNumber; + makerZrxAllowance: BigNumber; + takerZrxBalance: BigNumber; + takerZrxAllowance: BigNumber; + }> { + const self = (this as any) as OrderValidatorContract; + const abiEncoder = self._lookupAbiEncoder( + 'getTradersInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],address[])', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue< + Array<{ + makerBalance: BigNumber; + makerAllowance: BigNumber; + takerBalance: BigNumber; + takerAllowance: BigNumber; + makerZrxBalance: BigNumber; + makerZrxAllowance: BigNumber; + takerZrxBalance: BigNumber; + takerZrxAllowance: BigNumber; + }> + >(returnData); + return abiDecodedReturnData; + }, }; public getERC721TokenOwner = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( token: string, tokenId: BigNumber, @@ -475,6 +744,11 @@ export class OrderValidatorContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(token: string, tokenId: BigNumber): string { assert.isString('token', token); assert.isBigNumber('tokenId', tokenId); @@ -485,8 +759,27 @@ export class OrderValidatorContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as OrderValidatorContract; + const abiEncoder = self._lookupAbiEncoder('getERC721TokenOwner(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as OrderValidatorContract; + const abiEncoder = self._lookupAbiEncoder('getERC721TokenOwner(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public getBalancesAndAllowances = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( target: string, assetData: string[], @@ -533,6 +826,11 @@ export class OrderValidatorContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(target: string, assetData: string[]): string { assert.isString('target', target); assert.isArray('assetData', assetData); @@ -543,8 +841,27 @@ export class OrderValidatorContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): [BigNumber[], BigNumber[]] { + const self = (this as any) as OrderValidatorContract; + const abiEncoder = self._lookupAbiEncoder('getBalancesAndAllowances(address,bytes[])'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<[BigNumber[], BigNumber[]]>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): [BigNumber[], BigNumber[]] { + const self = (this as any) as OrderValidatorContract; + const abiEncoder = self._lookupAbiEncoder('getBalancesAndAllowances(address,bytes[])'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<[BigNumber[], BigNumber[]]>(returnData); + return abiDecodedReturnData; + }, }; public getTraderInfo = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( order: { makerAddress: string; @@ -623,6 +940,11 @@ export class OrderValidatorContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData( order: { makerAddress: string; @@ -648,11 +970,70 @@ export class OrderValidatorContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): { + makerBalance: BigNumber; + makerAllowance: BigNumber; + takerBalance: BigNumber; + takerAllowance: BigNumber; + makerZrxBalance: BigNumber; + makerZrxAllowance: BigNumber; + takerZrxBalance: BigNumber; + takerZrxAllowance: BigNumber; + } { + const self = (this as any) as OrderValidatorContract; + const abiEncoder = self._lookupAbiEncoder( + 'getTraderInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),address)', + ); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<{ + makerBalance: BigNumber; + makerAllowance: BigNumber; + takerBalance: BigNumber; + takerAllowance: BigNumber; + makerZrxBalance: BigNumber; + makerZrxAllowance: BigNumber; + takerZrxBalance: BigNumber; + takerZrxAllowance: BigNumber; + }>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): { + makerBalance: BigNumber; + makerAllowance: BigNumber; + takerBalance: BigNumber; + takerAllowance: BigNumber; + makerZrxBalance: BigNumber; + makerZrxAllowance: BigNumber; + takerZrxBalance: BigNumber; + takerZrxAllowance: BigNumber; + } { + const self = (this as any) as OrderValidatorContract; + const abiEncoder = self._lookupAbiEncoder( + 'getTraderInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),address)', + ); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<{ + makerBalance: BigNumber; + makerAllowance: BigNumber; + takerBalance: BigNumber; + takerAllowance: BigNumber; + makerZrxBalance: BigNumber; + makerZrxAllowance: BigNumber; + takerZrxBalance: BigNumber; + takerZrxAllowance: BigNumber; + }>(returnData); + return abiDecodedReturnData; + }, }; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, _exchange: string, _zrxAssetData: string, ): Promise { @@ -667,13 +1048,28 @@ export class OrderValidatorContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; - return OrderValidatorContract.deployAsync(bytecode, abi, provider, txDefaults, _exchange, _zrxAssetData); + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return OrderValidatorContract.deployAsync( + bytecode, + abi, + provider, + txDefaults, + logDecodeDependenciesAbiOnly, + _exchange, + _zrxAssetData, + ); } public static async deployAsync( bytecode: string, abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, _exchange: string, _zrxAssetData: string, ): Promise { @@ -703,7 +1099,12 @@ export class OrderValidatorContract extends BaseContract { logUtils.log(`transactionHash: ${txHash}`); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); logUtils.log(`OrderValidator successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new OrderValidatorContract(txReceipt.contractAddress as string, provider, txDefaults); + const contractInstance = new OrderValidatorContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); contractInstance.constructorArgs = [_exchange, _zrxAssetData]; return contractInstance; } @@ -1273,8 +1674,20 @@ export class OrderValidatorContract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('OrderValidator', OrderValidatorContract.ABI(), address, supportedProvider, txDefaults); + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super( + 'OrderValidator', + OrderValidatorContract.ABI(), + address, + supportedProvider, + txDefaults, + logDecodeDependencies, + ); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); } } diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/weth9.ts b/packages/abi-gen-wrappers/src/generated-wrappers/weth9.ts index 825c856c17..d94ea5e255 100644 --- a/packages/abi-gen-wrappers/src/generated-wrappers/weth9.ts +++ b/packages/abi-gen-wrappers/src/generated-wrappers/weth9.ts @@ -1,7 +1,14 @@ // tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma // tslint:disable:whitespace no-unbound-method no-trailing-whitespace // tslint:disable:no-unused-variable -import { BaseContract, PromiseWithTransactionHash } from '@0x/base-contract'; +import { + BaseContract, + BlockRange, + EventCallback, + IndexedFilterValues, + SubscriptionManager, + PromiseWithTransactionHash, +} from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { BlockParam, @@ -10,6 +17,7 @@ import { ContractAbi, ContractArtifact, DecodedLogArgs, + LogWithDecodedArgs, MethodAbi, TransactionReceiptWithDecodedLogs, TxData, @@ -63,6 +71,11 @@ export interface WETH9WithdrawalEventArgs extends DecodedLogArgs { // tslint:disable-next-line:class-name export class WETH9Contract extends BaseContract { public name = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -99,13 +112,38 @@ export class WETH9Contract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as WETH9Contract; const abiEncodedTransactionData = self._strictEncodeArguments('name()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('name()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('name()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public approve = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(guy: string, wad: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as WETH9Contract; const encodedData = self._strictEncodeArguments('approve(address,uint256)', [guy, wad]); @@ -131,6 +169,13 @@ export class WETH9Contract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( guy: string, wad: BigNumber, @@ -154,6 +199,11 @@ export class WETH9Contract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(guy: string, wad: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as WETH9Contract; const encodedData = self._strictEncodeArguments('approve(address,uint256)', [guy, wad]); @@ -178,6 +228,11 @@ export class WETH9Contract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( guy: string, wad: BigNumber, @@ -221,6 +276,11 @@ export class WETH9Contract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(guy: string, wad: BigNumber): string { assert.isString('guy', guy); assert.isBigNumber('wad', wad); @@ -231,8 +291,36 @@ export class WETH9Contract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('approve(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('approve(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + guy: string, + wad: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).approve.callAsync(guy, wad, txData); + const txHash = await (this as any).approve.sendTransactionAsync(guy, wad, txData); + return txHash; + }, }; public totalSupply = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -269,13 +357,38 @@ export class WETH9Contract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as WETH9Contract; const abiEncodedTransactionData = self._strictEncodeArguments('totalSupply()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('totalSupply()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('totalSupply()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public transferFrom = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( src: string, dst: string, @@ -306,6 +419,13 @@ export class WETH9Contract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( src: string, dst: string, @@ -336,6 +456,11 @@ export class WETH9Contract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( src: string, dst: string, @@ -365,6 +490,11 @@ export class WETH9Contract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( src: string, dst: string, @@ -414,6 +544,11 @@ export class WETH9Contract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(src: string, dst: string, wad: BigNumber): string { assert.isString('src', src); assert.isString('dst', dst); @@ -426,8 +561,38 @@ export class WETH9Contract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('transferFrom(address,address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('transferFrom(address,address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + src: string, + dst: string, + wad: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).transferFrom.callAsync(src, dst, wad, txData); + const txHash = await (this as any).transferFrom.sendTransactionAsync(src, dst, wad, txData); + return txHash; + }, }; public withdraw = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(wad: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as WETH9Contract; const encodedData = self._strictEncodeArguments('withdraw(uint256)', [wad]); @@ -453,6 +618,13 @@ export class WETH9Contract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( wad: BigNumber, txData?: Partial, @@ -474,6 +646,11 @@ export class WETH9Contract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(wad: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as WETH9Contract; const encodedData = self._strictEncodeArguments('withdraw(uint256)', [wad]); @@ -498,6 +675,11 @@ export class WETH9Contract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(wad: BigNumber, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isBigNumber('wad', wad); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -535,14 +717,43 @@ export class WETH9Contract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(wad: BigNumber): string { assert.isBigNumber('wad', wad); const self = (this as any) as WETH9Contract; const abiEncodedTransactionData = self._strictEncodeArguments('withdraw(uint256)', [wad]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('withdraw(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('withdraw(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(wad: BigNumber, txData?: Partial | undefined): Promise { + await (this as any).withdraw.callAsync(wad, txData); + const txHash = await (this as any).withdraw.sendTransactionAsync(wad, txData); + return txHash; + }, }; public decimals = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -579,13 +790,37 @@ export class WETH9Contract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as WETH9Contract; const abiEncodedTransactionData = self._strictEncodeArguments('decimals()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): number { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('decimals()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): number { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('decimals()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public balanceOf = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( index_0: string, callData: Partial = {}, @@ -627,6 +862,11 @@ export class WETH9Contract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: string): string { assert.isString('index_0', index_0); const self = (this as any) as WETH9Contract; @@ -635,8 +875,27 @@ export class WETH9Contract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('balanceOf(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('balanceOf(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public symbol = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -673,13 +932,38 @@ export class WETH9Contract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as WETH9Contract; const abiEncodedTransactionData = self._strictEncodeArguments('symbol()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('symbol()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('symbol()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public transfer = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(dst: string, wad: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as WETH9Contract; const encodedData = self._strictEncodeArguments('transfer(address,uint256)', [dst, wad]); @@ -705,6 +989,13 @@ export class WETH9Contract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( dst: string, wad: BigNumber, @@ -728,6 +1019,11 @@ export class WETH9Contract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(dst: string, wad: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as WETH9Contract; const encodedData = self._strictEncodeArguments('transfer(address,uint256)', [dst, wad]); @@ -752,6 +1048,11 @@ export class WETH9Contract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( dst: string, wad: BigNumber, @@ -795,6 +1096,11 @@ export class WETH9Contract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(dst: string, wad: BigNumber): string { assert.isString('dst', dst); assert.isBigNumber('wad', wad); @@ -805,8 +1111,37 @@ export class WETH9Contract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('transfer(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('transfer(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + dst: string, + wad: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).transfer.callAsync(dst, wad, txData); + const txHash = await (this as any).transfer.sendTransactionAsync(dst, wad, txData); + return txHash; + }, }; public deposit = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(txData?: Partial | undefined): Promise { const self = (this as any) as WETH9Contract; const encodedData = self._strictEncodeArguments('deposit()', []); @@ -832,6 +1167,13 @@ export class WETH9Contract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( txData?: Partial, pollingIntervalMs?: number, @@ -851,6 +1193,11 @@ export class WETH9Contract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(txData?: Partial | undefined): Promise { const self = (this as any) as WETH9Contract; const encodedData = self._strictEncodeArguments('deposit()', []); @@ -875,6 +1222,11 @@ export class WETH9Contract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -911,13 +1263,42 @@ export class WETH9Contract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as WETH9Contract; const abiEncodedTransactionData = self._strictEncodeArguments('deposit()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('deposit()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('deposit()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(txData?: Partial | undefined): Promise { + await (this as any).deposit.callAsync(txData); + const txHash = await (this as any).deposit.sendTransactionAsync(txData); + return txHash; + }, }; public allowance = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( index_0: string, index_1: string, @@ -964,6 +1345,11 @@ export class WETH9Contract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(index_0: string, index_1: string): string { assert.isString('index_0', index_0); assert.isString('index_1', index_1); @@ -974,11 +1360,27 @@ export class WETH9Contract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('allowance(address,address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as WETH9Contract; + const abiEncoder = self._lookupAbiEncoder('allowance(address,address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + private readonly _subscriptionManager: SubscriptionManager; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, ): Promise { assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ schemas.addressSchema, @@ -991,13 +1393,20 @@ export class WETH9Contract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; - return WETH9Contract.deployAsync(bytecode, abi, provider, txDefaults); + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return WETH9Contract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); } public static async deployAsync( bytecode: string, abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, ): Promise { assert.isHexString('bytecode', bytecode); assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ @@ -1021,7 +1430,12 @@ export class WETH9Contract extends BaseContract { logUtils.log(`transactionHash: ${txHash}`); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); logUtils.log(`WETH9 successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new WETH9Contract(txReceipt.contractAddress as string, provider, txDefaults); + const contractInstance = new WETH9Contract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); contractInstance.constructorArgs = []; return contractInstance; } @@ -1317,9 +1731,86 @@ export class WETH9Contract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('WETH9', WETH9Contract.ABI(), address, supportedProvider, txDefaults); + /** + * Subscribe to an event type emitted by the WETH9 contract. + * @param eventName The WETH9 contract event you would like to subscribe to. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` + * @param callback Callback that gets called when a log is added/removed + * @param isVerbose Enable verbose subscription warnings (e.g recoverable network issues encountered) + * @return Subscription token used later to unsubscribe + */ + public subscribe( + eventName: WETH9Events, + indexFilterValues: IndexedFilterValues, + callback: EventCallback, + isVerbose: boolean = false, + blockPollingIntervalMs?: number, + ): string { + assert.doesBelongToStringEnum('eventName', eventName, WETH9Events); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + assert.isFunction('callback', callback); + const subscriptionToken = this._subscriptionManager.subscribe( + this.address, + eventName, + indexFilterValues, + WETH9Contract.ABI(), + callback, + isVerbose, + blockPollingIntervalMs, + ); + return subscriptionToken; + } + /** + * Cancel a subscription + * @param subscriptionToken Subscription token returned by `subscribe()` + */ + public unsubscribe(subscriptionToken: string): void { + this._subscriptionManager.unsubscribe(subscriptionToken); + } + /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + this._subscriptionManager.unsubscribeAll(); + } + /** + * Gets historical logs without creating a subscription + * @param eventName The WETH9 contract event you would like to subscribe to. + * @param blockRange Block range to get logs from. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` + * @return Array of logs that match the parameters + */ + public async getLogsAsync( + eventName: WETH9Events, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, + ): Promise>> { + assert.doesBelongToStringEnum('eventName', eventName, WETH9Events); + assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + const logs = await this._subscriptionManager.getLogsAsync( + this.address, + eventName, + blockRange, + indexFilterValues, + WETH9Contract.ABI(), + ); + return logs; + } + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super('WETH9', WETH9Contract.ABI(), address, supportedProvider, txDefaults, logDecodeDependencies); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); + this._subscriptionManager = new SubscriptionManager( + WETH9Contract.ABI(), + this._web3Wrapper, + ); } } diff --git a/packages/abi-gen-wrappers/src/generated-wrappers/zrx_token.ts b/packages/abi-gen-wrappers/src/generated-wrappers/zrx_token.ts index 274f5b983d..974f6f10b7 100644 --- a/packages/abi-gen-wrappers/src/generated-wrappers/zrx_token.ts +++ b/packages/abi-gen-wrappers/src/generated-wrappers/zrx_token.ts @@ -1,7 +1,14 @@ // tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma // tslint:disable:whitespace no-unbound-method no-trailing-whitespace // tslint:disable:no-unused-variable -import { BaseContract, PromiseWithTransactionHash } from '@0x/base-contract'; +import { + BaseContract, + BlockRange, + EventCallback, + IndexedFilterValues, + SubscriptionManager, + PromiseWithTransactionHash, +} from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { BlockParam, @@ -10,6 +17,7 @@ import { ContractAbi, ContractArtifact, DecodedLogArgs, + LogWithDecodedArgs, MethodAbi, TransactionReceiptWithDecodedLogs, TxData, @@ -47,6 +55,11 @@ export interface ZRXTokenApprovalEventArgs extends DecodedLogArgs { // tslint:disable-next-line:class-name export class ZRXTokenContract extends BaseContract { public name = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -83,13 +96,38 @@ export class ZRXTokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as ZRXTokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('name()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as ZRXTokenContract; + const abiEncoder = self._lookupAbiEncoder('name()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as ZRXTokenContract; + const abiEncoder = self._lookupAbiEncoder('name()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public approve = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _spender: string, _value: BigNumber, @@ -119,6 +157,13 @@ export class ZRXTokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _spender: string, _value: BigNumber, @@ -142,6 +187,11 @@ export class ZRXTokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( _spender: string, _value: BigNumber, @@ -170,6 +220,11 @@ export class ZRXTokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( _spender: string, _value: BigNumber, @@ -216,6 +271,11 @@ export class ZRXTokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(_spender: string, _value: BigNumber): string { assert.isString('_spender', _spender); assert.isBigNumber('_value', _value); @@ -226,8 +286,36 @@ export class ZRXTokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as ZRXTokenContract; + const abiEncoder = self._lookupAbiEncoder('approve(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as ZRXTokenContract; + const abiEncoder = self._lookupAbiEncoder('approve(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _spender: string, + _value: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).approve.callAsync(_spender, _value, txData); + const txHash = await (this as any).approve.sendTransactionAsync(_spender, _value, txData); + return txHash; + }, }; public totalSupply = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -264,13 +352,44 @@ export class ZRXTokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as ZRXTokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('totalSupply()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as ZRXTokenContract; + const abiEncoder = self._lookupAbiEncoder('totalSupply()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as ZRXTokenContract; + const abiEncoder = self._lookupAbiEncoder('totalSupply()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance. + */ public transferFrom = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param _from Address to transfer from. + * @param _to Address to transfer to. + * @param _value Amount to transfer. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _from: string, _to: string, @@ -305,6 +424,16 @@ export class ZRXTokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param _from Address to transfer from. + * @param _to Address to transfer to. + * @param _value Amount to transfer. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _from: string, _to: string, @@ -335,6 +464,14 @@ export class ZRXTokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param _from Address to transfer from. + * @param _to Address to transfer to. + * @param _value Amount to transfer. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync( _from: string, _to: string, @@ -368,6 +505,15 @@ export class ZRXTokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param _from Address to transfer from. + * @param _to Address to transfer to. + * @param _value Amount to transfer. + * @returns Success of transfer. + */ async callAsync( _from: string, _to: string, @@ -417,6 +563,14 @@ export class ZRXTokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param _from Address to transfer from. + * @param _to Address to transfer to. + * @param _value Amount to transfer. + */ getABIEncodedTransactionData(_from: string, _to: string, _value: BigNumber): string { assert.isString('_from', _from); assert.isString('_to', _to); @@ -429,8 +583,37 @@ export class ZRXTokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as ZRXTokenContract; + const abiEncoder = self._lookupAbiEncoder('transferFrom(address,address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as ZRXTokenContract; + const abiEncoder = self._lookupAbiEncoder('transferFrom(address,address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _from: string, + _to: string, + _value: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).transferFrom.callAsync(_from, _to, _value, txData); + const txHash = await (this as any).transferFrom.sendTransactionAsync(_from, _to, _value, txData); + return txHash; + }, }; public decimals = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -467,13 +650,37 @@ export class ZRXTokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as ZRXTokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('decimals()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): number { + const self = (this as any) as ZRXTokenContract; + const abiEncoder = self._lookupAbiEncoder('decimals()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): number { + const self = (this as any) as ZRXTokenContract; + const abiEncoder = self._lookupAbiEncoder('decimals()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public balanceOf = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( _owner: string, callData: Partial = {}, @@ -515,14 +722,38 @@ export class ZRXTokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(_owner: string): string { assert.isString('_owner', _owner); const self = (this as any) as ZRXTokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('balanceOf(address)', [_owner.toLowerCase()]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as ZRXTokenContract; + const abiEncoder = self._lookupAbiEncoder('balanceOf(address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as ZRXTokenContract; + const abiEncoder = self._lookupAbiEncoder('balanceOf(address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public symbol = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -559,13 +790,38 @@ export class ZRXTokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as ZRXTokenContract; const abiEncodedTransactionData = self._strictEncodeArguments('symbol()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as ZRXTokenContract; + const abiEncoder = self._lookupAbiEncoder('symbol()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as ZRXTokenContract; + const abiEncoder = self._lookupAbiEncoder('symbol()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public transfer = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync( _to: string, _value: BigNumber, @@ -595,6 +851,13 @@ export class ZRXTokenContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( _to: string, _value: BigNumber, @@ -618,6 +881,11 @@ export class ZRXTokenContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(_to: string, _value: BigNumber, txData?: Partial | undefined): Promise { const self = (this as any) as ZRXTokenContract; const encodedData = self._strictEncodeArguments('transfer(address,uint256)', [_to, _value]); @@ -642,6 +910,11 @@ export class ZRXTokenContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( _to: string, _value: BigNumber, @@ -685,6 +958,11 @@ export class ZRXTokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(_to: string, _value: BigNumber): string { assert.isString('_to', _to); assert.isBigNumber('_value', _value); @@ -695,8 +973,36 @@ export class ZRXTokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): boolean { + const self = (this as any) as ZRXTokenContract; + const abiEncoder = self._lookupAbiEncoder('transfer(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): boolean { + const self = (this as any) as ZRXTokenContract; + const abiEncoder = self._lookupAbiEncoder('transfer(address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync( + _to: string, + _value: BigNumber, + txData?: Partial | undefined, + ): Promise { + await (this as any).transfer.callAsync(_to, _value, txData); + const txHash = await (this as any).transfer.sendTransactionAsync(_to, _value, txData); + return txHash; + }, }; public allowance = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( _owner: string, _spender: string, @@ -743,6 +1049,11 @@ export class ZRXTokenContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(_owner: string, _spender: string): string { assert.isString('_owner', _owner); assert.isString('_spender', _spender); @@ -753,11 +1064,27 @@ export class ZRXTokenContract extends BaseContract { ]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as ZRXTokenContract; + const abiEncoder = self._lookupAbiEncoder('allowance(address,address)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as ZRXTokenContract; + const abiEncoder = self._lookupAbiEncoder('allowance(address,address)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + private readonly _subscriptionManager: SubscriptionManager; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, ): Promise { assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ schemas.addressSchema, @@ -770,13 +1097,20 @@ export class ZRXTokenContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; - return ZRXTokenContract.deployAsync(bytecode, abi, provider, txDefaults); + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return ZRXTokenContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); } public static async deployAsync( bytecode: string, abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, ): Promise { assert.isHexString('bytecode', bytecode); assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ @@ -800,7 +1134,12 @@ export class ZRXTokenContract extends BaseContract { logUtils.log(`transactionHash: ${txHash}`); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); logUtils.log(`ZRXToken successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new ZRXTokenContract(txReceipt.contractAddress as string, provider, txDefaults); + const contractInstance = new ZRXTokenContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); contractInstance.constructorArgs = []; return contractInstance; } @@ -1027,9 +1366,86 @@ export class ZRXTokenContract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('ZRXToken', ZRXTokenContract.ABI(), address, supportedProvider, txDefaults); + /** + * Subscribe to an event type emitted by the ZRXToken contract. + * @param eventName The ZRXToken contract event you would like to subscribe to. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` + * @param callback Callback that gets called when a log is added/removed + * @param isVerbose Enable verbose subscription warnings (e.g recoverable network issues encountered) + * @return Subscription token used later to unsubscribe + */ + public subscribe( + eventName: ZRXTokenEvents, + indexFilterValues: IndexedFilterValues, + callback: EventCallback, + isVerbose: boolean = false, + blockPollingIntervalMs?: number, + ): string { + assert.doesBelongToStringEnum('eventName', eventName, ZRXTokenEvents); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + assert.isFunction('callback', callback); + const subscriptionToken = this._subscriptionManager.subscribe( + this.address, + eventName, + indexFilterValues, + ZRXTokenContract.ABI(), + callback, + isVerbose, + blockPollingIntervalMs, + ); + return subscriptionToken; + } + /** + * Cancel a subscription + * @param subscriptionToken Subscription token returned by `subscribe()` + */ + public unsubscribe(subscriptionToken: string): void { + this._subscriptionManager.unsubscribe(subscriptionToken); + } + /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + this._subscriptionManager.unsubscribeAll(); + } + /** + * Gets historical logs without creating a subscription + * @param eventName The ZRXToken contract event you would like to subscribe to. + * @param blockRange Block range to get logs from. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` + * @return Array of logs that match the parameters + */ + public async getLogsAsync( + eventName: ZRXTokenEvents, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, + ): Promise>> { + assert.doesBelongToStringEnum('eventName', eventName, ZRXTokenEvents); + assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + const logs = await this._subscriptionManager.getLogsAsync( + this.address, + eventName, + blockRange, + indexFilterValues, + ZRXTokenContract.ABI(), + ); + return logs; + } + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super('ZRXToken', ZRXTokenContract.ABI(), address, supportedProvider, txDefaults, logDecodeDependencies); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); + this._subscriptionManager = new SubscriptionManager( + ZRXTokenContract.ABI(), + this._web3Wrapper, + ); } } diff --git a/packages/abi-gen-wrappers/src/index.ts b/packages/abi-gen-wrappers/src/index.ts index 7c610993bc..b9ec431af9 100644 --- a/packages/abi-gen-wrappers/src/index.ts +++ b/packages/abi-gen-wrappers/src/index.ts @@ -1,7 +1,9 @@ export * from './generated-wrappers/asset_proxy_owner'; +export * from './generated-wrappers/dev_utils'; export * from './generated-wrappers/dummy_erc20_token'; export * from './generated-wrappers/dummy_erc721_token'; export * from './generated-wrappers/dutch_auction'; +export * from './generated-wrappers/erc1155_proxy'; export * from './generated-wrappers/erc20_proxy'; export * from './generated-wrappers/erc20_token'; export * from './generated-wrappers/erc721_proxy'; @@ -13,6 +15,7 @@ export * from './generated-wrappers/i_validator'; export * from './generated-wrappers/i_wallet'; export * from './generated-wrappers/multi_asset_proxy'; export * from './generated-wrappers/order_validator'; +export * from './generated-wrappers/static_call_proxy'; export * from './generated-wrappers/weth9'; export * from './generated-wrappers/zrx_token'; export * from './generated-wrappers/coordinator'; diff --git a/packages/order-watcher/typedoc-tsconfig.json b/packages/abi-gen-wrappers/typedoc-tsconfig.json similarity index 69% rename from packages/order-watcher/typedoc-tsconfig.json rename to packages/abi-gen-wrappers/typedoc-tsconfig.json index c9b0af1ae6..a4c669cb6d 100644 --- a/packages/order-watcher/typedoc-tsconfig.json +++ b/packages/abi-gen-wrappers/typedoc-tsconfig.json @@ -3,5 +3,5 @@ "compilerOptions": { "outDir": "lib" }, - "include": ["./src/**/*", "./test/**/*"] + "include": ["./src/**/*"] } diff --git a/packages/abi-gen/CHANGELOG.json b/packages/abi-gen/CHANGELOG.json index af73fccfc8..ce46a1b94e 100644 --- a/packages/abi-gen/CHANGELOG.json +++ b/packages/abi-gen/CHANGELOG.json @@ -1,4 +1,68 @@ [ + { + "version": "4.1.0", + "changes": [ + { + "note": "Updated expected typescript output for cli tests to include `getABIDecodedTransactionData` and `getABIDecodedReturnData`", + "pr": 2018 + }, + { + "note": "Added tests for`getABIDecodedTransactionData` and `getABIDecodedReturnData` in contract wrappers.", + "pr": 2018 + } + ], + "timestamp": 1565296576 + }, + { + "version": "4.0.0", + "changes": [ + { + "note": "whitespace changes to generated Python code", + "pr": 1996 + }, + { + "note": "move Python Validator base class from generated code to common package", + "pr": 1996 + }, + { + "note": "Changed fundamental thing-to-be-wrapped from the contract to the contract method. That is, now there is a base contract method wrapper class rather than a base contract wrapper class, and individual contract methods are represented by named classes inheriting from that base, and the different operations on a method are now represented by a nested-object dot notation, ie, WrappedContract.ContractMethod.call() and WrappedContract.ContractMethod.send_transaction().", + "pr": 1996 + }, + { + "note": "added gas estimation functionality to contract methods", + "pr": 1996 + }, + { + "note": "Python: fixed bug with methods returning multiple values", + "pr": 1996 + }, + { + "note": "Python: fixed bug with methods returning arrays of structs", + "pr": 1996 + }, + { + "note": "Python: fixed bug with methods that return a struct that contains another struct where the inner struct was not otherwise directly referenced by any method", + "pr": 1996 + }, + { + "note": "Python: fixed bug with tuples sometimes being used before they were declared", + "pr": 1996 + }, + { + "note": "Python: fixed bug with supporting overloaded methods", + "pr": 1996 + } + ] + }, + { + "version": "3.1.2", + "changes": [ + { + "note": "Dependencies updated" + } + ], + "timestamp": 1564604963 + }, { "version": "3.1.1", "changes": [ @@ -30,7 +94,8 @@ "note": "lots of fixes to satisfy linters of generated Python code", "pr": 1919 } - ] + ], + "timestamp": 1563957393 }, { "timestamp": 1563047529, diff --git a/packages/abi-gen/CHANGELOG.md b/packages/abi-gen/CHANGELOG.md index f3c82e82a4..2cad6884c8 100644 --- a/packages/abi-gen/CHANGELOG.md +++ b/packages/abi-gen/CHANGELOG.md @@ -5,6 +5,37 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v4.1.0 - _August 8, 2019_ + + * Updated expected typescript output for cli tests to include `getABIDecodedTransactionData` and `getABIDecodedReturnData` (#2018) + * Added tests for`getABIDecodedTransactionData` and `getABIDecodedReturnData` in contract wrappers. (#2018) + +## v4.0.0 - _Invalid date_ + + * whitespace changes to generated Python code (#1996) + * move Python Validator base class from generated code to common package (#1996) + * Changed fundamental thing-to-be-wrapped from the contract to the contract method. That is, now there is a base contract method wrapper class rather than a base contract wrapper class, and individual contract methods are represented by named classes inheriting from that base, and the different operations on a method are now represented by a nested-object dot notation, ie, WrappedContract.ContractMethod.call() and WrappedContract.ContractMethod.send_transaction(). (#1996) + * added gas estimation functionality to contract methods (#1996) + * Python: fixed bug with methods returning multiple values (#1996) + * Python: fixed bug with methods returning arrays of structs (#1996) + * Python: fixed bug with methods that return a struct that contains another struct where the inner struct was not otherwise directly referenced by any method (#1996) + * Python: fixed bug with tuples sometimes being used before they were declared (#1996) + * Python: fixed bug with supporting overloaded methods (#1996) + +## v3.1.2 - _July 31, 2019_ + + * Dependencies updated + +## v3.1.1 - _July 24, 2019_ + + * Python method parameters are now in snake case (#1919) + * Python wrappers now support tuples in method parameters (#1919) + * document Python method's bytes params as requiring UTF-8 (#1919) + * generate Python output into a contract-named folder, not a file (eg exchange/__init__.py rather than exchange.py) leaving space for user-defined additions to the same module, such as for custom types, as used by the Exchange wrapper's manually-written type aliases in the contract_wrappers.exchange.types Python module (#1919) + * support for customizable parameter validation for Python wrappers (#1919) + * wrap Python docstrings better, for pydocstyle compliance (#1919) + * lots of fixes to satisfy linters of generated Python code (#1919) + ## v2.1.1 - _July 13, 2019_ * Dependencies updated diff --git a/packages/abi-gen/README.md b/packages/abi-gen/README.md index d5df7ab450..87637f3214 100644 --- a/packages/abi-gen/README.md +++ b/packages/abi-gen/README.md @@ -110,7 +110,7 @@ The files in `test-cli/` are used to test the CLI output against a set of dummy Compile dummy contracts and generate wrappers: ``` -yarn test_cli:prebuild +yarn compile:sol ``` Build generated wrappers and unit tests: diff --git a/packages/abi-gen/package.json b/packages/abi-gen/package.json index 1d81675691..806f76e182 100644 --- a/packages/abi-gen/package.json +++ b/packages/abi-gen/package.json @@ -1,6 +1,6 @@ { "name": "@0x/abi-gen", - "version": "2.1.1", + "version": "4.1.0", "engines": { "node": ">=6.12" }, @@ -8,21 +8,26 @@ "main": "lib/src/index.js", "types": "lib/src/index.d.ts", "scripts": { - "lint": "tslint --format stylish --project . && yarn lint-contracts", - "lint-contracts": "solhint -c ../../contracts/.solhint.json test-cli/contracts/*.sol", + "lint": "tslint --format stylish --project . && yarn test_cli:lint", "fix": "tslint --fix --format stylish --project . && yarn lint-contracts", "clean": "shx rm -rf lib && yarn test_cli:clean", "build": "tsc -b && yarn generate_contract_wrappers && yarn prettier_contract_wrappers && yarn test_cli:build", "build:ci": "yarn build", "test": "yarn run_mocha && yarn test_cli", "test:circleci": "yarn test:coverage && yarn test_cli", - "run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/*_test.js --timeout 100000 --bail --exit", + "run_mocha": "(uname -s | grep -q Darwin && echo 'HACK! skipping mocha run due to https://github.com/0xProject/0x-monorepo/issues/2000') || mocha --require source-map-support/register --require make-promises-safe lib/test/*_test.js --timeout 100000 --bail --exit", "test:coverage": "nyc npm run test --all && yarn coverage:report:lcov", "coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info", - "test_cli": "yarn test_cli:run_mocha && yarn diff_contract_wrappers", + "test_cli": "run-p test_cli:test_typescript diff_contract_wrappers", "test_cli:clean": "rm -rf test-cli/output && rm -rf test-cli/test_typescript/lib", "test_cli:build": "tsc --project test-cli/tsconfig.json", - "test_cli:run_mocha": "mocha --require source-map-support/register --require make-promises-safe test-cli/test_typescript/lib/**/*_test.js --timeout 100000 --bail --exit", + "test_cli:test_typescript": "mocha --require source-map-support/register --require make-promises-safe test-cli/test_typescript/lib/**/*_test.js --timeout 100000 --bail --exit", + "test_cli:lint": "run-p test_cli:lint_solidity test_cli:lint_python # test_cli:lint_typescript # HACK: typescript lint disabled because prettier fails", + "test_cli:lint_solidity": "solhint -c ../../contracts/.solhint.json test-cli/fixtures/contracts/*.sol", + "test_cli:lint_typescript": "prettier --check ./test-cli/output/typescript/* --config ../../.prettierrc", + "test_cli:lint_python": "pip install -r test-cli/fixtures/python-requirements.txt && run-p test_cli:lint_python:black test_cli:lint_python:pylint", + "test_cli:lint_python:black": "black --line-length=79 --check ./test-cli/output/python/*", + "test_cli:lint_python:pylint": "PYTHONPATH=../../python-packages/contract_wrappers/src pylint --rcfile=test-cli/fixtures/pylintrc ./test-cli/output/python/*", "rebuild_and_test": "run-s build test", "test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html", "test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha", @@ -32,7 +37,7 @@ "prettier_contract_wrappers": "prettier --write ./test-cli/output/typescript/* --config ../../.prettierrc", "generate_contract_wrappers": "run-p gen_typescript gen_python", "gen_typescript": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output ./test-cli/output/typescript --backend ethers", - "gen_python": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/Python/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/Python/partials/**/*.handlebars' --output ./test-cli/output/python --language Python", + "gen_python": "pip install black && abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/Python/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/Python/partials/**/*.handlebars' --output ./test-cli/output/python --language Python", "diff_contract_wrappers": "test-cli/diff.sh ./test-cli/expected-output ./test-cli/output", "coverage:report:text": "istanbul report text", "coverage:report:html": "istanbul report html && open coverage/index.html", @@ -56,32 +61,34 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/abi-gen/README.md", "dependencies": { - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@types/toposort": "^2.0.1", "chalk": "^2.3.0", "change-case": "^3.0.2", "cli-format": "^3.0.9", - "ethereum-types": "^2.1.3", + "ethereum-types": "^2.1.4", "glob": "^7.1.2", - "handlebars": "^4.0.11", + "handlebars": "^4.1.2", "lodash": "^4.17.11", "mkdirp": "^0.5.1", "tmp": "^0.0.33", "to-snake-case": "^1.0.0", + "toposort": "^2.0.2", "yargs": "^10.0.3" }, "devDependencies": { - "@0x/base-contract": "^5.1.1", - "@0x/contracts-gen": "^1.0.10", - "@0x/dev-utils": "^2.2.4", - "@0x/sol-compiler": "^3.1.9", - "@0x/subproviders": "^4.1.1", + "@0x/base-contract": "^5.3.1", + "@0x/contracts-gen": "^1.0.13", + "@0x/dev-utils": "^2.3.0", + "@0x/sol-compiler": "^3.1.12", + "@0x/subproviders": "^5.0.1", "@0x/tslint-config": "^3.0.1", - "@0x/web3-wrapper": "^6.0.7", + "@0x/web3-wrapper": "^6.0.10", "@types/glob": "5.0.35", - "@types/handlebars": "^4.0.36", "@types/mkdirp": "^0.5.2", + "@types/mocha": "^5.2.7", "@types/node": "*", "@types/tmp": "^0.0.33", "@types/yargs": "^11.0.0", @@ -90,9 +97,10 @@ "chai-bignumber": "^3.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", + "sinon": "^4.0.0", "solhint": "^1.4.1", "tslint": "5.11.0", "typescript": "3.0.1" diff --git a/packages/abi-gen/src/index.ts b/packages/abi-gen/src/index.ts index a325d31c52..5938297ee9 100644 --- a/packages/abi-gen/src/index.ts +++ b/packages/abi-gen/src/index.ts @@ -1,5 +1,7 @@ #!/usr/bin/env node +import { execSync } from 'child_process'; + import { AbiEncoder, abiUtils, logUtils } from '@0x/utils'; import chalk from 'chalk'; import * as changeCase from 'change-case'; @@ -12,12 +14,12 @@ import { DevdocOutput, EventAbi, MethodAbi, - TupleDataItem, } from 'ethereum-types'; import { sync as globSync } from 'glob'; import * as Handlebars from 'handlebars'; import * as _ from 'lodash'; import * as mkdirp from 'mkdirp'; +import toposort = require('toposort'); import * as yargs from 'yargs'; import { ContextData, ContractsBackend, ParamKind } from './types'; @@ -104,52 +106,90 @@ function registerTypeScriptHelpers(): void { return context !== undefined; }, ); + + // Format docstring for method description + Handlebars.registerHelper( + 'formatDocstringForMethodTs', + (docString: string): Handlebars.SafeString => { + // preserve newlines + const regex = /([ ]{4,})+/gi; + const formatted = docString.replace(regex, '\n * '); + return new Handlebars.SafeString(formatted); + }, + ); + // Get docstring for method param + Handlebars.registerHelper( + 'getDocstringForParamTs', + (paramName: string, devdocParamsObj: { [name: string]: string }): Handlebars.SafeString | undefined => { + if (devdocParamsObj === undefined || devdocParamsObj[paramName] === undefined) { + return undefined; + } + return new Handlebars.SafeString(`${devdocParamsObj[paramName]}`); + }, + ); + + // Format docstring for method param + Handlebars.registerHelper( + 'formatDocstringForParamTs', + (paramName: string, desc: Handlebars.SafeString): Handlebars.SafeString => { + const docString = `@param ${paramName} ${desc}`; + const hangingIndentLength = 4; + const config = { + width: 80, + paddingLeft: ' * ', + hangingIndent: ' '.repeat(hangingIndentLength), + ansi: false, + }; + return new Handlebars.SafeString(`${cliFormat.wrap(docString, config)}`); + }, + ); } function registerPythonHelpers(): void { - Handlebars.registerHelper('equal', (lhs, rhs, options) => { + Handlebars.registerHelper('equal', (lhs: any, rhs: any) => { return lhs === rhs; }); - Handlebars.registerHelper('safeString', (str, options) => new Handlebars.SafeString(str)); + Handlebars.registerHelper('safeString', (str: string) => new Handlebars.SafeString(str)); Handlebars.registerHelper('parameterType', utils.solTypeToPyType.bind(utils)); Handlebars.registerHelper('returnType', utils.solTypeToPyType.bind(utils)); Handlebars.registerHelper('toPythonIdentifier', utils.toPythonIdentifier.bind(utils)); - Handlebars.registerHelper( - 'sanitizeDevdocDetails', - (methodName: string, devdocDetails: string, indent: number, options) => { - // wrap to 80 columns, assuming given indent, so that generated - // docstrings can pass pycodestyle checks. - if (devdocDetails === undefined || devdocDetails.length === 0) { - return ''; - } - const columnsPerRow = 80; - return new Handlebars.SafeString( - `\n${cliFormat.wrap(devdocDetails || '', { - paddingLeft: ' '.repeat(indent), - width: columnsPerRow, - ansi: false, - })}\n`, - ); - }, - ); - Handlebars.registerHelper( - 'makeParameterDocstringRole', - (name: string, description: string, indent: number, options) => { - let docstring = `:param ${name}:`; - if (description && description.length > 0) { - docstring = `${docstring} ${description}`; - } - return new Handlebars.SafeString(utils.wrapPythonDocstringRole(docstring, indent)); - }, - ); + Handlebars.registerHelper('sanitizeDevdocDetails', (_methodName: string, devdocDetails: string, indent: number) => { + // wrap to 80 columns, assuming given indent, so that generated + // docstrings can pass pycodestyle checks. also, replace repeated + // spaces, likely caused by leading indents in the Solidity, because + // they cause repeated spaces in the output, and in particular they may + // cause repeated spaces at the beginning of a line in the docstring, + // which leads to "unexpected indent" errors when generating + // documentation. + if (devdocDetails === undefined || devdocDetails.length === 0) { + return ''; + } + const columnsPerRow = 80; + return new Handlebars.SafeString( + `\n${cliFormat.wrap(devdocDetails.replace(/ +/g, ' ') || '', { + paddingLeft: ' '.repeat(indent), + width: columnsPerRow, + ansi: false, + })}\n`, + ); + }); + Handlebars.registerHelper('makeParameterDocstringRole', (name: string, description: string, indent: number) => { + let docstring = `:param ${name}:`; + if (description && description.length > 0) { + docstring = `${docstring} ${description}`; + } + return new Handlebars.SafeString(utils.wrapPythonDocstringRole(docstring, indent)); + }); Handlebars.registerHelper( 'makeReturnDocstringRole', - (description: string, indent: number, options) => - new Handlebars.SafeString(utils.wrapPythonDocstringRole(`:returns: ${description}`, indent)), + (description: string, indent: number) => + new Handlebars.SafeString( + utils.wrapPythonDocstringRole(`:returns: ${description.replace(/ +/g, ' ')}`, indent), + ), ); Handlebars.registerHelper( 'makeEventParameterDocstringRole', - (eventName: string, indent: number, options) => + (eventName: string, indent: number) => new Handlebars.SafeString( utils.wrapPythonDocstringRole( `:param tx_hash: hash of transaction emitting ${eventName} event`, @@ -157,13 +197,18 @@ function registerPythonHelpers(): void { ), ), ); - Handlebars.registerHelper('tupleDefinitions', (abisJSON: string, options) => { + Handlebars.registerHelper('tupleDefinitions', (abisJSON: string) => { const abis: AbiDefinition[] = JSON.parse(abisJSON); // build an array of objects, each of which has one key, the Python - // name of a tuple, with a string value holding the Python - // definition of that tuple. Using a key-value object conveniently + // name of a tuple, with a string value holding the body of a Python + // class representing that tuple. Using a key-value object conveniently // filters duplicate references to the same tuple. - const tupleDefinitions: { [pythonTupleName: string]: string } = {}; + const tupleBodies: { [pythonTupleName: string]: string } = {}; + // build an array of tuple dependencies, whose format conforms to the + // expected input to toposort, a function to do a topological sort, + // which will help us declare tuples in the proper order, avoiding + // references to tuples that haven't been declared yet. + const tupleDependencies: Array<[string, string]> = []; for (const abi of abis) { let parameters: DataItem[] = []; if (abi.hasOwnProperty('inputs')) { @@ -185,26 +230,38 @@ function registerPythonHelpers(): void { parameters = parameters.concat((abi as MethodAbi).outputs); } for (const parameter of parameters) { - if (parameter.type === 'tuple') { - tupleDefinitions[ - utils.makePythonTupleName((parameter as TupleDataItem).components) - ] = utils.makePythonTupleClassBody((parameter as TupleDataItem).components); - } + utils.extractTuples(parameter, tupleBodies, tupleDependencies); } } + // build up a list of tuples to declare. the order they're pushed into + // this array is the order they will be declared. + const tuplesToDeclare = []; + // first push the ones that have dependencies + tuplesToDeclare.push(...toposort(tupleDependencies)); + // then push any remaining bodies (the ones that DON'T have + // dependencies) + for (const pythonTupleName in tupleBodies) { + if (!tuplesToDeclare.includes(pythonTupleName)) { + tuplesToDeclare.push(pythonTupleName); + } + } + // now iterate over those ordered tuples-to-declare, and prefix the + // corresponding class bodies with their class headers, to form full + // class declarations. const tupleDeclarations = []; - for (const pythonTupleName in tupleDefinitions) { - if (tupleDefinitions[pythonTupleName]) { + for (const pythonTupleName of tuplesToDeclare) { + if (tupleBodies[pythonTupleName]) { tupleDeclarations.push( - `class ${pythonTupleName}(TypedDict):\n """Python representation of a tuple or struct.\n\n A tuple found in an ABI may have been written in Solidity as a literal\n tuple, or it may have been written as a parameter with a Solidity\n \`struct\`:code: data type; there's no way to tell which, based solely on the\n ABI, and the name of a Solidity \`struct\`:code: is not conveyed through the\n ABI. This class represents a tuple that appeared in a method definition.\n Its name is derived from a hash of that tuple's field names, and every\n method whose ABI refers to a tuple with that same list of field names will\n have a generated wrapper method that refers to this class.\n\n Any members of type \`bytes\`:code: should be encoded as UTF-8, which can be\n accomplished via \`str.encode("utf_8")\`:code:\n """${ - tupleDefinitions[pythonTupleName] + `class ${pythonTupleName}(TypedDict):\n """Python representation of a tuple or struct.\n\n Solidity compiler output does not include the names of structs that appear\n in method definitions. A tuple found in an ABI may have been written in\n Solidity as a literal, anonymous tuple, or it may have been written as a\n named \`struct\`:code:, but there is no way to tell from the compiler\n output. This class represents a tuple that appeared in a method\n definition. Its name is derived from a hash of that tuple's field names,\n and every method whose ABI refers to a tuple with that same list of field\n names will have a generated wrapper method that refers to this class.\n\n Any members of type \`bytes\`:code: should be encoded as UTF-8, which can be\n accomplished via \`str.encode("utf_8")\`:code:\n """${ + tupleBodies[pythonTupleName] }`, ); } } - return new Handlebars.SafeString(tupleDeclarations.join('\n\n')); + // finally, join the class declarations together for the output file + return new Handlebars.SafeString(tupleDeclarations.join('\n\n\n')); }); - Handlebars.registerHelper('docBytesIfNecessary', (abisJSON: string, options) => { + Handlebars.registerHelper('docBytesIfNecessary', (abisJSON: string) => { const abis: AbiDefinition[] = JSON.parse(abisJSON); // see if any ABIs accept params of type bytes, and if so then emit // explanatory documentation string. @@ -231,6 +288,10 @@ function registerPythonHelpers(): void { } return ''; }); + Handlebars.registerHelper( + 'toPythonClassname', + (sourceName: string) => new Handlebars.SafeString(changeCase.pascal(sourceName)), + ); } if (args.language === 'TypeScript') { registerTypeScriptHelpers(); @@ -343,5 +404,17 @@ for (const abiFileName of abiFileNames) { }; const renderedCode = template(contextData); utils.writeOutputFile(outFilePath, renderedCode); + + if (args.language === 'Python') { + // use command-line tool black to reformat, if its available + try { + execSync(`black --line-length 79 ${outFilePath}`); + } catch { + logUtils.warn( + 'Failed to reformat generated Python with black. Do you have it installed? Proceeding anyways...', + ); + } + } + logUtils.log(`Created: ${chalk.bold(outFilePath)}`); } diff --git a/packages/abi-gen/src/utils.ts b/packages/abi-gen/src/utils.ts index 83ee80eac8..bb5a2d7812 100644 --- a/packages/abi-gen/src/utils.ts +++ b/packages/abi-gen/src/utils.ts @@ -2,7 +2,7 @@ import { createHash } from 'crypto'; import * as changeCase from 'change-case'; import * as cliFormat from 'cli-format'; -import { AbiType, ConstructorAbi, DataItem } from 'ethereum-types'; +import { AbiType, ConstructorAbi, DataItem, TupleDataItem } from 'ethereum-types'; import * as fs from 'fs'; import * as _ from 'lodash'; import * as path from 'path'; @@ -350,4 +350,28 @@ export const utils = { hangingIndent: ' '.repeat(columnsPerIndent), }); }, + extractTuples( + parameter: DataItem, + tupleBodies: { [pythonTupleName: string]: string }, // output + tupleDependencies: Array<[string, string]>, // output + ): void { + if (parameter.type === 'tuple' || parameter.type === 'tuple[]') { + const tupleDataItem = parameter as TupleDataItem; // tslint:disable-line:no-unnecessary-type-assertion + // without the above cast (which tslint complains about), tsc says + // Argument of type 'DataItem[] | undefined' is not assignable to parameter of type 'DataItem[]'. + // Type 'undefined' is not assignable to type 'DataItem[]' + // when the code below tries to access tupleDataItem.components. + const pythonTupleName = utils.makePythonTupleName(tupleDataItem.components); + tupleBodies[pythonTupleName] = utils.makePythonTupleClassBody(tupleDataItem.components); + for (const component of tupleDataItem.components) { + if (component.type === 'tuple' || component.type === 'tuple[]') { + tupleDependencies.push([ + utils.makePythonTupleName((component as TupleDataItem).components), // tslint:disable-line:no-unnecessary-type-assertion + pythonTupleName, + ]); + utils.extractTuples(component, tupleBodies, tupleDependencies); + } + } + } + }, }; diff --git a/packages/abi-gen/test-cli/expected-output/python/abi_gen_dummy/__init__.py b/packages/abi-gen/test-cli/expected-output/python/abi_gen_dummy/__init__.py index 70ca086ae5..76126181b0 100644 --- a/packages/abi-gen/test-cli/expected-output/python/abi_gen_dummy/__init__.py +++ b/packages/abi-gen/test-cli/expected-output/python/abi_gen_dummy/__init__.py @@ -11,37 +11,18 @@ from typing import ( # pylint: disable=unused-import Union, ) +from eth_utils import to_checksum_address from mypy_extensions import TypedDict # pylint: disable=unused-import from hexbytes import HexBytes +from web3 import Web3 +from web3.contract import ContractFunction from web3.datastructures import AttributeDict from web3.providers.base import BaseProvider -from zero_ex.contract_wrappers._base_contract_wrapper import BaseContractWrapper +from zero_ex.contract_wrappers.bases import ContractMethod, Validator from zero_ex.contract_wrappers.tx_params import TxParams -class AbiGenDummyValidatorBase: - """Base class for validating inputs to AbiGenDummy methods.""" - def __init__( - self, - provider: BaseProvider, - contract_address: str, - private_key: str = None, - ): - """Initialize the instance.""" - - def assert_valid( - self, method_name: str, parameter_name: str, argument_value: Any - ): - """Raise an exception if method input is not valid. - - :param method_name: Name of the method whose input is to be validated. - :param parameter_name: Name of the parameter whose input is to be - validated. - :param argument_value: Value of argument to parameter to be validated. - """ - - # Try to import a custom validator class definition; if there isn't one, # declare one that we can instantiate for the default argument to the # constructor for AbiGenDummy below. @@ -53,41 +34,61 @@ try: ) except ImportError: - class AbiGenDummyValidator(AbiGenDummyValidatorBase): # type: ignore + class AbiGenDummyValidator( # type: ignore + Validator + ): """No-op input validator.""" -class Tuple0xc9bdd2d5(TypedDict): +class Tuple0x246f9407(TypedDict): """Python representation of a tuple or struct. - A tuple found in an ABI may have been written in Solidity as a literal - tuple, or it may have been written as a parameter with a Solidity - `struct`:code: data type; there's no way to tell which, based solely on the - ABI, and the name of a Solidity `struct`:code: is not conveyed through the - ABI. This class represents a tuple that appeared in a method definition. - Its name is derived from a hash of that tuple's field names, and every - method whose ABI refers to a tuple with that same list of field names will - have a generated wrapper method that refers to this class. + Solidity compiler output does not include the names of structs that appear + in method definitions. A tuple found in an ABI may have been written in + Solidity as a literal, anonymous tuple, or it may have been written as a + named `struct`:code:, but there is no way to tell from the compiler + output. This class represents a tuple that appeared in a method + definition. Its name is derived from a hash of that tuple's field names, + and every method whose ABI refers to a tuple with that same list of field + names will have a generated wrapper method that refers to this class. Any members of type `bytes`:code: should be encoded as UTF-8, which can be accomplished via `str.encode("utf_8")`:code: """ - innerStruct: Tuple0xcf8ad995 + aField: int + + +class Tuple0x1b9da225(TypedDict): + """Python representation of a tuple or struct. + + Solidity compiler output does not include the names of structs that appear + in method definitions. A tuple found in an ABI may have been written in + Solidity as a literal, anonymous tuple, or it may have been written as a + named `struct`:code:, but there is no way to tell from the compiler + output. This class represents a tuple that appeared in a method + definition. Its name is derived from a hash of that tuple's field names, + and every method whose ABI refers to a tuple with that same list of field + names will have a generated wrapper method that refers to this class. + + Any members of type `bytes`:code: should be encoded as UTF-8, which can be + accomplished via `str.encode("utf_8")`:code: + """ + + innerStruct: Tuple0x246f9407 - description: str class Tuple0xcf8ad995(TypedDict): """Python representation of a tuple or struct. - A tuple found in an ABI may have been written in Solidity as a literal - tuple, or it may have been written as a parameter with a Solidity - `struct`:code: data type; there's no way to tell which, based solely on the - ABI, and the name of a Solidity `struct`:code: is not conveyed through the - ABI. This class represents a tuple that appeared in a method definition. - Its name is derived from a hash of that tuple's field names, and every - method whose ABI refers to a tuple with that same list of field names will - have a generated wrapper method that refers to this class. + Solidity compiler output does not include the names of structs that appear + in method definitions. A tuple found in an ABI may have been written in + Solidity as a literal, anonymous tuple, or it may have been written as a + named `struct`:code:, but there is no way to tell from the compiler + output. This class represents a tuple that appeared in a method + definition. Its name is derived from a hash of that tuple's field names, + and every method whose ABI refers to a tuple with that same list of field + names will have a generated wrapper method that refers to this class. Any members of type `bytes`:code: should be encoded as UTF-8, which can be accomplished via `str.encode("utf_8")`:code: @@ -102,74 +103,143 @@ class Tuple0xcf8ad995(TypedDict): aString: str -# pylint: disable=too-many-public-methods -class AbiGenDummy(BaseContractWrapper): - """Wrapper class for AbiGenDummy Solidity contract. +class Tuple0xc9bdd2d5(TypedDict): + """Python representation of a tuple or struct. - All method parameters of type `bytes`:code: should be encoded as UTF-8, - which can be accomplished via `str.encode("utf_8")`:code:. + Solidity compiler output does not include the names of structs that appear + in method definitions. A tuple found in an ABI may have been written in + Solidity as a literal, anonymous tuple, or it may have been written as a + named `struct`:code:, but there is no way to tell from the compiler + output. This class represents a tuple that appeared in a method + definition. Its name is derived from a hash of that tuple's field names, + and every method whose ABI refers to a tuple with that same list of field + names will have a generated wrapper method that refers to this class. + + Any members of type `bytes`:code: should be encoded as UTF-8, which can be + accomplished via `str.encode("utf_8")`:code: """ + innerStruct: Tuple0xcf8ad995 + + description: str + + +class Tuple0xf95128ef(TypedDict): + """Python representation of a tuple or struct. + + Solidity compiler output does not include the names of structs that appear + in method definitions. A tuple found in an ABI may have been written in + Solidity as a literal, anonymous tuple, or it may have been written as a + named `struct`:code:, but there is no way to tell from the compiler + output. This class represents a tuple that appeared in a method + definition. Its name is derived from a hash of that tuple's field names, + and every method whose ABI refers to a tuple with that same list of field + names will have a generated wrapper method that refers to this class. + + Any members of type `bytes`:code: should be encoded as UTF-8, which can be + accomplished via `str.encode("utf_8")`:code: + """ + + foo: int + + bar: bytes + + car: str + + +class Tuple0xa057bf41(TypedDict): + """Python representation of a tuple or struct. + + Solidity compiler output does not include the names of structs that appear + in method definitions. A tuple found in an ABI may have been written in + Solidity as a literal, anonymous tuple, or it may have been written as a + named `struct`:code:, but there is no way to tell from the compiler + output. This class represents a tuple that appeared in a method + definition. Its name is derived from a hash of that tuple's field names, + and every method whose ABI refers to a tuple with that same list of field + names will have a generated wrapper method that refers to this class. + + Any members of type `bytes`:code: should be encoded as UTF-8, which can be + accomplished via `str.encode("utf_8")`:code: + """ + + input: Tuple0xf95128ef + + lorem: bytes + + ipsum: bytes + + dolor: str + + +class SimpleRequireMethod(ContractMethod): + """Various interfaces to the simpleRequire method.""" + def __init__( self, provider: BaseProvider, contract_address: str, - validator: AbiGenDummyValidator = None, - private_key: str = None, + contract_function: ContractFunction, + validator: Validator = None, ): - """Get an instance of wrapper for smart contract. + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function - :param provider: instance of :class:`web3.providers.base.BaseProvider` - :param contract_address: where the contract has been deployed - :param private_key: If specified, transactions will be signed locally, - via Web3.py's `eth.account.signTransaction()`:code:, before being - sent via `eth.sendRawTransaction()`:code:. - """ - super().__init__( - provider=provider, - contract_address=contract_address, - private_key=private_key, - ) - - if not validator: - validator = AbiGenDummyValidator(provider, contract_address, private_key) - - self.validator = validator - - def _get_contract_instance(self, token_address): - """Get an instance of the smart contract at a specific address. - - :returns: contract object - """ - return self._contract_instance( - address=token_address, abi=AbiGenDummy.abi() - ) - - def simple_require( - self, - tx_params: Optional[TxParams] = None, - ) -> None: - """Execute underlying, same-named contract method. + def call(self, tx_params: Optional[TxParams] = None) -> None: + """Execute underlying contract method via eth_call. :param tx_params: transaction parameters """ - func = self._get_contract_instance( - self.contract_address - ).functions.simpleRequire( - ) - return self._invoke_function_call( - func=func, - tx_params=tx_params, - view_only=True - ) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().call(tx_params.as_dict()) - def accepts_an_array_of_bytes( + def send_transaction( + self, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + :param tx_params: transaction parameters + + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().transact(tx_params.as_dict()) + + def estimate_gas(self, tx_params: Optional[TxParams] = None) -> int: + """Estimate gas consumption of method call.""" + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().estimateGas(tx_params.as_dict()) + + +class AcceptsAnArrayOfBytesMethod(ContractMethod): + """Various interfaces to the acceptsAnArrayOfBytes method.""" + + def __init__( self, - a: List[bytes], - tx_params: Optional[TxParams] = None, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def validate_and_normalize_inputs(self, a: List[bytes]): + """Validate the inputs to the acceptsAnArrayOfBytes method.""" + self.validator.assert_valid( + method_name="acceptsAnArrayOfBytes", + parameter_name="a", + argument_value=a, + ) + a = [bytes.fromhex(a_element.decode("utf-8")) for a_element in a] + return a + + def call( + self, a: List[bytes], tx_params: Optional[TxParams] = None ) -> None: - """Execute underlying, same-named contract method. + """Execute underlying contract method via eth_call. a method that accepts an array of bytes @@ -177,27 +247,285 @@ class AbiGenDummy(BaseContractWrapper): :param tx_params: transaction parameters """ + (a) = self.validate_and_normalize_inputs(a) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(a).call(tx_params.as_dict()) + + def send_transaction( + self, a: List[bytes], tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + a method that accepts an array of bytes + + :param a: the array of bytes being accepted + :param tx_params: transaction parameters + + """ + (a) = self.validate_and_normalize_inputs(a) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(a).transact(tx_params.as_dict()) + + def estimate_gas( + self, a: List[bytes], tx_params: Optional[TxParams] = None + ) -> int: + """Estimate gas consumption of method call.""" + (a) = self.validate_and_normalize_inputs(a) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(a).estimateGas(tx_params.as_dict()) + + +class SimpleInputSimpleOutputMethod(ContractMethod): + """Various interfaces to the simpleInputSimpleOutput method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def validate_and_normalize_inputs(self, index_0: int): + """Validate the inputs to the simpleInputSimpleOutput method.""" self.validator.assert_valid( - method_name='acceptsAnArrayOfBytes', - parameter_name='a', - argument_value=a, + method_name="simpleInputSimpleOutput", + parameter_name="index_0", + argument_value=index_0, ) - a = [ - bytes.fromhex(a_element.decode("utf-8")) - for a_element in a - ] - func = self._get_contract_instance( - self.contract_address - ).functions.acceptsAnArrayOfBytes( - a + # safeguard against fractional inputs + index_0 = int(index_0) + return index_0 + + def call(self, index_0: int, tx_params: Optional[TxParams] = None) -> int: + """Execute underlying contract method via eth_call. + + Tests decoding when both input and output are non-empty. + + :param tx_params: transaction parameters + + """ + (index_0) = self.validate_and_normalize_inputs(index_0) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(index_0).call(tx_params.as_dict()) + + def send_transaction( + self, index_0: int, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + Tests decoding when both input and output are non-empty. + + :param tx_params: transaction parameters + + """ + (index_0) = self.validate_and_normalize_inputs(index_0) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(index_0).transact(tx_params.as_dict()) + + def estimate_gas( + self, index_0: int, tx_params: Optional[TxParams] = None + ) -> int: + """Estimate gas consumption of method call.""" + (index_0) = self.validate_and_normalize_inputs(index_0) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(index_0).estimateGas(tx_params.as_dict()) + + +class WithdrawMethod(ContractMethod): + """Various interfaces to the withdraw method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def validate_and_normalize_inputs(self, wad: int): + """Validate the inputs to the withdraw method.""" + self.validator.assert_valid( + method_name="withdraw", parameter_name="wad", argument_value=wad ) - return self._invoke_function_call( - func=func, - tx_params=tx_params, - view_only=True + # safeguard against fractional inputs + wad = int(wad) + return wad + + def call( + self, wad: int, tx_params: Optional[TxParams] = None + ) -> Union[None, Union[HexBytes, bytes]]: + """Execute underlying contract method via eth_call. + + :param tx_params: transaction parameters + :returns: the return value of the underlying method. + """ + (wad) = self.validate_and_normalize_inputs(wad) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(wad).call(tx_params.as_dict()) + + def send_transaction( + self, wad: int, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + :param tx_params: transaction parameters + """ + (wad) = self.validate_and_normalize_inputs(wad) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(wad).transact(tx_params.as_dict()) + + def estimate_gas( + self, wad: int, tx_params: Optional[TxParams] = None + ) -> int: + """Estimate gas consumption of method call.""" + (wad) = self.validate_and_normalize_inputs(wad) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(wad).estimateGas(tx_params.as_dict()) + + +class MultiInputMultiOutputMethod(ContractMethod): + """Various interfaces to the multiInputMultiOutput method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def validate_and_normalize_inputs( + self, index_0: int, index_1: bytes, index_2: str + ): + """Validate the inputs to the multiInputMultiOutput method.""" + self.validator.assert_valid( + method_name="multiInputMultiOutput", + parameter_name="index_0", + argument_value=index_0, + ) + # safeguard against fractional inputs + index_0 = int(index_0) + self.validator.assert_valid( + method_name="multiInputMultiOutput", + parameter_name="index_1", + argument_value=index_1, + ) + index_1 = bytes.fromhex(index_1.decode("utf-8")) + self.validator.assert_valid( + method_name="multiInputMultiOutput", + parameter_name="index_2", + argument_value=index_2, + ) + return (index_0, index_1, index_2) + + def call( + self, + index_0: int, + index_1: bytes, + index_2: str, + tx_params: Optional[TxParams] = None, + ) -> Tuple[bytes, bytes, str]: + """Execute underlying contract method via eth_call. + + Tests decoding when the input and output are complex and have more than + one argument. + + :param tx_params: transaction parameters + + """ + (index_0, index_1, index_2) = self.validate_and_normalize_inputs( + index_0, index_1, index_2 + ) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(index_0, index_1, index_2).call( + tx_params.as_dict() ) - def ecrecover_fn( + def send_transaction( + self, + index_0: int, + index_1: bytes, + index_2: str, + tx_params: Optional[TxParams] = None, + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + Tests decoding when the input and output are complex and have more than + one argument. + + :param tx_params: transaction parameters + + """ + (index_0, index_1, index_2) = self.validate_and_normalize_inputs( + index_0, index_1, index_2 + ) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(index_0, index_1, index_2).transact( + tx_params.as_dict() + ) + + def estimate_gas( + self, + index_0: int, + index_1: bytes, + index_2: str, + tx_params: Optional[TxParams] = None, + ) -> int: + """Estimate gas consumption of method call.""" + (index_0, index_1, index_2) = self.validate_and_normalize_inputs( + index_0, index_1, index_2 + ) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(index_0, index_1, index_2).estimateGas( + tx_params.as_dict() + ) + + +class EcrecoverFnMethod(ContractMethod): + """Various interfaces to the ecrecoverFn method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def validate_and_normalize_inputs( + self, _hash: bytes, v: int, r: bytes, s: bytes + ): + """Validate the inputs to the ecrecoverFn method.""" + self.validator.assert_valid( + method_name="ecrecoverFn", + parameter_name="hash", + argument_value=_hash, + ) + self.validator.assert_valid( + method_name="ecrecoverFn", parameter_name="v", argument_value=v + ) + self.validator.assert_valid( + method_name="ecrecoverFn", parameter_name="r", argument_value=r + ) + self.validator.assert_valid( + method_name="ecrecoverFn", parameter_name="s", argument_value=s + ) + return (_hash, v, r, s) + + def call( self, _hash: bytes, v: int, @@ -205,149 +533,425 @@ class AbiGenDummy(BaseContractWrapper): s: bytes, tx_params: Optional[TxParams] = None, ) -> str: - """Execute underlying, same-named contract method. + """Execute underlying contract method via eth_call. + test that devdocs will be generated and that multiline devdocs will + look okay + + :param hash: description of some hash. Let's make this line super long + to demonstrate hanging indents for method params. It has to be more + than one hundred twenty columns. + :param r: ECDSA r output + :param s: ECDSA s output + :param v: some v, recovery id :param tx_params: transaction parameters - + :returns: the signerAddress that created this signature. this line too + is super long in order to demonstrate the proper hanging + indentation in generated code. """ - self.validator.assert_valid( - method_name='ecrecoverFn', - parameter_name='hash', - argument_value=_hash, - ) - self.validator.assert_valid( - method_name='ecrecoverFn', - parameter_name='v', - argument_value=v, - ) - self.validator.assert_valid( - method_name='ecrecoverFn', - parameter_name='r', - argument_value=r, - ) - self.validator.assert_valid( - method_name='ecrecoverFn', - parameter_name='s', - argument_value=s, - ) - func = self._get_contract_instance( - self.contract_address - ).functions.ecrecoverFn( - _hash, - v, - r, - s - ) - return self._invoke_function_call( - func=func, - tx_params=tx_params, - view_only=True - ) + (_hash, v, r, s) = self.validate_and_normalize_inputs(_hash, v, r, s) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(_hash, v, r, s).call(tx_params.as_dict()) - def accepts_bytes( + def send_transaction( self, - a: bytes, + _hash: bytes, + v: int, + r: bytes, + s: bytes, tx_params: Optional[TxParams] = None, - ) -> None: - """Execute underlying, same-named contract method. + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + test that devdocs will be generated and that multiline devdocs will + look okay + + :param hash: description of some hash. Let's make this line super long + to demonstrate hanging indents for method params. It has to be more + than one hundred twenty columns. + :param r: ECDSA r output + :param s: ECDSA s output + :param v: some v, recovery id :param tx_params: transaction parameters - + :returns: the signerAddress that created this signature. this line too + is super long in order to demonstrate the proper hanging + indentation in generated code. """ + (_hash, v, r, s) = self.validate_and_normalize_inputs(_hash, v, r, s) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(_hash, v, r, s).transact( + tx_params.as_dict() + ) + + def estimate_gas( + self, + _hash: bytes, + v: int, + r: bytes, + s: bytes, + tx_params: Optional[TxParams] = None, + ) -> int: + """Estimate gas consumption of method call.""" + (_hash, v, r, s) = self.validate_and_normalize_inputs(_hash, v, r, s) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(_hash, v, r, s).estimateGas( + tx_params.as_dict() + ) + + +class AcceptsBytesMethod(ContractMethod): + """Various interfaces to the acceptsBytes method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def validate_and_normalize_inputs(self, a: bytes): + """Validate the inputs to the acceptsBytes method.""" self.validator.assert_valid( - method_name='acceptsBytes', - parameter_name='a', - argument_value=a, + method_name="acceptsBytes", parameter_name="a", argument_value=a ) a = bytes.fromhex(a.decode("utf-8")) - func = self._get_contract_instance( - self.contract_address - ).functions.acceptsBytes( - a - ) - return self._invoke_function_call( - func=func, - tx_params=tx_params, - view_only=True - ) + return a - def revert_with_constant( - self, - tx_params: Optional[TxParams] = None, - ) -> None: - """Execute underlying, same-named contract method. + def call(self, a: bytes, tx_params: Optional[TxParams] = None) -> None: + """Execute underlying contract method via eth_call. :param tx_params: transaction parameters """ - func = self._get_contract_instance( - self.contract_address - ).functions.revertWithConstant( - ) - return self._invoke_function_call( - func=func, - tx_params=tx_params, - view_only=True - ) + (a) = self.validate_and_normalize_inputs(a) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(a).call(tx_params.as_dict()) - def simple_revert( - self, - tx_params: Optional[TxParams] = None, - ) -> None: - """Execute underlying, same-named contract method. + def send_transaction( + self, a: bytes, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. :param tx_params: transaction parameters """ - func = self._get_contract_instance( - self.contract_address - ).functions.simpleRevert( - ) - return self._invoke_function_call( - func=func, - tx_params=tx_params, - view_only=True - ) + (a) = self.validate_and_normalize_inputs(a) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(a).transact(tx_params.as_dict()) - def nested_struct_output( + def estimate_gas( + self, a: bytes, tx_params: Optional[TxParams] = None + ) -> int: + """Estimate gas consumption of method call.""" + (a) = self.validate_and_normalize_inputs(a) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(a).estimateGas(tx_params.as_dict()) + + +class NoInputSimpleOutputMethod(ContractMethod): + """Various interfaces to the noInputSimpleOutput method.""" + + def __init__( self, - tx_params: Optional[TxParams] = None, - ) -> Tuple0xc9bdd2d5: - """Execute underlying, same-named contract method. + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def call(self, tx_params: Optional[TxParams] = None) -> int: + """Execute underlying contract method via eth_call. + + Tests decoding when input is empty and output is non-empty. :param tx_params: transaction parameters """ - func = self._get_contract_instance( - self.contract_address - ).functions.nestedStructOutput( - ) - return self._invoke_function_call( - func=func, - tx_params=tx_params, - view_only=True - ) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().call(tx_params.as_dict()) - def require_with_constant( - self, - tx_params: Optional[TxParams] = None, - ) -> None: - """Execute underlying, same-named contract method. + def send_transaction( + self, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + Tests decoding when input is empty and output is non-empty. :param tx_params: transaction parameters """ - func = self._get_contract_instance( - self.contract_address - ).functions.requireWithConstant( - ) - return self._invoke_function_call( - func=func, - tx_params=tx_params, - view_only=True - ) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().transact(tx_params.as_dict()) - def with_address_input( + def estimate_gas(self, tx_params: Optional[TxParams] = None) -> int: + """Estimate gas consumption of method call.""" + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().estimateGas(tx_params.as_dict()) + + +class RevertWithConstantMethod(ContractMethod): + """Various interfaces to the revertWithConstant method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def call(self, tx_params: Optional[TxParams] = None) -> None: + """Execute underlying contract method via eth_call. + + :param tx_params: transaction parameters + + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().call(tx_params.as_dict()) + + def send_transaction( + self, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + :param tx_params: transaction parameters + + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().transact(tx_params.as_dict()) + + def estimate_gas(self, tx_params: Optional[TxParams] = None) -> int: + """Estimate gas consumption of method call.""" + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().estimateGas(tx_params.as_dict()) + + +class SimpleRevertMethod(ContractMethod): + """Various interfaces to the simpleRevert method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def call(self, tx_params: Optional[TxParams] = None) -> None: + """Execute underlying contract method via eth_call. + + :param tx_params: transaction parameters + + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().call(tx_params.as_dict()) + + def send_transaction( + self, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + :param tx_params: transaction parameters + + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().transact(tx_params.as_dict()) + + def estimate_gas(self, tx_params: Optional[TxParams] = None) -> int: + """Estimate gas consumption of method call.""" + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().estimateGas(tx_params.as_dict()) + + +class MethodUsingNestedStructWithInnerStructNotUsedElsewhereMethod( + ContractMethod +): + """Various interfaces to the methodUsingNestedStructWithInnerStructNotUsedElsewhere method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def call(self, tx_params: Optional[TxParams] = None) -> Tuple0x1b9da225: + """Execute underlying contract method via eth_call. + + :param tx_params: transaction parameters + + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().call(tx_params.as_dict()) + + def send_transaction( + self, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + :param tx_params: transaction parameters + + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().transact(tx_params.as_dict()) + + def estimate_gas(self, tx_params: Optional[TxParams] = None) -> int: + """Estimate gas consumption of method call.""" + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().estimateGas(tx_params.as_dict()) + + +class NestedStructOutputMethod(ContractMethod): + """Various interfaces to the nestedStructOutput method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def call(self, tx_params: Optional[TxParams] = None) -> Tuple0xc9bdd2d5: + """Execute underlying contract method via eth_call. + + :param tx_params: transaction parameters + + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().call(tx_params.as_dict()) + + def send_transaction( + self, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + :param tx_params: transaction parameters + + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().transact(tx_params.as_dict()) + + def estimate_gas(self, tx_params: Optional[TxParams] = None) -> int: + """Estimate gas consumption of method call.""" + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().estimateGas(tx_params.as_dict()) + + +class RequireWithConstantMethod(ContractMethod): + """Various interfaces to the requireWithConstant method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def call(self, tx_params: Optional[TxParams] = None) -> None: + """Execute underlying contract method via eth_call. + + :param tx_params: transaction parameters + + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().call(tx_params.as_dict()) + + def send_transaction( + self, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + :param tx_params: transaction parameters + + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().transact(tx_params.as_dict()) + + def estimate_gas(self, tx_params: Optional[TxParams] = None) -> int: + """Estimate gas consumption of method call.""" + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().estimateGas(tx_params.as_dict()) + + +class WithAddressInputMethod(ContractMethod): + """Various interfaces to the withAddressInput method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def validate_and_normalize_inputs( + self, x: str, a: int, b: int, y: str, c: int + ): + """Validate the inputs to the withAddressInput method.""" + self.validator.assert_valid( + method_name="withAddressInput", + parameter_name="x", + argument_value=x, + ) + x = self.validate_and_checksum_address(x) + self.validator.assert_valid( + method_name="withAddressInput", + parameter_name="a", + argument_value=a, + ) + # safeguard against fractional inputs + a = int(a) + self.validator.assert_valid( + method_name="withAddressInput", + parameter_name="b", + argument_value=b, + ) + # safeguard against fractional inputs + b = int(b) + self.validator.assert_valid( + method_name="withAddressInput", + parameter_name="y", + argument_value=y, + ) + y = self.validate_and_checksum_address(y) + self.validator.assert_valid( + method_name="withAddressInput", + parameter_name="c", + argument_value=c, + ) + # safeguard against fractional inputs + c = int(c) + return (x, a, b, y, c) + + def call( self, x: str, a: int, @@ -356,245 +960,1139 @@ class AbiGenDummy(BaseContractWrapper): c: int, tx_params: Optional[TxParams] = None, ) -> str: - """Execute underlying, same-named contract method. + """Execute underlying contract method via eth_call. :param tx_params: transaction parameters """ - self.validator.assert_valid( - method_name='withAddressInput', - parameter_name='x', - argument_value=x, - ) - x = self._validate_and_checksum_address(x) - self.validator.assert_valid( - method_name='withAddressInput', - parameter_name='a', - argument_value=a, - ) - # safeguard against fractional inputs - a = int(a) - self.validator.assert_valid( - method_name='withAddressInput', - parameter_name='b', - argument_value=b, - ) - # safeguard against fractional inputs - b = int(b) - self.validator.assert_valid( - method_name='withAddressInput', - parameter_name='y', - argument_value=y, - ) - y = self._validate_and_checksum_address(y) - self.validator.assert_valid( - method_name='withAddressInput', - parameter_name='c', - argument_value=c, - ) - # safeguard against fractional inputs - c = int(c) - func = self._get_contract_instance( - self.contract_address - ).functions.withAddressInput( - x, - a, - b, - y, - c - ) - return self._invoke_function_call( - func=func, - tx_params=tx_params, - view_only=True - ) + (x, a, b, y, c) = self.validate_and_normalize_inputs(x, a, b, y, c) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(x, a, b, y, c).call(tx_params.as_dict()) - def struct_input( + def send_transaction( self, - s: Tuple0xcf8ad995, + x: str, + a: int, + b: int, + y: str, + c: int, tx_params: Optional[TxParams] = None, - ) -> None: - """Execute underlying, same-named contract method. + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. :param tx_params: transaction parameters """ - self.validator.assert_valid( - method_name='structInput', - parameter_name='s', - argument_value=s, - ) - func = self._get_contract_instance( - self.contract_address - ).functions.structInput( - s - ) - return self._invoke_function_call( - func=func, - tx_params=tx_params, - view_only=True + (x, a, b, y, c) = self.validate_and_normalize_inputs(x, a, b, y, c) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(x, a, b, y, c).transact( + tx_params.as_dict() ) - def non_pure_method( + def estimate_gas( self, - tx_params: Optional[TxParams] = None, - view_only: bool = False, - ) -> Union[int, Union[HexBytes, bytes]]: - """Execute underlying, same-named contract method. - - :param tx_params: transaction parameters - :param view_only: whether to use transact() or call() - - :returns: if param `view_only`:code: is `True`:code:, then returns the - value returned from the underlying function; else returns the - transaction hash. - """ - func = self._get_contract_instance( - self.contract_address - ).functions.nonPureMethod( - ) - return self._invoke_function_call( - func=func, - tx_params=tx_params, - view_only=view_only - ) - - def simple_pure_function_with_input( - self, - x: int, + x: str, + a: int, + b: int, + y: str, + c: int, tx_params: Optional[TxParams] = None, ) -> int: - """Execute underlying, same-named contract method. + """Estimate gas consumption of method call.""" + (x, a, b, y, c) = self.validate_and_normalize_inputs(x, a, b, y, c) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(x, a, b, y, c).estimateGas( + tx_params.as_dict() + ) + + +class StructInputMethod(ContractMethod): + """Various interfaces to the structInput method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def validate_and_normalize_inputs(self, s: Tuple0xcf8ad995): + """Validate the inputs to the structInput method.""" + self.validator.assert_valid( + method_name="structInput", parameter_name="s", argument_value=s + ) + return s + + def call( + self, s: Tuple0xcf8ad995, tx_params: Optional[TxParams] = None + ) -> None: + """Execute underlying contract method via eth_call. :param tx_params: transaction parameters """ + (s) = self.validate_and_normalize_inputs(s) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(s).call(tx_params.as_dict()) + + def send_transaction( + self, s: Tuple0xcf8ad995, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + :param tx_params: transaction parameters + + """ + (s) = self.validate_and_normalize_inputs(s) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(s).transact(tx_params.as_dict()) + + def estimate_gas( + self, s: Tuple0xcf8ad995, tx_params: Optional[TxParams] = None + ) -> int: + """Estimate gas consumption of method call.""" + (s) = self.validate_and_normalize_inputs(s) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(s).estimateGas(tx_params.as_dict()) + + +class NonPureMethodMethod(ContractMethod): + """Various interfaces to the nonPureMethod method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def call( + self, tx_params: Optional[TxParams] = None + ) -> Union[int, Union[HexBytes, bytes]]: + """Execute underlying contract method via eth_call. + + :param tx_params: transaction parameters + :returns: the return value of the underlying method. + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().call(tx_params.as_dict()) + + def send_transaction( + self, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + :param tx_params: transaction parameters + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().transact(tx_params.as_dict()) + + def estimate_gas(self, tx_params: Optional[TxParams] = None) -> int: + """Estimate gas consumption of method call.""" + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().estimateGas(tx_params.as_dict()) + + +class ComplexInputComplexOutputMethod(ContractMethod): + """Various interfaces to the complexInputComplexOutput method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def validate_and_normalize_inputs(self, complex_input: Tuple0xf95128ef): + """Validate the inputs to the complexInputComplexOutput method.""" self.validator.assert_valid( - method_name='simplePureFunctionWithInput', - parameter_name='x', + method_name="complexInputComplexOutput", + parameter_name="complexInput", + argument_value=complex_input, + ) + return complex_input + + def call( + self, + complex_input: Tuple0xf95128ef, + tx_params: Optional[TxParams] = None, + ) -> Tuple0xa057bf41: + """Execute underlying contract method via eth_call. + + Tests decoding when the input and output are complex. + + :param tx_params: transaction parameters + + """ + (complex_input) = self.validate_and_normalize_inputs(complex_input) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(complex_input).call(tx_params.as_dict()) + + def send_transaction( + self, + complex_input: Tuple0xf95128ef, + tx_params: Optional[TxParams] = None, + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + Tests decoding when the input and output are complex. + + :param tx_params: transaction parameters + + """ + (complex_input) = self.validate_and_normalize_inputs(complex_input) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(complex_input).transact( + tx_params.as_dict() + ) + + def estimate_gas( + self, + complex_input: Tuple0xf95128ef, + tx_params: Optional[TxParams] = None, + ) -> int: + """Estimate gas consumption of method call.""" + (complex_input) = self.validate_and_normalize_inputs(complex_input) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(complex_input).estimateGas( + tx_params.as_dict() + ) + + +class NoInputNoOutputMethod(ContractMethod): + """Various interfaces to the noInputNoOutput method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def call(self, tx_params: Optional[TxParams] = None) -> None: + """Execute underlying contract method via eth_call. + + Tests decoding when both input and output are empty. + + :param tx_params: transaction parameters + + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().call(tx_params.as_dict()) + + def send_transaction( + self, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + Tests decoding when both input and output are empty. + + :param tx_params: transaction parameters + + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().transact(tx_params.as_dict()) + + def estimate_gas(self, tx_params: Optional[TxParams] = None) -> int: + """Estimate gas consumption of method call.""" + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().estimateGas(tx_params.as_dict()) + + +class SimplePureFunctionWithInputMethod(ContractMethod): + """Various interfaces to the simplePureFunctionWithInput method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def validate_and_normalize_inputs(self, x: int): + """Validate the inputs to the simplePureFunctionWithInput method.""" + self.validator.assert_valid( + method_name="simplePureFunctionWithInput", + parameter_name="x", argument_value=x, ) # safeguard against fractional inputs x = int(x) - func = self._get_contract_instance( - self.contract_address - ).functions.simplePureFunctionWithInput( - x - ) - return self._invoke_function_call( - func=func, - tx_params=tx_params, - view_only=True - ) + return x - def non_pure_method_that_returns_nothing( - self, - tx_params: Optional[TxParams] = None, - view_only: bool = False, - ) -> Union[None, Union[HexBytes, bytes]]: - """Execute underlying, same-named contract method. + def call(self, x: int, tx_params: Optional[TxParams] = None) -> int: + """Execute underlying contract method via eth_call. :param tx_params: transaction parameters - :param view_only: whether to use transact() or call() - :returns: if param `view_only`:code: is `True`:code:, then returns the - value returned from the underlying function; else returns the - transaction hash. """ - func = self._get_contract_instance( - self.contract_address - ).functions.nonPureMethodThatReturnsNothing( - ) - return self._invoke_function_call( - func=func, - tx_params=tx_params, - view_only=view_only - ) + (x) = self.validate_and_normalize_inputs(x) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(x).call(tx_params.as_dict()) - def simple_pure_function( - self, - tx_params: Optional[TxParams] = None, + def send_transaction( + self, x: int, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + :param tx_params: transaction parameters + + """ + (x) = self.validate_and_normalize_inputs(x) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(x).transact(tx_params.as_dict()) + + def estimate_gas( + self, x: int, tx_params: Optional[TxParams] = None ) -> int: - """Execute underlying, same-named contract method. + """Estimate gas consumption of method call.""" + (x) = self.validate_and_normalize_inputs(x) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(x).estimateGas(tx_params.as_dict()) - :param tx_params: transaction parameters - """ - func = self._get_contract_instance( - self.contract_address - ).functions.simplePureFunction( - ) - return self._invoke_function_call( - func=func, - tx_params=tx_params, - view_only=True - ) +class NonPureMethodThatReturnsNothingMethod(ContractMethod): + """Various interfaces to the nonPureMethodThatReturnsNothing method.""" - def nested_struct_input( + def __init__( self, - n: Tuple0xc9bdd2d5, - tx_params: Optional[TxParams] = None, - ) -> None: - """Execute underlying, same-named contract method. + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def call( + self, tx_params: Optional[TxParams] = None + ) -> Union[None, Union[HexBytes, bytes]]: + """Execute underlying contract method via eth_call. + + :param tx_params: transaction parameters + :returns: the return value of the underlying method. + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().call(tx_params.as_dict()) + + def send_transaction( + self, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + :param tx_params: transaction parameters + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().transact(tx_params.as_dict()) + + def estimate_gas(self, tx_params: Optional[TxParams] = None) -> int: + """Estimate gas consumption of method call.""" + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().estimateGas(tx_params.as_dict()) + + +class SimplePureFunctionMethod(ContractMethod): + """Various interfaces to the simplePureFunction method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def call(self, tx_params: Optional[TxParams] = None) -> int: + """Execute underlying contract method via eth_call. :param tx_params: transaction parameters """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().call(tx_params.as_dict()) + + def send_transaction( + self, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + :param tx_params: transaction parameters + + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().transact(tx_params.as_dict()) + + def estimate_gas(self, tx_params: Optional[TxParams] = None) -> int: + """Estimate gas consumption of method call.""" + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().estimateGas(tx_params.as_dict()) + + +class NestedStructInputMethod(ContractMethod): + """Various interfaces to the nestedStructInput method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def validate_and_normalize_inputs(self, n: Tuple0xc9bdd2d5): + """Validate the inputs to the nestedStructInput method.""" self.validator.assert_valid( - method_name='nestedStructInput', - parameter_name='n', + method_name="nestedStructInput", + parameter_name="n", argument_value=n, ) - func = self._get_contract_instance( - self.contract_address - ).functions.nestedStructInput( - n - ) - return self._invoke_function_call( - func=func, - tx_params=tx_params, - view_only=True - ) + return n - def struct_output( + def call( + self, n: Tuple0xc9bdd2d5, tx_params: Optional[TxParams] = None + ) -> None: + """Execute underlying contract method via eth_call. + + :param tx_params: transaction parameters + + """ + (n) = self.validate_and_normalize_inputs(n) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(n).call(tx_params.as_dict()) + + def send_transaction( + self, n: Tuple0xc9bdd2d5, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + :param tx_params: transaction parameters + + """ + (n) = self.validate_and_normalize_inputs(n) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(n).transact(tx_params.as_dict()) + + def estimate_gas( + self, n: Tuple0xc9bdd2d5, tx_params: Optional[TxParams] = None + ) -> int: + """Estimate gas consumption of method call.""" + (n) = self.validate_and_normalize_inputs(n) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(n).estimateGas(tx_params.as_dict()) + + +class MethodReturningMultipleValuesMethod(ContractMethod): + """Various interfaces to the methodReturningMultipleValues method.""" + + def __init__( self, - tx_params: Optional[TxParams] = None, - ) -> Tuple0xcf8ad995: - """Execute underlying, same-named contract method. + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def call(self, tx_params: Optional[TxParams] = None) -> Tuple[int, str]: + """Execute underlying contract method via eth_call. + + :param tx_params: transaction parameters + + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().call(tx_params.as_dict()) + + def send_transaction( + self, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + :param tx_params: transaction parameters + + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().transact(tx_params.as_dict()) + + def estimate_gas(self, tx_params: Optional[TxParams] = None) -> int: + """Estimate gas consumption of method call.""" + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().estimateGas(tx_params.as_dict()) + + +class MethodReturningArrayOfStructsMethod(ContractMethod): + """Various interfaces to the methodReturningArrayOfStructs method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def call( + self, tx_params: Optional[TxParams] = None + ) -> List[Tuple0xcf8ad995]: + """Execute underlying contract method via eth_call. + + :param tx_params: transaction parameters + + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().call(tx_params.as_dict()) + + def send_transaction( + self, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + :param tx_params: transaction parameters + + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().transact(tx_params.as_dict()) + + def estimate_gas(self, tx_params: Optional[TxParams] = None) -> int: + """Estimate gas consumption of method call.""" + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().estimateGas(tx_params.as_dict()) + + +class StructOutputMethod(ContractMethod): + """Various interfaces to the structOutput method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def call(self, tx_params: Optional[TxParams] = None) -> Tuple0xcf8ad995: + """Execute underlying contract method via eth_call. a method that returns a struct :param tx_params: transaction parameters :returns: a Struct struct """ - func = self._get_contract_instance( - self.contract_address - ).functions.structOutput( - ) - return self._invoke_function_call( - func=func, - tx_params=tx_params, - view_only=True - ) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().call(tx_params.as_dict()) - def pure_function_with_constant( + def send_transaction( + self, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + a method that returns a struct + + :param tx_params: transaction parameters + :returns: a Struct struct + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().transact(tx_params.as_dict()) + + def estimate_gas(self, tx_params: Optional[TxParams] = None) -> int: + """Estimate gas consumption of method call.""" + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().estimateGas(tx_params.as_dict()) + + +class PureFunctionWithConstantMethod(ContractMethod): + """Various interfaces to the pureFunctionWithConstant method.""" + + def __init__( self, - tx_params: Optional[TxParams] = None, - ) -> int: - """Execute underlying, same-named contract method. + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def call(self, tx_params: Optional[TxParams] = None) -> int: + """Execute underlying contract method via eth_call. :param tx_params: transaction parameters """ - func = self._get_contract_instance( - self.contract_address - ).functions.pureFunctionWithConstant( + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().call(tx_params.as_dict()) + + def send_transaction( + self, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + :param tx_params: transaction parameters + + """ + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().transact(tx_params.as_dict()) + + def estimate_gas(self, tx_params: Optional[TxParams] = None) -> int: + """Estimate gas consumption of method call.""" + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method().estimateGas(tx_params.as_dict()) + + +class SimpleInputNoOutputMethod(ContractMethod): + """Various interfaces to the simpleInputNoOutput method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def validate_and_normalize_inputs(self, index_0: int): + """Validate the inputs to the simpleInputNoOutput method.""" + self.validator.assert_valid( + method_name="simpleInputNoOutput", + parameter_name="index_0", + argument_value=index_0, ) - return self._invoke_function_call( - func=func, - tx_params=tx_params, - view_only=True + # safeguard against fractional inputs + index_0 = int(index_0) + return index_0 + + def call(self, index_0: int, tx_params: Optional[TxParams] = None) -> None: + """Execute underlying contract method via eth_call. + + Tests decoding when input is not empty but output is empty. + + :param tx_params: transaction parameters + + """ + (index_0) = self.validate_and_normalize_inputs(index_0) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(index_0).call(tx_params.as_dict()) + + def send_transaction( + self, index_0: int, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + Tests decoding when input is not empty but output is empty. + + :param tx_params: transaction parameters + + """ + (index_0) = self.validate_and_normalize_inputs(index_0) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(index_0).transact(tx_params.as_dict()) + + def estimate_gas( + self, index_0: int, tx_params: Optional[TxParams] = None + ) -> int: + """Estimate gas consumption of method call.""" + (index_0) = self.validate_and_normalize_inputs(index_0) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(index_0).estimateGas(tx_params.as_dict()) + + +class OverloadedMethod2Method(ContractMethod): + """Various interfaces to the overloadedMethod method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def validate_and_normalize_inputs(self, a: str): + """Validate the inputs to the overloadedMethod method.""" + self.validator.assert_valid( + method_name="overloadedMethod", + parameter_name="a", + argument_value=a, ) + return a + + def call(self, a: str, tx_params: Optional[TxParams] = None) -> None: + """Execute underlying contract method via eth_call. + + :param tx_params: transaction parameters + + """ + (a) = self.validate_and_normalize_inputs(a) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(a).call(tx_params.as_dict()) + + def send_transaction( + self, a: str, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + :param tx_params: transaction parameters + + """ + (a) = self.validate_and_normalize_inputs(a) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(a).transact(tx_params.as_dict()) + + def estimate_gas( + self, a: str, tx_params: Optional[TxParams] = None + ) -> int: + """Estimate gas consumption of method call.""" + (a) = self.validate_and_normalize_inputs(a) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(a).estimateGas(tx_params.as_dict()) + + +class OverloadedMethod1Method(ContractMethod): + """Various interfaces to the overloadedMethod method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def validate_and_normalize_inputs(self, a: int): + """Validate the inputs to the overloadedMethod method.""" + self.validator.assert_valid( + method_name="overloadedMethod", + parameter_name="a", + argument_value=a, + ) + return a + + def call(self, a: int, tx_params: Optional[TxParams] = None) -> None: + """Execute underlying contract method via eth_call. + + :param tx_params: transaction parameters + + """ + (a) = self.validate_and_normalize_inputs(a) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(a).call(tx_params.as_dict()) + + def send_transaction( + self, a: int, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + :param tx_params: transaction parameters + + """ + (a) = self.validate_and_normalize_inputs(a) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(a).transact(tx_params.as_dict()) + + def estimate_gas( + self, a: int, tx_params: Optional[TxParams] = None + ) -> int: + """Estimate gas consumption of method call.""" + (a) = self.validate_and_normalize_inputs(a) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(a).estimateGas(tx_params.as_dict()) + + +# pylint: disable=too-many-public-methods,too-many-instance-attributes +class AbiGenDummy: + """Wrapper class for AbiGenDummy Solidity contract. + + All method parameters of type `bytes`:code: should be encoded as UTF-8, + which can be accomplished via `str.encode("utf_8")`:code:. + """ + + simple_require: SimpleRequireMethod + """Constructor-initialized instance of + :class:`SimpleRequireMethod`. + """ + + accepts_an_array_of_bytes: AcceptsAnArrayOfBytesMethod + """Constructor-initialized instance of + :class:`AcceptsAnArrayOfBytesMethod`. + """ + + simple_input_simple_output: SimpleInputSimpleOutputMethod + """Constructor-initialized instance of + :class:`SimpleInputSimpleOutputMethod`. + """ + + withdraw: WithdrawMethod + """Constructor-initialized instance of + :class:`WithdrawMethod`. + """ + + multi_input_multi_output: MultiInputMultiOutputMethod + """Constructor-initialized instance of + :class:`MultiInputMultiOutputMethod`. + """ + + ecrecover_fn: EcrecoverFnMethod + """Constructor-initialized instance of + :class:`EcrecoverFnMethod`. + """ + + accepts_bytes: AcceptsBytesMethod + """Constructor-initialized instance of + :class:`AcceptsBytesMethod`. + """ + + no_input_simple_output: NoInputSimpleOutputMethod + """Constructor-initialized instance of + :class:`NoInputSimpleOutputMethod`. + """ + + revert_with_constant: RevertWithConstantMethod + """Constructor-initialized instance of + :class:`RevertWithConstantMethod`. + """ + + simple_revert: SimpleRevertMethod + """Constructor-initialized instance of + :class:`SimpleRevertMethod`. + """ + + method_using_nested_struct_with_inner_struct_not_used_elsewhere: MethodUsingNestedStructWithInnerStructNotUsedElsewhereMethod + """Constructor-initialized instance of + :class:`MethodUsingNestedStructWithInnerStructNotUsedElsewhereMethod`. + """ + + nested_struct_output: NestedStructOutputMethod + """Constructor-initialized instance of + :class:`NestedStructOutputMethod`. + """ + + require_with_constant: RequireWithConstantMethod + """Constructor-initialized instance of + :class:`RequireWithConstantMethod`. + """ + + with_address_input: WithAddressInputMethod + """Constructor-initialized instance of + :class:`WithAddressInputMethod`. + """ + + struct_input: StructInputMethod + """Constructor-initialized instance of + :class:`StructInputMethod`. + """ + + non_pure_method: NonPureMethodMethod + """Constructor-initialized instance of + :class:`NonPureMethodMethod`. + """ + + complex_input_complex_output: ComplexInputComplexOutputMethod + """Constructor-initialized instance of + :class:`ComplexInputComplexOutputMethod`. + """ + + no_input_no_output: NoInputNoOutputMethod + """Constructor-initialized instance of + :class:`NoInputNoOutputMethod`. + """ + + simple_pure_function_with_input: SimplePureFunctionWithInputMethod + """Constructor-initialized instance of + :class:`SimplePureFunctionWithInputMethod`. + """ + + non_pure_method_that_returns_nothing: NonPureMethodThatReturnsNothingMethod + """Constructor-initialized instance of + :class:`NonPureMethodThatReturnsNothingMethod`. + """ + + simple_pure_function: SimplePureFunctionMethod + """Constructor-initialized instance of + :class:`SimplePureFunctionMethod`. + """ + + nested_struct_input: NestedStructInputMethod + """Constructor-initialized instance of + :class:`NestedStructInputMethod`. + """ + + method_returning_multiple_values: MethodReturningMultipleValuesMethod + """Constructor-initialized instance of + :class:`MethodReturningMultipleValuesMethod`. + """ + + method_returning_array_of_structs: MethodReturningArrayOfStructsMethod + """Constructor-initialized instance of + :class:`MethodReturningArrayOfStructsMethod`. + """ + + struct_output: StructOutputMethod + """Constructor-initialized instance of + :class:`StructOutputMethod`. + """ + + pure_function_with_constant: PureFunctionWithConstantMethod + """Constructor-initialized instance of + :class:`PureFunctionWithConstantMethod`. + """ + + simple_input_no_output: SimpleInputNoOutputMethod + """Constructor-initialized instance of + :class:`SimpleInputNoOutputMethod`. + """ + + overloaded_method2: OverloadedMethod2Method + """Constructor-initialized instance of + :class:`OverloadedMethod2Method`. + """ + + overloaded_method1: OverloadedMethod1Method + """Constructor-initialized instance of + :class:`OverloadedMethod1Method`. + """ + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + validator: AbiGenDummyValidator = None, + ): + """Get an instance of wrapper for smart contract. + + :param provider: instance of :class:`web3.providers.base.BaseProvider` + :param contract_address: where the contract has been deployed + :param validator: for validation of method inputs. + """ + self.contract_address = contract_address + + if not validator: + validator = AbiGenDummyValidator(provider, contract_address) + + self._web3_eth = Web3( # type: ignore # pylint: disable=no-member + provider + ).eth + + functions = self._web3_eth.contract( + address=to_checksum_address(contract_address), + abi=AbiGenDummy.abi(), + ).functions + + self.simple_require = SimpleRequireMethod( + provider, contract_address, functions.simpleRequire, validator + ) + + self.accepts_an_array_of_bytes = AcceptsAnArrayOfBytesMethod( + provider, + contract_address, + functions.acceptsAnArrayOfBytes, + validator, + ) + + self.simple_input_simple_output = SimpleInputSimpleOutputMethod( + provider, + contract_address, + functions.simpleInputSimpleOutput, + validator, + ) + + self.withdraw = WithdrawMethod( + provider, contract_address, functions.withdraw, validator + ) + + self.multi_input_multi_output = MultiInputMultiOutputMethod( + provider, + contract_address, + functions.multiInputMultiOutput, + validator, + ) + + self.ecrecover_fn = EcrecoverFnMethod( + provider, contract_address, functions.ecrecoverFn, validator + ) + + self.accepts_bytes = AcceptsBytesMethod( + provider, contract_address, functions.acceptsBytes, validator + ) + + self.no_input_simple_output = NoInputSimpleOutputMethod( + provider, + contract_address, + functions.noInputSimpleOutput, + validator, + ) + + self.revert_with_constant = RevertWithConstantMethod( + provider, contract_address, functions.revertWithConstant, validator + ) + + self.simple_revert = SimpleRevertMethod( + provider, contract_address, functions.simpleRevert, validator + ) + + self.method_using_nested_struct_with_inner_struct_not_used_elsewhere = MethodUsingNestedStructWithInnerStructNotUsedElsewhereMethod( + provider, + contract_address, + functions.methodUsingNestedStructWithInnerStructNotUsedElsewhere, + validator, + ) + + self.nested_struct_output = NestedStructOutputMethod( + provider, contract_address, functions.nestedStructOutput, validator + ) + + self.require_with_constant = RequireWithConstantMethod( + provider, + contract_address, + functions.requireWithConstant, + validator, + ) + + self.with_address_input = WithAddressInputMethod( + provider, contract_address, functions.withAddressInput, validator + ) + + self.struct_input = StructInputMethod( + provider, contract_address, functions.structInput, validator + ) + + self.non_pure_method = NonPureMethodMethod( + provider, contract_address, functions.nonPureMethod, validator + ) + + self.complex_input_complex_output = ComplexInputComplexOutputMethod( + provider, + contract_address, + functions.complexInputComplexOutput, + validator, + ) + + self.no_input_no_output = NoInputNoOutputMethod( + provider, contract_address, functions.noInputNoOutput, validator + ) + + self.simple_pure_function_with_input = SimplePureFunctionWithInputMethod( + provider, + contract_address, + functions.simplePureFunctionWithInput, + validator, + ) + + self.non_pure_method_that_returns_nothing = NonPureMethodThatReturnsNothingMethod( + provider, + contract_address, + functions.nonPureMethodThatReturnsNothing, + validator, + ) + + self.simple_pure_function = SimplePureFunctionMethod( + provider, contract_address, functions.simplePureFunction, validator + ) + + self.nested_struct_input = NestedStructInputMethod( + provider, contract_address, functions.nestedStructInput, validator + ) + + self.method_returning_multiple_values = MethodReturningMultipleValuesMethod( + provider, + contract_address, + functions.methodReturningMultipleValues, + validator, + ) + + self.method_returning_array_of_structs = MethodReturningArrayOfStructsMethod( + provider, + contract_address, + functions.methodReturningArrayOfStructs, + validator, + ) + + self.struct_output = StructOutputMethod( + provider, contract_address, functions.structOutput, validator + ) + + self.pure_function_with_constant = PureFunctionWithConstantMethod( + provider, + contract_address, + functions.pureFunctionWithConstant, + validator, + ) + + self.simple_input_no_output = SimpleInputNoOutputMethod( + provider, + contract_address, + functions.simpleInputNoOutput, + validator, + ) + + self.overloaded_method2 = OverloadedMethod2Method( + provider, contract_address, functions.overloadedMethod, validator + ) + + self.overloaded_method1 = OverloadedMethod1Method( + provider, contract_address, functions.overloadedMethod, validator + ) + + def get_withdrawal_event( + self, tx_hash: Union[HexBytes, bytes] + ) -> Tuple[AttributeDict]: + """Get log entry for Withdrawal event. + + :param tx_hash: hash of transaction emitting Withdrawal event + """ + tx_receipt = self._web3_eth.getTransactionReceipt(tx_hash) + return ( + self._web3_eth.contract( + address=to_checksum_address(self.contract_address), + abi=AbiGenDummy.abi(), + ) + .events.Withdrawal() + .processReceipt(tx_receipt) + ) + def get_an_event_event( self, tx_hash: Union[HexBytes, bytes] ) -> Tuple[AttributeDict]: @@ -604,7 +2102,10 @@ class AbiGenDummy(BaseContractWrapper): """ tx_receipt = self._web3_eth.getTransactionReceipt(tx_hash) return ( - self._get_contract_instance(self.contract_address) + self._web3_eth.contract( + address=to_checksum_address(self.contract_address), + abi=AbiGenDummy.abi(), + ) .events.AnEvent() .processReceipt(tx_receipt) ) @@ -613,7 +2114,8 @@ class AbiGenDummy(BaseContractWrapper): def abi(): """Return the ABI to the underlying contract.""" return json.loads( - '[{"constant":true,"inputs":[],"name":"simpleRequire","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"a","type":"bytes[]"}],"name":"acceptsAnArrayOfBytes","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"hash","type":"bytes32"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"}],"name":"ecrecoverFn","outputs":[{"name":"signerAddress","type":"address"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"a","type":"bytes"}],"name":"acceptsBytes","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"revertWithConstant","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"simpleRevert","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"nestedStructOutput","outputs":[{"components":[{"components":[{"name":"someBytes","type":"bytes"},{"name":"anInteger","type":"uint32"},{"name":"aDynamicArrayOfBytes","type":"bytes[]"},{"name":"aString","type":"string"}],"name":"innerStruct","type":"tuple"},{"name":"description","type":"string"}],"name":"","type":"tuple"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"requireWithConstant","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"x","type":"address"},{"name":"a","type":"uint256"},{"name":"b","type":"uint256"},{"name":"y","type":"address"},{"name":"c","type":"uint256"}],"name":"withAddressInput","outputs":[{"name":"z","type":"address"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"components":[{"name":"someBytes","type":"bytes"},{"name":"anInteger","type":"uint32"},{"name":"aDynamicArrayOfBytes","type":"bytes[]"},{"name":"aString","type":"string"}],"name":"s","type":"tuple"}],"name":"structInput","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"nonPureMethod","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"x","type":"uint256"}],"name":"simplePureFunctionWithInput","outputs":[{"name":"sum","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"nonPureMethodThatReturnsNothing","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"simplePureFunction","outputs":[{"name":"result","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"components":[{"components":[{"name":"someBytes","type":"bytes"},{"name":"anInteger","type":"uint32"},{"name":"aDynamicArrayOfBytes","type":"bytes[]"},{"name":"aString","type":"string"}],"name":"innerStruct","type":"tuple"},{"name":"description","type":"string"}],"name":"n","type":"tuple"}],"name":"nestedStructInput","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"structOutput","outputs":[{"components":[{"name":"someBytes","type":"bytes"},{"name":"anInteger","type":"uint32"},{"name":"aDynamicArrayOfBytes","type":"bytes[]"},{"name":"aString","type":"string"}],"name":"s","type":"tuple"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"pureFunctionWithConstant","outputs":[{"name":"someConstant","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"param","type":"uint8"}],"name":"AnEvent","type":"event"}]' # noqa: E501 (line-too-long) + '[{"constant":true,"inputs":[],"name":"simpleRequire","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes[]","name":"a","type":"bytes[]"}],"name":"acceptsAnArrayOfBytes","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"index_0","type":"uint256"}],"name":"simpleInputSimpleOutput","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"index_0","type":"uint256"},{"internalType":"bytes","name":"index_1","type":"bytes"},{"internalType":"string","name":"index_2","type":"string"}],"name":"multiInputMultiOutput","outputs":[{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ecrecoverFn","outputs":[{"internalType":"address","name":"signerAddress","type":"address"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes","name":"a","type":"bytes"}],"name":"acceptsBytes","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"noInputSimpleOutput","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"revertWithConstant","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"simpleRevert","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"methodUsingNestedStructWithInnerStructNotUsedElsewhere","outputs":[{"components":[{"components":[{"internalType":"uint256","name":"aField","type":"uint256"}],"internalType":"struct AbiGenDummy.StructNotDirectlyUsedAnywhere","name":"innerStruct","type":"tuple"}],"internalType":"struct AbiGenDummy.NestedStructWithInnerStructNotUsedElsewhere","name":"","type":"tuple"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"nestedStructOutput","outputs":[{"components":[{"components":[{"internalType":"bytes","name":"someBytes","type":"bytes"},{"internalType":"uint32","name":"anInteger","type":"uint32"},{"internalType":"bytes[]","name":"aDynamicArrayOfBytes","type":"bytes[]"},{"internalType":"string","name":"aString","type":"string"}],"internalType":"struct AbiGenDummy.Struct","name":"innerStruct","type":"tuple"},{"internalType":"string","name":"description","type":"string"}],"internalType":"struct AbiGenDummy.NestedStruct","name":"","type":"tuple"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"requireWithConstant","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"x","type":"address"},{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"},{"internalType":"address","name":"y","type":"address"},{"internalType":"uint256","name":"c","type":"uint256"}],"name":"withAddressInput","outputs":[{"internalType":"address","name":"z","type":"address"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"components":[{"internalType":"bytes","name":"someBytes","type":"bytes"},{"internalType":"uint32","name":"anInteger","type":"uint32"},{"internalType":"bytes[]","name":"aDynamicArrayOfBytes","type":"bytes[]"},{"internalType":"string","name":"aString","type":"string"}],"internalType":"struct AbiGenDummy.Struct","name":"s","type":"tuple"}],"name":"structInput","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"nonPureMethod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"components":[{"internalType":"uint256","name":"foo","type":"uint256"},{"internalType":"bytes","name":"bar","type":"bytes"},{"internalType":"string","name":"car","type":"string"}],"internalType":"struct AbiGenDummy.ComplexInput","name":"complexInput","type":"tuple"}],"name":"complexInputComplexOutput","outputs":[{"components":[{"components":[{"internalType":"uint256","name":"foo","type":"uint256"},{"internalType":"bytes","name":"bar","type":"bytes"},{"internalType":"string","name":"car","type":"string"}],"internalType":"struct AbiGenDummy.ComplexInput","name":"input","type":"tuple"},{"internalType":"bytes","name":"lorem","type":"bytes"},{"internalType":"bytes","name":"ipsum","type":"bytes"},{"internalType":"string","name":"dolor","type":"string"}],"internalType":"struct AbiGenDummy.ComplexOutput","name":"","type":"tuple"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"noInputNoOutput","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"simplePureFunctionWithInput","outputs":[{"internalType":"uint256","name":"sum","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[],"name":"nonPureMethodThatReturnsNothing","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"simplePureFunction","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"components":[{"components":[{"internalType":"bytes","name":"someBytes","type":"bytes"},{"internalType":"uint32","name":"anInteger","type":"uint32"},{"internalType":"bytes[]","name":"aDynamicArrayOfBytes","type":"bytes[]"},{"internalType":"string","name":"aString","type":"string"}],"internalType":"struct AbiGenDummy.Struct","name":"innerStruct","type":"tuple"},{"internalType":"string","name":"description","type":"string"}],"internalType":"struct AbiGenDummy.NestedStruct","name":"n","type":"tuple"}],"name":"nestedStructInput","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"methodReturningMultipleValues","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"methodReturningArrayOfStructs","outputs":[{"components":[{"internalType":"bytes","name":"someBytes","type":"bytes"},{"internalType":"uint32","name":"anInteger","type":"uint32"},{"internalType":"bytes[]","name":"aDynamicArrayOfBytes","type":"bytes[]"},{"internalType":"string","name":"aString","type":"string"}],"internalType":"struct AbiGenDummy.Struct[]","name":"","type":"tuple[]"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"structOutput","outputs":[{"components":[{"internalType":"bytes","name":"someBytes","type":"bytes"},{"internalType":"uint32","name":"anInteger","type":"uint32"},{"internalType":"bytes[]","name":"aDynamicArrayOfBytes","type":"bytes[]"},{"internalType":"string","name":"aString","type":"string"}],"internalType":"struct AbiGenDummy.Struct","name":"s","type":"tuple"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"pureFunctionWithConstant","outputs":[{"internalType":"uint256","name":"someConstant","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"index_0","type":"uint256"}],"name":"simpleInputNoOutput","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"a","type":"string"}],"name":"overloadedMethod","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"int256","name":"a","type":"int256"}],"name":"overloadedMethod","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Withdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"param","type":"uint8"}],"name":"AnEvent","type":"event"}]' # noqa: E501 (line-too-long) ) + # pylint: disable=too-many-lines diff --git a/packages/abi-gen/test-cli/expected-output/python/lib_dummy/__init__.py b/packages/abi-gen/test-cli/expected-output/python/lib_dummy/__init__.py index 66bb91e528..1181817fdc 100644 --- a/packages/abi-gen/test-cli/expected-output/python/lib_dummy/__init__.py +++ b/packages/abi-gen/test-cli/expected-output/python/lib_dummy/__init__.py @@ -11,37 +11,18 @@ from typing import ( # pylint: disable=unused-import Union, ) +from eth_utils import to_checksum_address from mypy_extensions import TypedDict # pylint: disable=unused-import from hexbytes import HexBytes +from web3 import Web3 +from web3.contract import ContractFunction from web3.datastructures import AttributeDict from web3.providers.base import BaseProvider -from zero_ex.contract_wrappers._base_contract_wrapper import BaseContractWrapper +from zero_ex.contract_wrappers.bases import ContractMethod, Validator from zero_ex.contract_wrappers.tx_params import TxParams -class LibDummyValidatorBase: - """Base class for validating inputs to LibDummy methods.""" - def __init__( - self, - provider: BaseProvider, - contract_address: str, - private_key: str = None, - ): - """Initialize the instance.""" - - def assert_valid( - self, method_name: str, parameter_name: str, argument_value: Any - ): - """Raise an exception if method input is not valid. - - :param method_name: Name of the method whose input is to be validated. - :param parameter_name: Name of the parameter whose input is to be - validated. - :param argument_value: Value of argument to parameter to be validated. - """ - - # Try to import a custom validator class definition; if there isn't one, # declare one that we can instantiate for the default argument to the # constructor for LibDummy below. @@ -53,15 +34,14 @@ try: ) except ImportError: - class LibDummyValidator(LibDummyValidatorBase): # type: ignore + class LibDummyValidator( # type: ignore + Validator + ): """No-op input validator.""" - - - -# pylint: disable=too-many-public-methods -class LibDummy(BaseContractWrapper): +# pylint: disable=too-many-public-methods,too-many-instance-attributes +class LibDummy: """Wrapper class for LibDummy Solidity contract.""" def __init__( @@ -69,41 +49,26 @@ class LibDummy(BaseContractWrapper): provider: BaseProvider, contract_address: str, validator: LibDummyValidator = None, - private_key: str = None, ): """Get an instance of wrapper for smart contract. :param provider: instance of :class:`web3.providers.base.BaseProvider` :param contract_address: where the contract has been deployed - :param private_key: If specified, transactions will be signed locally, - via Web3.py's `eth.account.signTransaction()`:code:, before being - sent via `eth.sendRawTransaction()`:code:. + :param validator: for validation of method inputs. """ - super().__init__( - provider=provider, - contract_address=contract_address, - private_key=private_key, - ) + self.contract_address = contract_address if not validator: - validator = LibDummyValidator(provider, contract_address, private_key) + validator = LibDummyValidator(provider, contract_address) - self.validator = validator - - def _get_contract_instance(self, token_address): - """Get an instance of the smart contract at a specific address. - - :returns: contract object - """ - return self._contract_instance( - address=token_address, abi=LibDummy.abi() - ) + self._web3_eth = Web3( # type: ignore # pylint: disable=no-member + provider + ).eth @staticmethod def abi(): """Return the ABI to the underlying contract.""" - return json.loads( - '[]' # noqa: E501 (line-too-long) - ) + return json.loads("[]") # noqa: E501 (line-too-long) + # pylint: disable=too-many-lines diff --git a/packages/abi-gen/test-cli/expected-output/python/test_lib_dummy/__init__.py b/packages/abi-gen/test-cli/expected-output/python/test_lib_dummy/__init__.py index 5c4cab81d8..ebdd8c6c6a 100644 --- a/packages/abi-gen/test-cli/expected-output/python/test_lib_dummy/__init__.py +++ b/packages/abi-gen/test-cli/expected-output/python/test_lib_dummy/__init__.py @@ -11,37 +11,18 @@ from typing import ( # pylint: disable=unused-import Union, ) +from eth_utils import to_checksum_address from mypy_extensions import TypedDict # pylint: disable=unused-import from hexbytes import HexBytes +from web3 import Web3 +from web3.contract import ContractFunction from web3.datastructures import AttributeDict from web3.providers.base import BaseProvider -from zero_ex.contract_wrappers._base_contract_wrapper import BaseContractWrapper +from zero_ex.contract_wrappers.bases import ContractMethod, Validator from zero_ex.contract_wrappers.tx_params import TxParams -class TestLibDummyValidatorBase: - """Base class for validating inputs to TestLibDummy methods.""" - def __init__( - self, - provider: BaseProvider, - contract_address: str, - private_key: str = None, - ): - """Initialize the instance.""" - - def assert_valid( - self, method_name: str, parameter_name: str, argument_value: Any - ): - """Raise an exception if method input is not valid. - - :param method_name: Name of the method whose input is to be validated. - :param parameter_name: Name of the parameter whose input is to be - validated. - :param argument_value: Value of argument to parameter to be validated. - """ - - # Try to import a custom validator class definition; if there isn't one, # declare one that we can instantiate for the default argument to the # constructor for TestLibDummy below. @@ -53,106 +34,168 @@ try: ) except ImportError: - class TestLibDummyValidator(TestLibDummyValidatorBase): # type: ignore + class TestLibDummyValidator( # type: ignore + Validator + ): """No-op input validator.""" +class PublicAddConstantMethod(ContractMethod): + """Various interfaces to the publicAddConstant method.""" + + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def validate_and_normalize_inputs(self, x: int): + """Validate the inputs to the publicAddConstant method.""" + self.validator.assert_valid( + method_name="publicAddConstant", + parameter_name="x", + argument_value=x, + ) + # safeguard against fractional inputs + x = int(x) + return x + + def call(self, x: int, tx_params: Optional[TxParams] = None) -> int: + """Execute underlying contract method via eth_call. + + :param tx_params: transaction parameters + + """ + (x) = self.validate_and_normalize_inputs(x) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(x).call(tx_params.as_dict()) + + def send_transaction( + self, x: int, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + :param tx_params: transaction parameters + + """ + (x) = self.validate_and_normalize_inputs(x) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(x).transact(tx_params.as_dict()) + + def estimate_gas( + self, x: int, tx_params: Optional[TxParams] = None + ) -> int: + """Estimate gas consumption of method call.""" + (x) = self.validate_and_normalize_inputs(x) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(x).estimateGas(tx_params.as_dict()) +class PublicAddOneMethod(ContractMethod): + """Various interfaces to the publicAddOne method.""" -# pylint: disable=too-many-public-methods -class TestLibDummy(BaseContractWrapper): + def __init__( + self, + provider: BaseProvider, + contract_address: str, + contract_function: ContractFunction, + validator: Validator = None, + ): + """Persist instance data.""" + super().__init__(provider, contract_address, validator) + self.underlying_method = contract_function + + def validate_and_normalize_inputs(self, x: int): + """Validate the inputs to the publicAddOne method.""" + self.validator.assert_valid( + method_name="publicAddOne", parameter_name="x", argument_value=x + ) + # safeguard against fractional inputs + x = int(x) + return x + + def call(self, x: int, tx_params: Optional[TxParams] = None) -> int: + """Execute underlying contract method via eth_call. + + :param tx_params: transaction parameters + + """ + (x) = self.validate_and_normalize_inputs(x) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(x).call(tx_params.as_dict()) + + def send_transaction( + self, x: int, tx_params: Optional[TxParams] = None + ) -> Union[HexBytes, bytes]: + """Execute underlying contract method via eth_sendTransaction. + + :param tx_params: transaction parameters + + """ + (x) = self.validate_and_normalize_inputs(x) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(x).transact(tx_params.as_dict()) + + def estimate_gas( + self, x: int, tx_params: Optional[TxParams] = None + ) -> int: + """Estimate gas consumption of method call.""" + (x) = self.validate_and_normalize_inputs(x) + tx_params = super().normalize_tx_params(tx_params) + return self.underlying_method(x).estimateGas(tx_params.as_dict()) + + +# pylint: disable=too-many-public-methods,too-many-instance-attributes +class TestLibDummy: """Wrapper class for TestLibDummy Solidity contract.""" + public_add_constant: PublicAddConstantMethod + """Constructor-initialized instance of + :class:`PublicAddConstantMethod`. + """ + + public_add_one: PublicAddOneMethod + """Constructor-initialized instance of + :class:`PublicAddOneMethod`. + """ + def __init__( self, provider: BaseProvider, contract_address: str, validator: TestLibDummyValidator = None, - private_key: str = None, ): """Get an instance of wrapper for smart contract. :param provider: instance of :class:`web3.providers.base.BaseProvider` :param contract_address: where the contract has been deployed - :param private_key: If specified, transactions will be signed locally, - via Web3.py's `eth.account.signTransaction()`:code:, before being - sent via `eth.sendRawTransaction()`:code:. + :param validator: for validation of method inputs. """ - super().__init__( - provider=provider, - contract_address=contract_address, - private_key=private_key, - ) + self.contract_address = contract_address if not validator: - validator = TestLibDummyValidator(provider, contract_address, private_key) + validator = TestLibDummyValidator(provider, contract_address) - self.validator = validator + self._web3_eth = Web3( # type: ignore # pylint: disable=no-member + provider + ).eth - def _get_contract_instance(self, token_address): - """Get an instance of the smart contract at a specific address. + functions = self._web3_eth.contract( + address=to_checksum_address(contract_address), + abi=TestLibDummy.abi(), + ).functions - :returns: contract object - """ - return self._contract_instance( - address=token_address, abi=TestLibDummy.abi() + self.public_add_constant = PublicAddConstantMethod( + provider, contract_address, functions.publicAddConstant, validator ) - def public_add_constant( - self, - x: int, - tx_params: Optional[TxParams] = None, - ) -> int: - """Execute underlying, same-named contract method. - - :param tx_params: transaction parameters - - """ - self.validator.assert_valid( - method_name='publicAddConstant', - parameter_name='x', - argument_value=x, - ) - # safeguard against fractional inputs - x = int(x) - func = self._get_contract_instance( - self.contract_address - ).functions.publicAddConstant( - x - ) - return self._invoke_function_call( - func=func, - tx_params=tx_params, - view_only=True - ) - - def public_add_one( - self, - x: int, - tx_params: Optional[TxParams] = None, - ) -> int: - """Execute underlying, same-named contract method. - - :param tx_params: transaction parameters - - """ - self.validator.assert_valid( - method_name='publicAddOne', - parameter_name='x', - argument_value=x, - ) - # safeguard against fractional inputs - x = int(x) - func = self._get_contract_instance( - self.contract_address - ).functions.publicAddOne( - x - ) - return self._invoke_function_call( - func=func, - tx_params=tx_params, - view_only=True + self.public_add_one = PublicAddOneMethod( + provider, contract_address, functions.publicAddOne, validator ) @staticmethod @@ -162,4 +205,5 @@ class TestLibDummy(BaseContractWrapper): '[{"constant":true,"inputs":[{"name":"x","type":"uint256"}],"name":"publicAddConstant","outputs":[{"name":"result","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"x","type":"uint256"}],"name":"publicAddOne","outputs":[{"name":"result","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"}]' # noqa: E501 (line-too-long) ) + # pylint: disable=too-many-lines diff --git a/packages/abi-gen/test-cli/expected-output/typescript/abi_gen_dummy.ts b/packages/abi-gen/test-cli/expected-output/typescript/abi_gen_dummy.ts index 67ca4b9534..6e02229ffb 100644 --- a/packages/abi-gen/test-cli/expected-output/typescript/abi_gen_dummy.ts +++ b/packages/abi-gen/test-cli/expected-output/typescript/abi_gen_dummy.ts @@ -1,7 +1,14 @@ // tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma // tslint:disable:whitespace no-unbound-method no-trailing-whitespace // tslint:disable:no-unused-variable -import { BaseContract, PromiseWithTransactionHash } from '@0x/base-contract'; +import { + BaseContract, + BlockRange, + EventCallback, + IndexedFilterValues, + SubscriptionManager, + PromiseWithTransactionHash, +} from '@0x/base-contract'; import { schemas } from '@0x/json-schemas'; import { BlockParam, @@ -10,6 +17,7 @@ import { ContractAbi, ContractArtifact, DecodedLogArgs, + LogWithDecodedArgs, MethodAbi, TransactionReceiptWithDecodedLogs, TxData, @@ -23,12 +31,18 @@ import { assert } from '@0x/assert'; import * as ethers from 'ethers'; // tslint:enable:no-unused-variable -export type AbiGenDummyEventArgs = AbiGenDummyAnEventEventArgs; +export type AbiGenDummyEventArgs = AbiGenDummyWithdrawalEventArgs | AbiGenDummyAnEventEventArgs; export enum AbiGenDummyEvents { + Withdrawal = 'Withdrawal', AnEvent = 'AnEvent', } +export interface AbiGenDummyWithdrawalEventArgs extends DecodedLogArgs { + _owner: string; + _value: BigNumber; +} + export interface AbiGenDummyAnEventEventArgs extends DecodedLogArgs { param: number; } @@ -38,6 +52,11 @@ export interface AbiGenDummyAnEventEventArgs extends DecodedLogArgs { // tslint:disable-next-line:class-name export class AbiGenDummyContract extends BaseContract { public simpleRequire = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -69,13 +88,41 @@ export class AbiGenDummyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as AbiGenDummyContract; const abiEncodedTransactionData = self._strictEncodeArguments('simpleRequire()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('simpleRequire()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('simpleRequire()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * a method that accepts an array of bytes + */ public acceptsAnArrayOfBytes = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param a the array of bytes being accepted + */ async callAsync(a: string[], callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isArray('a', a); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -108,14 +155,354 @@ export class AbiGenDummyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param a the array of bytes being accepted + */ getABIEncodedTransactionData(a: string[]): string { assert.isArray('a', a); const self = (this as any) as AbiGenDummyContract; const abiEncodedTransactionData = self._strictEncodeArguments('acceptsAnArrayOfBytes(bytes[])', [a]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('acceptsAnArrayOfBytes(bytes[])'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('acceptsAnArrayOfBytes(bytes[])'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Tests decoding when both input and output are non-empty. + */ + public simpleInputSimpleOutput = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ + async callAsync( + index_0: BigNumber, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + assert.isBigNumber('index_0', index_0); + assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (defaultBlock !== undefined) { + assert.isBlockParam('defaultBlock', defaultBlock); + } + const self = (this as any) as AbiGenDummyContract; + const encodedData = self._strictEncodeArguments('simpleInputSimpleOutput(uint256)', [index_0]); + const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( + { + to: self.address, + ...callData, + data: encodedData, + }, + self._web3Wrapper.getContractDefaults(), + ); + callDataWithDefaults.from = callDataWithDefaults.from + ? callDataWithDefaults.from.toLowerCase() + : callDataWithDefaults.from; + + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + BaseContract._throwIfRevertWithReasonCallResult(rawCallResult); + const abiEncoder = self._lookupAbiEncoder('simpleInputSimpleOutput(uint256)'); + // tslint:disable boolean-naming + const result = abiEncoder.strictDecodeReturnValue(rawCallResult); + // tslint:enable boolean-naming + return result; + }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ + getABIEncodedTransactionData(index_0: BigNumber): string { + assert.isBigNumber('index_0', index_0); + const self = (this as any) as AbiGenDummyContract; + const abiEncodedTransactionData = self._strictEncodeArguments('simpleInputSimpleOutput(uint256)', [ + index_0, + ]); + return abiEncodedTransactionData; + }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('simpleInputSimpleOutput(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('simpleInputSimpleOutput(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + }; + public withdraw = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ + async sendTransactionAsync(wad: BigNumber, txData?: Partial | undefined): Promise { + assert.isBigNumber('wad', wad); + const self = (this as any) as AbiGenDummyContract; + const encodedData = self._strictEncodeArguments('withdraw(uint256)', [wad]); + const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( + { + to: self.address, + ...txData, + data: encodedData, + }, + self._web3Wrapper.getContractDefaults(), + self.withdraw.estimateGasAsync.bind(self, wad), + ); + if (txDataWithDefaults.from !== undefined) { + txDataWithDefaults.from = txDataWithDefaults.from.toLowerCase(); + } + + const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); + return txHash; + }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ + awaitTransactionSuccessAsync( + wad: BigNumber, + txData?: Partial, + pollingIntervalMs?: number, + timeoutMs?: number, + ): PromiseWithTransactionHash { + assert.isBigNumber('wad', wad); + const self = (this as any) as AbiGenDummyContract; + const txHashPromise = self.withdraw.sendTransactionAsync(wad, txData); + return new PromiseWithTransactionHash( + txHashPromise, + (async (): Promise => { + // When the transaction hash resolves, wait for it to be mined. + return self._web3Wrapper.awaitTransactionSuccessAsync( + await txHashPromise, + pollingIntervalMs, + timeoutMs, + ); + })(), + ); + }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ + async estimateGasAsync(wad: BigNumber, txData?: Partial | undefined): Promise { + assert.isBigNumber('wad', wad); + const self = (this as any) as AbiGenDummyContract; + const encodedData = self._strictEncodeArguments('withdraw(uint256)', [wad]); + const txDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( + { + to: self.address, + ...txData, + data: encodedData, + }, + self._web3Wrapper.getContractDefaults(), + ); + if (txDataWithDefaults.from !== undefined) { + txDataWithDefaults.from = txDataWithDefaults.from.toLowerCase(); + } + + const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); + return gas; + }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ + async callAsync(wad: BigNumber, callData: Partial = {}, defaultBlock?: BlockParam): Promise { + assert.isBigNumber('wad', wad); + assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (defaultBlock !== undefined) { + assert.isBlockParam('defaultBlock', defaultBlock); + } + const self = (this as any) as AbiGenDummyContract; + const encodedData = self._strictEncodeArguments('withdraw(uint256)', [wad]); + const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( + { + to: self.address, + ...callData, + data: encodedData, + }, + self._web3Wrapper.getContractDefaults(), + ); + callDataWithDefaults.from = callDataWithDefaults.from + ? callDataWithDefaults.from.toLowerCase() + : callDataWithDefaults.from; + + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + BaseContract._throwIfRevertWithReasonCallResult(rawCallResult); + const abiEncoder = self._lookupAbiEncoder('withdraw(uint256)'); + // tslint:disable boolean-naming + const result = abiEncoder.strictDecodeReturnValue(rawCallResult); + // tslint:enable boolean-naming + return result; + }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ + getABIEncodedTransactionData(wad: BigNumber): string { + assert.isBigNumber('wad', wad); + const self = (this as any) as AbiGenDummyContract; + const abiEncodedTransactionData = self._strictEncodeArguments('withdraw(uint256)', [wad]); + return abiEncodedTransactionData; + }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('withdraw(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('withdraw(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(wad: BigNumber, txData?: Partial | undefined): Promise { + await (this as any).withdraw.callAsync(wad, txData); + const txHash = await (this as any).withdraw.sendTransactionAsync(wad, txData); + return txHash; + }, + }; + /** + * Tests decoding when the input and output are complex and have more than one argument. + */ + public multiInputMultiOutput = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ + async callAsync( + index_0: BigNumber, + index_1: string, + index_2: string, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise<[string, string, string]> { + assert.isBigNumber('index_0', index_0); + assert.isString('index_1', index_1); + assert.isString('index_2', index_2); + assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (defaultBlock !== undefined) { + assert.isBlockParam('defaultBlock', defaultBlock); + } + const self = (this as any) as AbiGenDummyContract; + const encodedData = self._strictEncodeArguments('multiInputMultiOutput(uint256,bytes,string)', [ + index_0, + index_1, + index_2, + ]); + const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( + { + to: self.address, + ...callData, + data: encodedData, + }, + self._web3Wrapper.getContractDefaults(), + ); + callDataWithDefaults.from = callDataWithDefaults.from + ? callDataWithDefaults.from.toLowerCase() + : callDataWithDefaults.from; + + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + BaseContract._throwIfRevertWithReasonCallResult(rawCallResult); + const abiEncoder = self._lookupAbiEncoder('multiInputMultiOutput(uint256,bytes,string)'); + // tslint:disable boolean-naming + const result = abiEncoder.strictDecodeReturnValue<[string, string, string]>(rawCallResult); + // tslint:enable boolean-naming + return result; + }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ + getABIEncodedTransactionData(index_0: BigNumber, index_1: string, index_2: string): string { + assert.isBigNumber('index_0', index_0); + assert.isString('index_1', index_1); + assert.isString('index_2', index_2); + const self = (this as any) as AbiGenDummyContract; + const abiEncodedTransactionData = self._strictEncodeArguments( + 'multiInputMultiOutput(uint256,bytes,string)', + [index_0, index_1, index_2], + ); + return abiEncodedTransactionData; + }, + getABIDecodedTransactionData(callData: string): [string, string, string] { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('multiInputMultiOutput(uint256,bytes,string)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<[string, string, string]>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): [string, string, string] { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('multiInputMultiOutput(uint256,bytes,string)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<[string, string, string]>(returnData); + return abiDecodedReturnData; + }, + }; + /** + * test that devdocs will be generated and + * that multiline devdocs will look okay + */ public ecrecoverFn = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @param hash description of some hash. Let's make this line super long to + * demonstrate hanging indents for method params. It has to be more than + * one hundred twenty columns. + * @param v some v, recovery id + * @param r ECDSA r output + * @param s ECDSA s output + * @returns the signerAddress that created this signature. this line too is super long in order to demonstrate the proper hanging indentation in generated code. + */ async callAsync( hash: string, v: number | BigNumber, @@ -163,6 +550,17 @@ export class AbiGenDummyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + * @param hash description of some hash. Let's make this line super long to + * demonstrate hanging indents for method params. It has to be more than + * one hundred twenty columns. + * @param v some v, recovery id + * @param r ECDSA r output + * @param s ECDSA s output + */ getABIEncodedTransactionData(hash: string, v: number | BigNumber, r: string, s: string): string { assert.isString('hash', hash); assert.isNumberOrBigNumber('v', v); @@ -175,8 +573,27 @@ export class AbiGenDummyContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('ecrecoverFn(bytes32,uint8,bytes32,bytes32)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('ecrecoverFn(bytes32,uint8,bytes32,bytes32)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public acceptsBytes = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(a: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isString('a', a); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -209,14 +626,103 @@ export class AbiGenDummyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(a: string): string { assert.isString('a', a); const self = (this as any) as AbiGenDummyContract; const abiEncodedTransactionData = self._strictEncodeArguments('acceptsBytes(bytes)', [a]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('acceptsBytes(bytes)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('acceptsBytes(bytes)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + }; + /** + * Tests decoding when input is empty and output is non-empty. + */ + public noInputSimpleOutput = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (defaultBlock !== undefined) { + assert.isBlockParam('defaultBlock', defaultBlock); + } + const self = (this as any) as AbiGenDummyContract; + const encodedData = self._strictEncodeArguments('noInputSimpleOutput()', []); + const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( + { + to: self.address, + ...callData, + data: encodedData, + }, + self._web3Wrapper.getContractDefaults(), + ); + callDataWithDefaults.from = callDataWithDefaults.from + ? callDataWithDefaults.from.toLowerCase() + : callDataWithDefaults.from; + + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + BaseContract._throwIfRevertWithReasonCallResult(rawCallResult); + const abiEncoder = self._lookupAbiEncoder('noInputSimpleOutput()'); + // tslint:disable boolean-naming + const result = abiEncoder.strictDecodeReturnValue(rawCallResult); + // tslint:enable boolean-naming + return result; + }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ + getABIEncodedTransactionData(): string { + const self = (this as any) as AbiGenDummyContract; + const abiEncodedTransactionData = self._strictEncodeArguments('noInputSimpleOutput()', []); + return abiEncodedTransactionData; + }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('noInputSimpleOutput()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('noInputSimpleOutput()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public revertWithConstant = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -248,13 +754,37 @@ export class AbiGenDummyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as AbiGenDummyContract; const abiEncodedTransactionData = self._strictEncodeArguments('revertWithConstant()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('revertWithConstant()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('revertWithConstant()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public simpleRevert = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -286,13 +816,110 @@ export class AbiGenDummyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as AbiGenDummyContract; const abiEncodedTransactionData = self._strictEncodeArguments('simpleRevert()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('simpleRevert()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('simpleRevert()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + }; + public methodUsingNestedStructWithInnerStructNotUsedElsewhere = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ + async callAsync( + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise<{ innerStruct: { aField: BigNumber } }> { + assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (defaultBlock !== undefined) { + assert.isBlockParam('defaultBlock', defaultBlock); + } + const self = (this as any) as AbiGenDummyContract; + const encodedData = self._strictEncodeArguments( + 'methodUsingNestedStructWithInnerStructNotUsedElsewhere()', + [], + ); + const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( + { + to: self.address, + ...callData, + data: encodedData, + }, + self._web3Wrapper.getContractDefaults(), + ); + callDataWithDefaults.from = callDataWithDefaults.from + ? callDataWithDefaults.from.toLowerCase() + : callDataWithDefaults.from; + + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + BaseContract._throwIfRevertWithReasonCallResult(rawCallResult); + const abiEncoder = self._lookupAbiEncoder('methodUsingNestedStructWithInnerStructNotUsedElsewhere()'); + // tslint:disable boolean-naming + const result = abiEncoder.strictDecodeReturnValue<{ innerStruct: { aField: BigNumber } }>(rawCallResult); + // tslint:enable boolean-naming + return result; + }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ + getABIEncodedTransactionData(): string { + const self = (this as any) as AbiGenDummyContract; + const abiEncodedTransactionData = self._strictEncodeArguments( + 'methodUsingNestedStructWithInnerStructNotUsedElsewhere()', + [], + ); + return abiEncodedTransactionData; + }, + getABIDecodedTransactionData(callData: string): { innerStruct: { aField: BigNumber } } { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('methodUsingNestedStructWithInnerStructNotUsedElsewhere()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<{ innerStruct: { aField: BigNumber } }>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): { innerStruct: { aField: BigNumber } } { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('methodUsingNestedStructWithInnerStructNotUsedElsewhere()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<{ innerStruct: { aField: BigNumber } }>( + returnData, + ); + return abiDecodedReturnData; + }, }; public nestedStructOutput = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( callData: Partial = {}, defaultBlock?: BlockParam, @@ -333,13 +960,53 @@ export class AbiGenDummyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as AbiGenDummyContract; const abiEncodedTransactionData = self._strictEncodeArguments('nestedStructOutput()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): { + innerStruct: { someBytes: string; anInteger: number; aDynamicArrayOfBytes: string[]; aString: string }; + description: string; + } { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('nestedStructOutput()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<{ + innerStruct: { someBytes: string; anInteger: number; aDynamicArrayOfBytes: string[]; aString: string }; + description: string; + }>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): { + innerStruct: { someBytes: string; anInteger: number; aDynamicArrayOfBytes: string[]; aString: string }; + description: string; + } { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('nestedStructOutput()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<{ + innerStruct: { someBytes: string; anInteger: number; aDynamicArrayOfBytes: string[]; aString: string }; + description: string; + }>(returnData); + return abiDecodedReturnData; + }, }; public requireWithConstant = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -371,13 +1038,37 @@ export class AbiGenDummyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as AbiGenDummyContract; const abiEncodedTransactionData = self._strictEncodeArguments('requireWithConstant()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('requireWithConstant()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('requireWithConstant()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public withAddressInput = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( x: string, a: BigNumber, @@ -425,6 +1116,11 @@ export class AbiGenDummyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(x: string, a: BigNumber, b: BigNumber, y: string, c: BigNumber): string { assert.isString('x', x); assert.isBigNumber('a', a); @@ -438,8 +1134,27 @@ export class AbiGenDummyContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): string { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('withAddressInput(address,uint256,uint256,address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): string { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('withAddressInput(address,uint256,uint256,address,uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public structInput = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( s: { someBytes: string; anInteger: number | BigNumber; aDynamicArrayOfBytes: string[]; aString: string }, callData: Partial = {}, @@ -475,6 +1190,11 @@ export class AbiGenDummyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(s: { someBytes: string; anInteger: number | BigNumber; @@ -488,8 +1208,28 @@ export class AbiGenDummyContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('structInput((bytes,uint32,bytes[],string))'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('structInput((bytes,uint32,bytes[],string))'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public nonPureMethod = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(txData?: Partial | undefined): Promise { const self = (this as any) as AbiGenDummyContract; const encodedData = self._strictEncodeArguments('nonPureMethod()', []); @@ -509,6 +1249,13 @@ export class AbiGenDummyContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( txData?: Partial, pollingIntervalMs?: number, @@ -528,6 +1275,11 @@ export class AbiGenDummyContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(txData?: Partial | undefined): Promise { const self = (this as any) as AbiGenDummyContract; const encodedData = self._strictEncodeArguments('nonPureMethod()', []); @@ -546,6 +1298,11 @@ export class AbiGenDummyContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -577,13 +1334,205 @@ export class AbiGenDummyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as AbiGenDummyContract; const abiEncodedTransactionData = self._strictEncodeArguments('nonPureMethod()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('nonPureMethod()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('nonPureMethod()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(txData?: Partial | undefined): Promise { + await (this as any).nonPureMethod.callAsync(txData); + const txHash = await (this as any).nonPureMethod.sendTransactionAsync(txData); + return txHash; + }, + }; + /** + * Tests decoding when the input and output are complex. + */ + public complexInputComplexOutput = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ + async callAsync( + complexInput: { foo: BigNumber; bar: string; car: string }, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise<{ + input: { foo: BigNumber; bar: string; car: string }; + lorem: string; + ipsum: string; + dolor: string; + }> { + assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (defaultBlock !== undefined) { + assert.isBlockParam('defaultBlock', defaultBlock); + } + const self = (this as any) as AbiGenDummyContract; + const encodedData = self._strictEncodeArguments('complexInputComplexOutput((uint256,bytes,string))', [ + complexInput, + ]); + const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( + { + to: self.address, + ...callData, + data: encodedData, + }, + self._web3Wrapper.getContractDefaults(), + ); + callDataWithDefaults.from = callDataWithDefaults.from + ? callDataWithDefaults.from.toLowerCase() + : callDataWithDefaults.from; + + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + BaseContract._throwIfRevertWithReasonCallResult(rawCallResult); + const abiEncoder = self._lookupAbiEncoder('complexInputComplexOutput((uint256,bytes,string))'); + // tslint:disable boolean-naming + const result = abiEncoder.strictDecodeReturnValue<{ + input: { foo: BigNumber; bar: string; car: string }; + lorem: string; + ipsum: string; + dolor: string; + }>(rawCallResult); + // tslint:enable boolean-naming + return result; + }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ + getABIEncodedTransactionData(complexInput: { foo: BigNumber; bar: string; car: string }): string { + const self = (this as any) as AbiGenDummyContract; + const abiEncodedTransactionData = self._strictEncodeArguments( + 'complexInputComplexOutput((uint256,bytes,string))', + [complexInput], + ); + return abiEncodedTransactionData; + }, + getABIDecodedTransactionData( + callData: string, + ): { input: { foo: BigNumber; bar: string; car: string }; lorem: string; ipsum: string; dolor: string } { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('complexInputComplexOutput((uint256,bytes,string))'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<{ + input: { foo: BigNumber; bar: string; car: string }; + lorem: string; + ipsum: string; + dolor: string; + }>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): { input: { foo: BigNumber; bar: string; car: string }; lorem: string; ipsum: string; dolor: string } { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('complexInputComplexOutput((uint256,bytes,string))'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<{ + input: { foo: BigNumber; bar: string; car: string }; + lorem: string; + ipsum: string; + dolor: string; + }>(returnData); + return abiDecodedReturnData; + }, + }; + /** + * Tests decoding when both input and output are empty. + */ + public noInputNoOutput = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { + assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (defaultBlock !== undefined) { + assert.isBlockParam('defaultBlock', defaultBlock); + } + const self = (this as any) as AbiGenDummyContract; + const encodedData = self._strictEncodeArguments('noInputNoOutput()', []); + const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( + { + to: self.address, + ...callData, + data: encodedData, + }, + self._web3Wrapper.getContractDefaults(), + ); + callDataWithDefaults.from = callDataWithDefaults.from + ? callDataWithDefaults.from.toLowerCase() + : callDataWithDefaults.from; + + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + BaseContract._throwIfRevertWithReasonCallResult(rawCallResult); + const abiEncoder = self._lookupAbiEncoder('noInputNoOutput()'); + // tslint:disable boolean-naming + const result = abiEncoder.strictDecodeReturnValue(rawCallResult); + // tslint:enable boolean-naming + return result; + }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ + getABIEncodedTransactionData(): string { + const self = (this as any) as AbiGenDummyContract; + const abiEncodedTransactionData = self._strictEncodeArguments('noInputNoOutput()', []); + return abiEncodedTransactionData; + }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('noInputNoOutput()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('noInputNoOutput()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public simplePureFunctionWithInput = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(x: BigNumber, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isBigNumber('x', x); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -616,14 +1565,39 @@ export class AbiGenDummyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(x: BigNumber): string { assert.isBigNumber('x', x); const self = (this as any) as AbiGenDummyContract; const abiEncodedTransactionData = self._strictEncodeArguments('simplePureFunctionWithInput(uint256)', [x]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('simplePureFunctionWithInput(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('simplePureFunctionWithInput(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public nonPureMethodThatReturnsNothing = { + /** + * Sends an Ethereum transaction executing this method with the supplied parameters. This is a read/write + * Ethereum operation and will cost gas. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async sendTransactionAsync(txData?: Partial | undefined): Promise { const self = (this as any) as AbiGenDummyContract; const encodedData = self._strictEncodeArguments('nonPureMethodThatReturnsNothing()', []); @@ -643,6 +1617,13 @@ export class AbiGenDummyContract extends BaseContract { const txHash = await self._web3Wrapper.sendTransactionAsync(txDataWithDefaults); return txHash; }, + /** + * Sends an Ethereum transaction and waits until the transaction has been successfully mined without reverting. + * If the transaction was mined, but reverted, an error is thrown. + * @param txData Additional data for transaction + * @param pollingIntervalMs Interval at which to poll for success + * @returns A promise that resolves when the transaction is successful + */ awaitTransactionSuccessAsync( txData?: Partial, pollingIntervalMs?: number, @@ -662,6 +1643,11 @@ export class AbiGenDummyContract extends BaseContract { })(), ); }, + /** + * Estimates the gas cost of sending an Ethereum transaction calling this method with these arguments. + * @param txData Additional data for transaction + * @returns The hash of the transaction + */ async estimateGasAsync(txData?: Partial | undefined): Promise { const self = (this as any) as AbiGenDummyContract; const encodedData = self._strictEncodeArguments('nonPureMethodThatReturnsNothing()', []); @@ -680,6 +1666,11 @@ export class AbiGenDummyContract extends BaseContract { const gas = await self._web3Wrapper.estimateGasAsync(txDataWithDefaults); return gas; }, + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -711,13 +1702,42 @@ export class AbiGenDummyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as AbiGenDummyContract; const abiEncodedTransactionData = self._strictEncodeArguments('nonPureMethodThatReturnsNothing()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('nonPureMethodThatReturnsNothing()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('nonPureMethodThatReturnsNothing()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + async validateAndSendTransactionAsync(txData?: Partial | undefined): Promise { + await (this as any).nonPureMethodThatReturnsNothing.callAsync(txData); + const txHash = await (this as any).nonPureMethodThatReturnsNothing.sendTransactionAsync(txData); + return txHash; + }, }; public simplePureFunction = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -749,13 +1769,37 @@ export class AbiGenDummyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as AbiGenDummyContract; const abiEncodedTransactionData = self._strictEncodeArguments('simplePureFunction()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('simplePureFunction()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('simplePureFunction()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public nestedStructInput = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync( n: { innerStruct: { @@ -802,6 +1846,11 @@ export class AbiGenDummyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(n: { innerStruct: { someBytes: string; @@ -818,8 +1867,168 @@ export class AbiGenDummyContract extends BaseContract { ); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('nestedStructInput(((bytes,uint32,bytes[],string),string))'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('nestedStructInput(((bytes,uint32,bytes[],string),string))'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + public methodReturningMultipleValues = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ + async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise<[BigNumber, string]> { + assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (defaultBlock !== undefined) { + assert.isBlockParam('defaultBlock', defaultBlock); + } + const self = (this as any) as AbiGenDummyContract; + const encodedData = self._strictEncodeArguments('methodReturningMultipleValues()', []); + const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( + { + to: self.address, + ...callData, + data: encodedData, + }, + self._web3Wrapper.getContractDefaults(), + ); + callDataWithDefaults.from = callDataWithDefaults.from + ? callDataWithDefaults.from.toLowerCase() + : callDataWithDefaults.from; + + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + BaseContract._throwIfRevertWithReasonCallResult(rawCallResult); + const abiEncoder = self._lookupAbiEncoder('methodReturningMultipleValues()'); + // tslint:disable boolean-naming + const result = abiEncoder.strictDecodeReturnValue<[BigNumber, string]>(rawCallResult); + // tslint:enable boolean-naming + return result; + }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ + getABIEncodedTransactionData(): string { + const self = (this as any) as AbiGenDummyContract; + const abiEncodedTransactionData = self._strictEncodeArguments('methodReturningMultipleValues()', []); + return abiEncodedTransactionData; + }, + getABIDecodedTransactionData(callData: string): [BigNumber, string] { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('methodReturningMultipleValues()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<[BigNumber, string]>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): [BigNumber, string] { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('methodReturningMultipleValues()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<[BigNumber, string]>(returnData); + return abiDecodedReturnData; + }, + }; + public methodReturningArrayOfStructs = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ + async callAsync( + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise> { + assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (defaultBlock !== undefined) { + assert.isBlockParam('defaultBlock', defaultBlock); + } + const self = (this as any) as AbiGenDummyContract; + const encodedData = self._strictEncodeArguments('methodReturningArrayOfStructs()', []); + const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( + { + to: self.address, + ...callData, + data: encodedData, + }, + self._web3Wrapper.getContractDefaults(), + ); + callDataWithDefaults.from = callDataWithDefaults.from + ? callDataWithDefaults.from.toLowerCase() + : callDataWithDefaults.from; + + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + BaseContract._throwIfRevertWithReasonCallResult(rawCallResult); + const abiEncoder = self._lookupAbiEncoder('methodReturningArrayOfStructs()'); + // tslint:disable boolean-naming + const result = abiEncoder.strictDecodeReturnValue< + Array<{ someBytes: string; anInteger: number; aDynamicArrayOfBytes: string[]; aString: string }> + >(rawCallResult); + // tslint:enable boolean-naming + return result; + }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ + getABIEncodedTransactionData(): string { + const self = (this as any) as AbiGenDummyContract; + const abiEncodedTransactionData = self._strictEncodeArguments('methodReturningArrayOfStructs()', []); + return abiEncodedTransactionData; + }, + getABIDecodedTransactionData( + callData: string, + ): Array<{ someBytes: string; anInteger: number; aDynamicArrayOfBytes: string[]; aString: string }> { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('methodReturningArrayOfStructs()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode< + Array<{ someBytes: string; anInteger: number; aDynamicArrayOfBytes: string[]; aString: string }> + >(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): Array<{ someBytes: string; anInteger: number; aDynamicArrayOfBytes: string[]; aString: string }> { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('methodReturningArrayOfStructs()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue< + Array<{ someBytes: string; anInteger: number; aDynamicArrayOfBytes: string[]; aString: string }> + >(returnData); + return abiDecodedReturnData; + }, + }; + /** + * a method that returns a struct + */ public structOutput = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + * @returns a Struct struct + */ async callAsync( callData: Partial = {}, defaultBlock?: BlockParam, @@ -859,13 +2068,51 @@ export class AbiGenDummyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as AbiGenDummyContract; const abiEncodedTransactionData = self._strictEncodeArguments('structOutput()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData( + callData: string, + ): { someBytes: string; anInteger: number; aDynamicArrayOfBytes: string[]; aString: string } { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('structOutput()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode<{ + someBytes: string; + anInteger: number; + aDynamicArrayOfBytes: string[]; + aString: string; + }>(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData( + returnData: string, + ): { someBytes: string; anInteger: number; aDynamicArrayOfBytes: string[]; aString: string } { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('structOutput()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue<{ + someBytes: string; + anInteger: number; + aDynamicArrayOfBytes: string[]; + aString: string; + }>(returnData); + return abiDecodedReturnData; + }, }; public pureFunctionWithConstant = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ schemas.addressSchema, @@ -897,16 +2144,236 @@ export class AbiGenDummyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(): string { const self = (this as any) as AbiGenDummyContract; const abiEncodedTransactionData = self._strictEncodeArguments('pureFunctionWithConstant()', []); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('pureFunctionWithConstant()'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('pureFunctionWithConstant()'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; + /** + * Tests decoding when input is not empty but output is empty. + */ + public simpleInputNoOutput = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ + async callAsync( + index_0: BigNumber, + callData: Partial = {}, + defaultBlock?: BlockParam, + ): Promise { + assert.isBigNumber('index_0', index_0); + assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (defaultBlock !== undefined) { + assert.isBlockParam('defaultBlock', defaultBlock); + } + const self = (this as any) as AbiGenDummyContract; + const encodedData = self._strictEncodeArguments('simpleInputNoOutput(uint256)', [index_0]); + const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( + { + to: self.address, + ...callData, + data: encodedData, + }, + self._web3Wrapper.getContractDefaults(), + ); + callDataWithDefaults.from = callDataWithDefaults.from + ? callDataWithDefaults.from.toLowerCase() + : callDataWithDefaults.from; + + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + BaseContract._throwIfRevertWithReasonCallResult(rawCallResult); + const abiEncoder = self._lookupAbiEncoder('simpleInputNoOutput(uint256)'); + // tslint:disable boolean-naming + const result = abiEncoder.strictDecodeReturnValue(rawCallResult); + // tslint:enable boolean-naming + return result; + }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ + getABIEncodedTransactionData(index_0: BigNumber): string { + assert.isBigNumber('index_0', index_0); + const self = (this as any) as AbiGenDummyContract; + const abiEncodedTransactionData = self._strictEncodeArguments('simpleInputNoOutput(uint256)', [index_0]); + return abiEncodedTransactionData; + }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('simpleInputNoOutput(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('simpleInputNoOutput(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + }; + public overloadedMethod2 = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ + async callAsync(a: string, callData: Partial = {}, defaultBlock?: BlockParam): Promise { + assert.isString('a', a); + assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (defaultBlock !== undefined) { + assert.isBlockParam('defaultBlock', defaultBlock); + } + const self = (this as any) as AbiGenDummyContract; + const encodedData = self._strictEncodeArguments('overloadedMethod(string)', [a]); + const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( + { + to: self.address, + ...callData, + data: encodedData, + }, + self._web3Wrapper.getContractDefaults(), + ); + callDataWithDefaults.from = callDataWithDefaults.from + ? callDataWithDefaults.from.toLowerCase() + : callDataWithDefaults.from; + + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + BaseContract._throwIfRevertWithReasonCallResult(rawCallResult); + const abiEncoder = self._lookupAbiEncoder('overloadedMethod(string)'); + // tslint:disable boolean-naming + const result = abiEncoder.strictDecodeReturnValue(rawCallResult); + // tslint:enable boolean-naming + return result; + }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ + getABIEncodedTransactionData(a: string): string { + assert.isString('a', a); + const self = (this as any) as AbiGenDummyContract; + const abiEncodedTransactionData = self._strictEncodeArguments('overloadedMethod(string)', [a]); + return abiEncodedTransactionData; + }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('overloadedMethod(string)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('overloadedMethod(string)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + }; + public overloadedMethod1 = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ + async callAsync(a: BigNumber, callData: Partial = {}, defaultBlock?: BlockParam): Promise { + assert.isBigNumber('a', a); + assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ + schemas.addressSchema, + schemas.numberSchema, + schemas.jsNumber, + ]); + if (defaultBlock !== undefined) { + assert.isBlockParam('defaultBlock', defaultBlock); + } + const self = (this as any) as AbiGenDummyContract; + const encodedData = self._strictEncodeArguments('overloadedMethod(int256)', [a]); + const callDataWithDefaults = await BaseContract._applyDefaultsToTxDataAsync( + { + to: self.address, + ...callData, + data: encodedData, + }, + self._web3Wrapper.getContractDefaults(), + ); + callDataWithDefaults.from = callDataWithDefaults.from + ? callDataWithDefaults.from.toLowerCase() + : callDataWithDefaults.from; + + const rawCallResult = await self._web3Wrapper.callAsync(callDataWithDefaults, defaultBlock); + BaseContract._throwIfRevertWithReasonCallResult(rawCallResult); + const abiEncoder = self._lookupAbiEncoder('overloadedMethod(int256)'); + // tslint:disable boolean-naming + const result = abiEncoder.strictDecodeReturnValue(rawCallResult); + // tslint:enable boolean-naming + return result; + }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ + getABIEncodedTransactionData(a: BigNumber): string { + assert.isBigNumber('a', a); + const self = (this as any) as AbiGenDummyContract; + const abiEncodedTransactionData = self._strictEncodeArguments('overloadedMethod(int256)', [a]); + return abiEncodedTransactionData; + }, + getABIDecodedTransactionData(callData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('overloadedMethod(int256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): void { + const self = (this as any) as AbiGenDummyContract; + const abiEncoder = self._lookupAbiEncoder('overloadedMethod(int256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, + }; + private readonly _subscriptionManager: SubscriptionManager; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, ): Promise { assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ schemas.addressSchema, @@ -919,13 +2386,20 @@ export class AbiGenDummyContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; - return AbiGenDummyContract.deployAsync(bytecode, abi, provider, txDefaults); + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return AbiGenDummyContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); } public static async deployAsync( bytecode: string, abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, ): Promise { assert.isHexString('bytecode', bytecode); assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ @@ -949,7 +2423,12 @@ export class AbiGenDummyContract extends BaseContract { logUtils.log(`transactionHash: ${txHash}`); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); logUtils.log(`AbiGenDummy successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new AbiGenDummyContract(txReceipt.contractAddress as string, provider, txDefaults); + const contractInstance = new AbiGenDummyContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); contractInstance.constructorArgs = []; return contractInstance; } @@ -982,6 +2461,74 @@ export class AbiGenDummyContract extends BaseContract { stateMutability: 'pure', type: 'function', }, + { + constant: true, + inputs: [ + { + name: 'index_0', + type: 'uint256', + }, + ], + name: 'simpleInputSimpleOutput', + outputs: [ + { + name: '', + type: 'uint256', + }, + ], + payable: false, + stateMutability: 'pure', + type: 'function', + }, + { + constant: false, + inputs: [ + { + name: 'wad', + type: 'uint256', + }, + ], + name: 'withdraw', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: 'index_0', + type: 'uint256', + }, + { + name: 'index_1', + type: 'bytes', + }, + { + name: 'index_2', + type: 'string', + }, + ], + name: 'multiInputMultiOutput', + outputs: [ + { + name: '', + type: 'bytes', + }, + { + name: '', + type: 'bytes', + }, + { + name: '', + type: 'string', + }, + ], + payable: false, + stateMutability: 'pure', + type: 'function', + }, { constant: true, inputs: [ @@ -1027,6 +2574,20 @@ export class AbiGenDummyContract extends BaseContract { stateMutability: 'pure', type: 'function', }, + { + constant: true, + inputs: [], + name: 'noInputSimpleOutput', + outputs: [ + { + name: '', + type: 'uint256', + }, + ], + payable: false, + stateMutability: 'pure', + type: 'function', + }, { constant: true, inputs: [], @@ -1045,6 +2606,32 @@ export class AbiGenDummyContract extends BaseContract { stateMutability: 'pure', type: 'function', }, + { + constant: true, + inputs: [], + name: 'methodUsingNestedStructWithInnerStructNotUsedElsewhere', + outputs: [ + { + name: '', + type: 'tuple', + components: [ + { + name: 'innerStruct', + type: 'tuple', + components: [ + { + name: 'aField', + type: 'uint256', + }, + ], + }, + ], + }, + ], + payable: false, + stateMutability: 'pure', + type: 'function', + }, { constant: true, inputs: [], @@ -1177,6 +2764,80 @@ export class AbiGenDummyContract extends BaseContract { stateMutability: 'nonpayable', type: 'function', }, + { + constant: true, + inputs: [ + { + name: 'complexInput', + type: 'tuple', + components: [ + { + name: 'foo', + type: 'uint256', + }, + { + name: 'bar', + type: 'bytes', + }, + { + name: 'car', + type: 'string', + }, + ], + }, + ], + name: 'complexInputComplexOutput', + outputs: [ + { + name: '', + type: 'tuple', + components: [ + { + name: 'input', + type: 'tuple', + components: [ + { + name: 'foo', + type: 'uint256', + }, + { + name: 'bar', + type: 'bytes', + }, + { + name: 'car', + type: 'string', + }, + ], + }, + { + name: 'lorem', + type: 'bytes', + }, + { + name: 'ipsum', + type: 'bytes', + }, + { + name: 'dolor', + type: 'string', + }, + ], + }, + ], + payable: false, + stateMutability: 'pure', + type: 'function', + }, + { + constant: true, + inputs: [], + name: 'noInputNoOutput', + outputs: [], + payable: false, + stateMutability: 'pure', + type: 'function', + }, { constant: true, inputs: [ @@ -1261,6 +2922,56 @@ export class AbiGenDummyContract extends BaseContract { stateMutability: 'pure', type: 'function', }, + { + constant: true, + inputs: [], + name: 'methodReturningMultipleValues', + outputs: [ + { + name: '', + type: 'uint256', + }, + { + name: '', + type: 'string', + }, + ], + payable: false, + stateMutability: 'pure', + type: 'function', + }, + { + constant: true, + inputs: [], + name: 'methodReturningArrayOfStructs', + outputs: [ + { + name: '', + type: 'tuple[]', + components: [ + { + name: 'someBytes', + type: 'bytes', + }, + { + name: 'anInteger', + type: 'uint32', + }, + { + name: 'aDynamicArrayOfBytes', + type: 'bytes[]', + }, + { + name: 'aString', + type: 'string', + }, + ], + }, + ], + payable: false, + stateMutability: 'pure', + type: 'function', + }, { constant: true, inputs: [], @@ -1307,6 +3018,66 @@ export class AbiGenDummyContract extends BaseContract { stateMutability: 'pure', type: 'function', }, + { + constant: true, + inputs: [ + { + name: 'index_0', + type: 'uint256', + }, + ], + name: 'simpleInputNoOutput', + outputs: [], + payable: false, + stateMutability: 'pure', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: 'a', + type: 'string', + }, + ], + name: 'overloadedMethod', + outputs: [], + payable: false, + stateMutability: 'pure', + type: 'function', + }, + { + constant: true, + inputs: [ + { + name: 'a', + type: 'int256', + }, + ], + name: 'overloadedMethod', + outputs: [], + payable: false, + stateMutability: 'pure', + type: 'function', + }, + { + anonymous: false, + inputs: [ + { + name: '_owner', + type: 'address', + indexed: true, + }, + { + name: '_value', + type: 'uint256', + indexed: false, + }, + ], + name: 'Withdrawal', + outputs: [], + type: 'event', + }, { anonymous: false, inputs: [ @@ -1323,9 +3094,86 @@ export class AbiGenDummyContract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('AbiGenDummy', AbiGenDummyContract.ABI(), address, supportedProvider, txDefaults); + /** + * Subscribe to an event type emitted by the AbiGenDummy contract. + * @param eventName The AbiGenDummy contract event you would like to subscribe to. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` + * @param callback Callback that gets called when a log is added/removed + * @param isVerbose Enable verbose subscription warnings (e.g recoverable network issues encountered) + * @return Subscription token used later to unsubscribe + */ + public subscribe( + eventName: AbiGenDummyEvents, + indexFilterValues: IndexedFilterValues, + callback: EventCallback, + isVerbose: boolean = false, + blockPollingIntervalMs?: number, + ): string { + assert.doesBelongToStringEnum('eventName', eventName, AbiGenDummyEvents); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + assert.isFunction('callback', callback); + const subscriptionToken = this._subscriptionManager.subscribe( + this.address, + eventName, + indexFilterValues, + AbiGenDummyContract.ABI(), + callback, + isVerbose, + blockPollingIntervalMs, + ); + return subscriptionToken; + } + /** + * Cancel a subscription + * @param subscriptionToken Subscription token returned by `subscribe()` + */ + public unsubscribe(subscriptionToken: string): void { + this._subscriptionManager.unsubscribe(subscriptionToken); + } + /** + * Cancels all existing subscriptions + */ + public unsubscribeAll(): void { + this._subscriptionManager.unsubscribeAll(); + } + /** + * Gets historical logs without creating a subscription + * @param eventName The AbiGenDummy contract event you would like to subscribe to. + * @param blockRange Block range to get logs from. + * @param indexFilterValues An object where the keys are indexed args returned by the event and + * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` + * @return Array of logs that match the parameters + */ + public async getLogsAsync( + eventName: AbiGenDummyEvents, + blockRange: BlockRange, + indexFilterValues: IndexedFilterValues, + ): Promise>> { + assert.doesBelongToStringEnum('eventName', eventName, AbiGenDummyEvents); + assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); + assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); + const logs = await this._subscriptionManager.getLogsAsync( + this.address, + eventName, + blockRange, + indexFilterValues, + AbiGenDummyContract.ABI(), + ); + return logs; + } + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super('AbiGenDummy', AbiGenDummyContract.ABI(), address, supportedProvider, txDefaults, logDecodeDependencies); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); + this._subscriptionManager = new SubscriptionManager( + AbiGenDummyContract.ABI(), + this._web3Wrapper, + ); } } diff --git a/packages/abi-gen/test-cli/expected-output/typescript/lib_dummy.ts b/packages/abi-gen/test-cli/expected-output/typescript/lib_dummy.ts index f613fbb853..4403bbce8e 100644 --- a/packages/abi-gen/test-cli/expected-output/typescript/lib_dummy.ts +++ b/packages/abi-gen/test-cli/expected-output/typescript/lib_dummy.ts @@ -31,6 +31,7 @@ export class LibDummyContract extends BaseContract { artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, ): Promise { assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ schemas.addressSchema, @@ -43,13 +44,20 @@ export class LibDummyContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; - return LibDummyContract.deployAsync(bytecode, abi, provider, txDefaults); + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return LibDummyContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); } public static async deployAsync( bytecode: string, abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, ): Promise { assert.isHexString('bytecode', bytecode); assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ @@ -73,7 +81,12 @@ export class LibDummyContract extends BaseContract { logUtils.log(`transactionHash: ${txHash}`); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); logUtils.log(`LibDummy successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new LibDummyContract(txReceipt.contractAddress as string, provider, txDefaults); + const contractInstance = new LibDummyContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); contractInstance.constructorArgs = []; return contractInstance; } @@ -85,8 +98,13 @@ export class LibDummyContract extends BaseContract { const abi = [] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('LibDummy', LibDummyContract.ABI(), address, supportedProvider, txDefaults); + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super('LibDummy', LibDummyContract.ABI(), address, supportedProvider, txDefaults, logDecodeDependencies); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); } } diff --git a/packages/abi-gen/test-cli/expected-output/typescript/test_lib_dummy.ts b/packages/abi-gen/test-cli/expected-output/typescript/test_lib_dummy.ts index 7c192214a1..93d5185886 100644 --- a/packages/abi-gen/test-cli/expected-output/typescript/test_lib_dummy.ts +++ b/packages/abi-gen/test-cli/expected-output/typescript/test_lib_dummy.ts @@ -28,6 +28,11 @@ import * as ethers from 'ethers'; // tslint:disable-next-line:class-name export class TestLibDummyContract extends BaseContract { public publicAddConstant = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(x: BigNumber, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isBigNumber('x', x); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -60,14 +65,38 @@ export class TestLibDummyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(x: BigNumber): string { assert.isBigNumber('x', x); const self = (this as any) as TestLibDummyContract; const abiEncodedTransactionData = self._strictEncodeArguments('publicAddConstant(uint256)', [x]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as TestLibDummyContract; + const abiEncoder = self._lookupAbiEncoder('publicAddConstant(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as TestLibDummyContract; + const abiEncoder = self._lookupAbiEncoder('publicAddConstant(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public publicAddOne = { + /** + * Sends a read-only call to the contract method. Returns the result that would happen if one were to send an + * Ethereum transaction to this method, given the current state of the blockchain. Calls do not cost gas + * since they don't modify state. + */ async callAsync(x: BigNumber, callData: Partial = {}, defaultBlock?: BlockParam): Promise { assert.isBigNumber('x', x); assert.doesConformToSchema('callData', callData, schemas.callDataSchema, [ @@ -100,17 +129,37 @@ export class TestLibDummyContract extends BaseContract { // tslint:enable boolean-naming return result; }, + /** + * Returns the ABI encoded transaction data needed to send an Ethereum transaction calling this method. Before + * sending the Ethereum tx, this encoded tx data can first be sent to a separate signing service or can be used + * to create a 0x transaction (see protocol spec for more details). + */ getABIEncodedTransactionData(x: BigNumber): string { assert.isBigNumber('x', x); const self = (this as any) as TestLibDummyContract; const abiEncodedTransactionData = self._strictEncodeArguments('publicAddOne(uint256)', [x]); return abiEncodedTransactionData; }, + getABIDecodedTransactionData(callData: string): BigNumber { + const self = (this as any) as TestLibDummyContract; + const abiEncoder = self._lookupAbiEncoder('publicAddOne(uint256)'); + // tslint:disable boolean-naming + const abiDecodedCallData = abiEncoder.strictDecode(callData); + return abiDecodedCallData; + }, + getABIDecodedReturnData(returnData: string): BigNumber { + const self = (this as any) as TestLibDummyContract; + const abiEncoder = self._lookupAbiEncoder('publicAddOne(uint256)'); + // tslint:disable boolean-naming + const abiDecodedReturnData = abiEncoder.strictDecodeReturnValue(returnData); + return abiDecodedReturnData; + }, }; public static async deployFrom0xArtifactAsync( artifact: ContractArtifact | SimpleContractArtifact, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact }, ): Promise { assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ schemas.addressSchema, @@ -123,13 +172,20 @@ export class TestLibDummyContract extends BaseContract { const provider = providerUtils.standardizeOrThrow(supportedProvider); const bytecode = artifact.compilerOutput.evm.bytecode.object; const abi = artifact.compilerOutput.abi; - return TestLibDummyContract.deployAsync(bytecode, abi, provider, txDefaults); + const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {}; + if (Object.keys(logDecodeDependencies) !== undefined) { + for (const key of Object.keys(logDecodeDependencies)) { + logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi; + } + } + return TestLibDummyContract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly); } public static async deployAsync( bytecode: string, abi: ContractAbi, supportedProvider: SupportedProvider, txDefaults: Partial, + logDecodeDependencies: { [contractName: string]: ContractAbi }, ): Promise { assert.isHexString('bytecode', bytecode); assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [ @@ -153,7 +209,12 @@ export class TestLibDummyContract extends BaseContract { logUtils.log(`transactionHash: ${txHash}`); const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash); logUtils.log(`TestLibDummy successfully deployed at ${txReceipt.contractAddress}`); - const contractInstance = new TestLibDummyContract(txReceipt.contractAddress as string, provider, txDefaults); + const contractInstance = new TestLibDummyContract( + txReceipt.contractAddress as string, + provider, + txDefaults, + logDecodeDependencies, + ); contractInstance.constructorArgs = []; return contractInstance; } @@ -204,8 +265,20 @@ export class TestLibDummyContract extends BaseContract { ] as ContractAbi; return abi; } - constructor(address: string, supportedProvider: SupportedProvider, txDefaults?: Partial) { - super('TestLibDummy', TestLibDummyContract.ABI(), address, supportedProvider, txDefaults); + constructor( + address: string, + supportedProvider: SupportedProvider, + txDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, + ) { + super( + 'TestLibDummy', + TestLibDummyContract.ABI(), + address, + supportedProvider, + txDefaults, + logDecodeDependencies, + ); classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']); } } diff --git a/packages/abi-gen/test-cli/fixtures/artifacts/AbiGenDummy.json b/packages/abi-gen/test-cli/fixtures/artifacts/AbiGenDummy.json index 0d6cf52860..b6497bea9f 100644 --- a/packages/abi-gen/test-cli/fixtures/artifacts/AbiGenDummy.json +++ b/packages/abi-gen/test-cli/fixtures/artifacts/AbiGenDummy.json @@ -16,6 +16,7 @@ "constant": true, "inputs": [ { + "internalType": "bytes[]", "name": "a", "type": "bytes[]" } @@ -30,18 +31,99 @@ "constant": true, "inputs": [ { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "simpleInputSimpleOutput", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "wad", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + }, + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "name": "multiInputMultiOutput", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + }, + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "bytes32", "name": "hash", "type": "bytes32" }, { + "internalType": "uint8", "name": "v", "type": "uint8" }, { + "internalType": "bytes32", "name": "r", "type": "bytes32" }, { + "internalType": "bytes32", "name": "s", "type": "bytes32" } @@ -49,6 +131,7 @@ "name": "ecrecoverFn", "outputs": [ { + "internalType": "address", "name": "signerAddress", "type": "address" } @@ -61,6 +144,7 @@ "constant": true, "inputs": [ { + "internalType": "bytes", "name": "a", "type": "bytes" } @@ -71,6 +155,21 @@ "stateMutability": "pure", "type": "function" }, + { + "constant": true, + "inputs": [], + "name": "noInputSimpleOutput", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, { "constant": true, "inputs": [], @@ -89,6 +188,35 @@ "stateMutability": "pure", "type": "function" }, + { + "constant": true, + "inputs": [], + "name": "methodUsingNestedStructWithInnerStructNotUsedElsewhere", + "outputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "uint256", + "name": "aField", + "type": "uint256" + } + ], + "internalType": "struct AbiGenDummy.StructNotDirectlyUsedAnywhere", + "name": "innerStruct", + "type": "tuple" + } + ], + "internalType": "struct AbiGenDummy.NestedStructWithInnerStructNotUsedElsewhere", + "name": "", + "type": "tuple" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, { "constant": true, "inputs": [], @@ -99,30 +227,37 @@ { "components": [ { + "internalType": "bytes", "name": "someBytes", "type": "bytes" }, { + "internalType": "uint32", "name": "anInteger", "type": "uint32" }, { + "internalType": "bytes[]", "name": "aDynamicArrayOfBytes", "type": "bytes[]" }, { + "internalType": "string", "name": "aString", "type": "string" } ], + "internalType": "struct AbiGenDummy.Struct", "name": "innerStruct", "type": "tuple" }, { + "internalType": "string", "name": "description", "type": "string" } ], + "internalType": "struct AbiGenDummy.NestedStruct", "name": "", "type": "tuple" } @@ -144,22 +279,27 @@ "constant": true, "inputs": [ { + "internalType": "address", "name": "x", "type": "address" }, { + "internalType": "uint256", "name": "a", "type": "uint256" }, { + "internalType": "uint256", "name": "b", "type": "uint256" }, { + "internalType": "address", "name": "y", "type": "address" }, { + "internalType": "uint256", "name": "c", "type": "uint256" } @@ -167,6 +307,7 @@ "name": "withAddressInput", "outputs": [ { + "internalType": "address", "name": "z", "type": "address" } @@ -181,22 +322,27 @@ { "components": [ { + "internalType": "bytes", "name": "someBytes", "type": "bytes" }, { + "internalType": "uint32", "name": "anInteger", "type": "uint32" }, { + "internalType": "bytes[]", "name": "aDynamicArrayOfBytes", "type": "bytes[]" }, { + "internalType": "string", "name": "aString", "type": "string" } ], + "internalType": "struct AbiGenDummy.Struct", "name": "s", "type": "tuple" } @@ -213,6 +359,7 @@ "name": "nonPureMethod", "outputs": [ { + "internalType": "uint256", "name": "", "type": "uint256" } @@ -225,6 +372,93 @@ "constant": true, "inputs": [ { + "components": [ + { + "internalType": "uint256", + "name": "foo", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "bar", + "type": "bytes" + }, + { + "internalType": "string", + "name": "car", + "type": "string" + } + ], + "internalType": "struct AbiGenDummy.ComplexInput", + "name": "complexInput", + "type": "tuple" + } + ], + "name": "complexInputComplexOutput", + "outputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "uint256", + "name": "foo", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "bar", + "type": "bytes" + }, + { + "internalType": "string", + "name": "car", + "type": "string" + } + ], + "internalType": "struct AbiGenDummy.ComplexInput", + "name": "input", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "lorem", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "ipsum", + "type": "bytes" + }, + { + "internalType": "string", + "name": "dolor", + "type": "string" + } + ], + "internalType": "struct AbiGenDummy.ComplexOutput", + "name": "", + "type": "tuple" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "noInputNoOutput", + "outputs": [], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", "name": "x", "type": "uint256" } @@ -232,6 +466,7 @@ "name": "simplePureFunctionWithInput", "outputs": [ { + "internalType": "uint256", "name": "sum", "type": "uint256" } @@ -255,6 +490,7 @@ "name": "simplePureFunction", "outputs": [ { + "internalType": "uint256", "name": "result", "type": "uint256" } @@ -271,30 +507,37 @@ { "components": [ { + "internalType": "bytes", "name": "someBytes", "type": "bytes" }, { + "internalType": "uint32", "name": "anInteger", "type": "uint32" }, { + "internalType": "bytes[]", "name": "aDynamicArrayOfBytes", "type": "bytes[]" }, { + "internalType": "string", "name": "aString", "type": "string" } ], + "internalType": "struct AbiGenDummy.Struct", "name": "innerStruct", "type": "tuple" }, { + "internalType": "string", "name": "description", "type": "string" } ], + "internalType": "struct AbiGenDummy.NestedStruct", "name": "n", "type": "tuple" } @@ -305,6 +548,63 @@ "stateMutability": "pure", "type": "function" }, + { + "constant": true, + "inputs": [], + "name": "methodReturningMultipleValues", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "methodReturningArrayOfStructs", + "outputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "someBytes", + "type": "bytes" + }, + { + "internalType": "uint32", + "name": "anInteger", + "type": "uint32" + }, + { + "internalType": "bytes[]", + "name": "aDynamicArrayOfBytes", + "type": "bytes[]" + }, + { + "internalType": "string", + "name": "aString", + "type": "string" + } + ], + "internalType": "struct AbiGenDummy.Struct[]", + "name": "", + "type": "tuple[]" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, { "constant": true, "inputs": [], @@ -313,22 +613,27 @@ { "components": [ { + "internalType": "bytes", "name": "someBytes", "type": "bytes" }, { + "internalType": "uint32", "name": "anInteger", "type": "uint32" }, { + "internalType": "bytes[]", "name": "aDynamicArrayOfBytes", "type": "bytes[]" }, { + "internalType": "string", "name": "aString", "type": "string" } ], + "internalType": "struct AbiGenDummy.Struct", "name": "s", "type": "tuple" } @@ -343,6 +648,7 @@ "name": "pureFunctionWithConstant", "outputs": [ { + "internalType": "uint256", "name": "someConstant", "type": "uint256" } @@ -351,11 +657,76 @@ "stateMutability": "pure", "type": "function" }, + { + "constant": true, + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "simpleInputNoOutput", + "outputs": [], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "string", + "name": "a", + "type": "string" + } + ], + "name": "overloadedMethod", + "outputs": [], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": "int256", + "name": "a", + "type": "int256" + } + ], + "name": "overloadedMethod", + "outputs": [], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_value", + "type": "uint256" + } + ], + "name": "Withdrawal", + "type": "event" + }, { "anonymous": false, "inputs": [ { "indexed": false, + "internalType": "uint8", "name": "param", "type": "uint8" } @@ -372,6 +743,34 @@ "a": "the array of bytes being accepted" } }, + "complexInputComplexOutput((uint256,bytes,string))": { + "details": "Tests decoding when the input and output are complex." + }, + "ecrecoverFn(bytes32,uint8,bytes32,bytes32)": { + "details": "test that devdocs will be generated and that multiline devdocs will look okay", + "params": { + "hash": "description of some hash. Let's make this line super long to demonstrate hanging indents for method params. It has to be more than one hundred twenty columns.", + "r": "ECDSA r output", + "s": "ECDSA s output", + "v": "some v, recovery id" + }, + "return": "the signerAddress that created this signature. this line too is super long in order to demonstrate the proper hanging indentation in generated code." + }, + "multiInputMultiOutput(uint256,bytes,string)": { + "details": "Tests decoding when the input and output are complex and have more than one argument." + }, + "noInputNoOutput()": { + "details": "Tests decoding when both input and output are empty." + }, + "noInputSimpleOutput()": { + "details": "Tests decoding when input is empty and output is non-empty." + }, + "simpleInputNoOutput(uint256)": { + "details": "Tests decoding when input is not empty but output is empty." + }, + "simpleInputSimpleOutput(uint256)": { + "details": "Tests decoding when both input and output are non-empty." + }, "structOutput()": { "details": "a method that returns a struct", "return": "a Struct struct" @@ -381,15 +780,15 @@ "evm": { "bytecode": { "linkReferences": {}, - "object": "0x608060405234801561001057600080fd5b50610b98806100206000396000f3fe608060405234801561001057600080fd5b506004361061011a5760003560e01c806363d69c88116100b25780639a3b618511610081578063ae2dae1711610066578063ae2dae17146101f9578063d6d7618c14610207578063d88be12f1461021c5761011a565b80639a3b6185146101e9578063a3c2f6b6146101f15761011a565b806363d69c88146101a0578063647341eb146101b357806376f15d5b146101c15780638ee52b4e146101d65761011a565b80634582eab2116100ee5780634582eab21461017357806345fdbdb71461017b57806359c28add146101835780635ba3c7c0146101985761011a565b806209e4371461011f5780630527c28f1461012957806336b323961461013c5780633e9ef66a14610165575b600080fd5b610127610224565b005b6101276101373660046106d7565b61025f565b61014f61014a366004610714565b610262565b60405161015c9190610999565b60405180910390f35b610127610137366004610757565b610127610344565b6101276103a9565b61018b6103db565b60405161015c9190610a60565b6101276103e6565b61014f6101ae366004610685565b61044b565b61012761013736600461081c565b6101c9610454565b60405161015c9190610ad3565b6101c96101e4366004610851565b610462565b610127610468565b6101c9610473565b61012761013736600461078c565b61020f610478565b60405161015c9190610ac0565b6101c9610480565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161025690610a29565b60405180910390fd5b50565b600060606040518060400160405280601c81526020017f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152509050600081876040516020016102b3929190610977565b604051602081830303815290604052805190602001209050600181878787604051600081526020016040526040516102ee94939291906109ba565b6020604051602081039080840390855afa158015610310573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015198975050505050505050565b604080518082018252601481527f5245564552545f574954485f434f4e5354414e54000000000000000000000000602082015290517f08c379a000000000000000000000000000000000000000000000000000000000815261025691906004016109d8565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610256906109f2565b6103e3610486565b90565b604080518082018252601581527f524551554952455f574954485f434f4e5354414e540000000000000000000000602082015290517f08c379a000000000000000000000000000000000000000000000000000000000815261025691906004016109d8565b50929392505050565b600080546001019081905590565b60010190565b600080546001019055565b600190565b6103e36104a6565b6104d290565b6040518060a001604052806104996104a6565b8152602001606081525090565b604051806080016040528060608152602001600063ffffffff16815260200160608152602001606081525090565b600082601f8301126104e4578081fd5b813567ffffffffffffffff8111156104fa578182fd5b60206105098182840201610adc565b828152925080830184820160005b848110156105405761052e888584358a010161054b565b83529183019190830190600101610517565b505050505092915050565b600082601f83011261055b578081fd5b813567ffffffffffffffff811115610571578182fd5b6105a260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610adc565b91508082528360208285010111156105b957600080fd5b8060208401602084013760009082016020015292915050565b6000608082840312156105e3578081fd5b6105ed6080610adc565b90506000823567ffffffffffffffff80821115610608578283fd5b6106148683870161054b565b84526020850135915063ffffffff8216821461062e578283fd5b8160208501526040850135915080821115610647578283fd5b610653868387016104d4565b6040850152606085013591508082111561066b578283fd5b506106788582860161054b565b6060840152505092915050565b600080600080600060a0868803121561069d57600080fd5b85356106a881610b33565b9450602086013593506040860135925060608601356106c681610b33565b949793965091946080013592915050565b6000602082840312156106e957600080fd5b813567ffffffffffffffff81111561070057600080fd5b61070c848285016104d4565b949350505050565b6000806000806080858703121561072a57600080fd5b84359350602085013560ff8116811461074257600080fd5b93969395505050506040820135916060013590565b60006020828403121561076957600080fd5b813567ffffffffffffffff81111561078057600080fd5b61070c8482850161054b565b60006020828403121561079d578081fd5b813567ffffffffffffffff808211156107b4578283fd5b818401604081870312156107c6578384fd5b6107d06040610adc565b92508035828111156107e0578485fd5b6107ec878284016105d2565b845250602081013582811115610800578485fd5b61080c8782840161054b565b6020850152509195945050505050565b60006020828403121561082e57600080fd5b813567ffffffffffffffff81111561084557600080fd5b61070c848285016105d2565b60006020828403121561086357600080fd5b5035919050565b60008151808452610882816020860160208601610b03565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60008151608084526108c9608085018261086a565b6020915063ffffffff82850151168286015260408401518582036040870152818151808452848401915084858202850101858401600094505b82851015610950577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086830301845261093c82825161086a565b600195909501949387019391508601610902565b506060880151955088810360608a015261096a818761086a565b9998505050505050505050565b60008351610989818460208801610b03565b9190910191825250602001919050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b93845260ff9290921660208401526040830152606082015260800190565b6000602082526109eb602083018461086a565b9392505050565b6020808252600d908201527f53494d504c455f52455645525400000000000000000000000000000000000000604082015260600190565b6020808252600e908201527f53494d504c455f52455155495245000000000000000000000000000000000000604082015260600190565b600060208252825160406020840152610a7c60608401826108b4565b602085015191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848203016040850152610ab7818361086a565b95945050505050565b6000602082526109eb60208301846108b4565b90815260200190565b60405181810167ffffffffffffffff81118282101715610afb57600080fd5b604052919050565b60005b83811015610b1e578181015183820152602001610b06565b83811115610b2d576000848401525b50505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461025f57600080fdfea365627a7a72305820888f51db8be2b65eeba07b18b43cdc6dad5d8e6807eb4aa7f11e06f111742aef6c6578706572696d656e74616cf564736f6c634300050a0040", - "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0xB98 DUP1 PUSH2 0x20 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x11A JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x63D69C88 GT PUSH2 0xB2 JUMPI DUP1 PUSH4 0x9A3B6185 GT PUSH2 0x81 JUMPI DUP1 PUSH4 0xAE2DAE17 GT PUSH2 0x66 JUMPI DUP1 PUSH4 0xAE2DAE17 EQ PUSH2 0x1F9 JUMPI DUP1 PUSH4 0xD6D7618C EQ PUSH2 0x207 JUMPI DUP1 PUSH4 0xD88BE12F EQ PUSH2 0x21C JUMPI PUSH2 0x11A JUMP JUMPDEST DUP1 PUSH4 0x9A3B6185 EQ PUSH2 0x1E9 JUMPI DUP1 PUSH4 0xA3C2F6B6 EQ PUSH2 0x1F1 JUMPI PUSH2 0x11A JUMP JUMPDEST DUP1 PUSH4 0x63D69C88 EQ PUSH2 0x1A0 JUMPI DUP1 PUSH4 0x647341EB EQ PUSH2 0x1B3 JUMPI DUP1 PUSH4 0x76F15D5B EQ PUSH2 0x1C1 JUMPI DUP1 PUSH4 0x8EE52B4E EQ PUSH2 0x1D6 JUMPI PUSH2 0x11A JUMP JUMPDEST DUP1 PUSH4 0x4582EAB2 GT PUSH2 0xEE JUMPI DUP1 PUSH4 0x4582EAB2 EQ PUSH2 0x173 JUMPI DUP1 PUSH4 0x45FDBDB7 EQ PUSH2 0x17B JUMPI DUP1 PUSH4 0x59C28ADD EQ PUSH2 0x183 JUMPI DUP1 PUSH4 0x5BA3C7C0 EQ PUSH2 0x198 JUMPI PUSH2 0x11A JUMP JUMPDEST DUP1 PUSH3 0x9E437 EQ PUSH2 0x11F JUMPI DUP1 PUSH4 0x527C28F EQ PUSH2 0x129 JUMPI DUP1 PUSH4 0x36B32396 EQ PUSH2 0x13C JUMPI DUP1 PUSH4 0x3E9EF66A EQ PUSH2 0x165 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x127 PUSH2 0x224 JUMP JUMPDEST STOP JUMPDEST PUSH2 0x127 PUSH2 0x137 CALLDATASIZE PUSH1 0x4 PUSH2 0x6D7 JUMP JUMPDEST PUSH2 0x25F JUMP JUMPDEST PUSH2 0x14F PUSH2 0x14A CALLDATASIZE PUSH1 0x4 PUSH2 0x714 JUMP JUMPDEST PUSH2 0x262 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x15C SWAP2 SWAP1 PUSH2 0x999 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x127 PUSH2 0x137 CALLDATASIZE PUSH1 0x4 PUSH2 0x757 JUMP JUMPDEST PUSH2 0x127 PUSH2 0x344 JUMP JUMPDEST PUSH2 0x127 PUSH2 0x3A9 JUMP JUMPDEST PUSH2 0x18B PUSH2 0x3DB JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x15C SWAP2 SWAP1 PUSH2 0xA60 JUMP JUMPDEST PUSH2 0x127 PUSH2 0x3E6 JUMP JUMPDEST PUSH2 0x14F PUSH2 0x1AE CALLDATASIZE PUSH1 0x4 PUSH2 0x685 JUMP JUMPDEST PUSH2 0x44B JUMP JUMPDEST PUSH2 0x127 PUSH2 0x137 CALLDATASIZE PUSH1 0x4 PUSH2 0x81C JUMP JUMPDEST PUSH2 0x1C9 PUSH2 0x454 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x15C SWAP2 SWAP1 PUSH2 0xAD3 JUMP JUMPDEST PUSH2 0x1C9 PUSH2 0x1E4 CALLDATASIZE PUSH1 0x4 PUSH2 0x851 JUMP JUMPDEST PUSH2 0x462 JUMP JUMPDEST PUSH2 0x127 PUSH2 0x468 JUMP JUMPDEST PUSH2 0x1C9 PUSH2 0x473 JUMP JUMPDEST PUSH2 0x127 PUSH2 0x137 CALLDATASIZE PUSH1 0x4 PUSH2 0x78C JUMP JUMPDEST PUSH2 0x20F PUSH2 0x478 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x15C SWAP2 SWAP1 PUSH2 0xAC0 JUMP JUMPDEST PUSH2 0x1C9 PUSH2 0x480 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x256 SWAP1 PUSH2 0xA29 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x60 PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x1C DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x19457468657265756D205369676E6564204D6573736167653A0A333200000000 DUP2 MSTORE POP SWAP1 POP PUSH1 0x0 DUP2 DUP8 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x2B3 SWAP3 SWAP2 SWAP1 PUSH2 0x977 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 SWAP1 POP PUSH1 0x1 DUP2 DUP8 DUP8 DUP8 PUSH1 0x40 MLOAD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD PUSH2 0x2EE SWAP5 SWAP4 SWAP3 SWAP2 SWAP1 PUSH2 0x9BA JUMP JUMPDEST PUSH1 0x20 PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 SUB SWAP1 DUP1 DUP5 SUB SWAP1 DUP6 GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x310 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP PUSH1 0x40 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 ADD MLOAD SWAP9 SWAP8 POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD DUP3 MSTORE PUSH1 0x14 DUP2 MSTORE PUSH32 0x5245564552545F574954485F434F4E5354414E54000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE SWAP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH2 0x256 SWAP2 SWAP1 PUSH1 0x4 ADD PUSH2 0x9D8 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x256 SWAP1 PUSH2 0x9F2 JUMP JUMPDEST PUSH2 0x3E3 PUSH2 0x486 JUMP JUMPDEST SWAP1 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD DUP3 MSTORE PUSH1 0x15 DUP2 MSTORE PUSH32 0x524551554952455F574954485F434F4E5354414E540000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE SWAP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH2 0x256 SWAP2 SWAP1 PUSH1 0x4 ADD PUSH2 0x9D8 JUMP JUMPDEST POP SWAP3 SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 ADD SWAP1 DUP2 SWAP1 SSTORE SWAP1 JUMP JUMPDEST PUSH1 0x1 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 ADD SWAP1 SSTORE JUMP JUMPDEST PUSH1 0x1 SWAP1 JUMP JUMPDEST PUSH2 0x3E3 PUSH2 0x4A6 JUMP JUMPDEST PUSH2 0x4D2 SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0xA0 ADD PUSH1 0x40 MSTORE DUP1 PUSH2 0x499 PUSH2 0x4A6 JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x80 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH4 0xFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x4E4 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x4FA JUMPI DUP2 DUP3 REVERT JUMPDEST PUSH1 0x20 PUSH2 0x509 DUP2 DUP3 DUP5 MUL ADD PUSH2 0xADC JUMP JUMPDEST DUP3 DUP2 MSTORE SWAP3 POP DUP1 DUP4 ADD DUP5 DUP3 ADD PUSH1 0x0 JUMPDEST DUP5 DUP2 LT ISZERO PUSH2 0x540 JUMPI PUSH2 0x52E DUP9 DUP6 DUP5 CALLDATALOAD DUP11 ADD ADD PUSH2 0x54B JUMP JUMPDEST DUP4 MSTORE SWAP2 DUP4 ADD SWAP2 SWAP1 DUP4 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x517 JUMP JUMPDEST POP POP POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x55B JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x571 JUMPI DUP2 DUP3 REVERT JUMPDEST PUSH2 0x5A2 PUSH1 0x20 PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 PUSH1 0x1F DUP5 ADD AND ADD PUSH2 0xADC JUMP JUMPDEST SWAP2 POP DUP1 DUP3 MSTORE DUP4 PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0x5B9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH1 0x20 DUP5 ADD PUSH1 0x20 DUP5 ADD CALLDATACOPY PUSH1 0x0 SWAP1 DUP3 ADD PUSH1 0x20 ADD MSTORE SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x80 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x5E3 JUMPI DUP1 DUP2 REVERT JUMPDEST PUSH2 0x5ED PUSH1 0x80 PUSH2 0xADC JUMP JUMPDEST SWAP1 POP PUSH1 0x0 DUP3 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x608 JUMPI DUP3 DUP4 REVERT JUMPDEST PUSH2 0x614 DUP7 DUP4 DUP8 ADD PUSH2 0x54B JUMP JUMPDEST DUP5 MSTORE PUSH1 0x20 DUP6 ADD CALLDATALOAD SWAP2 POP PUSH4 0xFFFFFFFF DUP3 AND DUP3 EQ PUSH2 0x62E JUMPI DUP3 DUP4 REVERT JUMPDEST DUP2 PUSH1 0x20 DUP6 ADD MSTORE PUSH1 0x40 DUP6 ADD CALLDATALOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x647 JUMPI DUP3 DUP4 REVERT JUMPDEST PUSH2 0x653 DUP7 DUP4 DUP8 ADD PUSH2 0x4D4 JUMP JUMPDEST PUSH1 0x40 DUP6 ADD MSTORE PUSH1 0x60 DUP6 ADD CALLDATALOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x66B JUMPI DUP3 DUP4 REVERT JUMPDEST POP PUSH2 0x678 DUP6 DUP3 DUP7 ADD PUSH2 0x54B JUMP JUMPDEST PUSH1 0x60 DUP5 ADD MSTORE POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x0 PUSH1 0xA0 DUP7 DUP9 SUB SLT ISZERO PUSH2 0x69D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP6 CALLDATALOAD PUSH2 0x6A8 DUP2 PUSH2 0xB33 JUMP JUMPDEST SWAP5 POP PUSH1 0x20 DUP7 ADD CALLDATALOAD SWAP4 POP PUSH1 0x40 DUP7 ADD CALLDATALOAD SWAP3 POP PUSH1 0x60 DUP7 ADD CALLDATALOAD PUSH2 0x6C6 DUP2 PUSH2 0xB33 JUMP JUMPDEST SWAP5 SWAP8 SWAP4 SWAP7 POP SWAP2 SWAP5 PUSH1 0x80 ADD CALLDATALOAD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x6E9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x700 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x70C DUP5 DUP3 DUP6 ADD PUSH2 0x4D4 JUMP JUMPDEST SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x80 DUP6 DUP8 SUB SLT ISZERO PUSH2 0x72A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP5 CALLDATALOAD SWAP4 POP PUSH1 0x20 DUP6 ADD CALLDATALOAD PUSH1 0xFF DUP2 AND DUP2 EQ PUSH2 0x742 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP7 SWAP4 SWAP6 POP POP POP POP PUSH1 0x40 DUP3 ADD CALLDATALOAD SWAP2 PUSH1 0x60 ADD CALLDATALOAD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x769 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x780 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x70C DUP5 DUP3 DUP6 ADD PUSH2 0x54B JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x79D JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x7B4 JUMPI DUP3 DUP4 REVERT JUMPDEST DUP2 DUP5 ADD PUSH1 0x40 DUP2 DUP8 SUB SLT ISZERO PUSH2 0x7C6 JUMPI DUP4 DUP5 REVERT JUMPDEST PUSH2 0x7D0 PUSH1 0x40 PUSH2 0xADC JUMP JUMPDEST SWAP3 POP DUP1 CALLDATALOAD DUP3 DUP2 GT ISZERO PUSH2 0x7E0 JUMPI DUP5 DUP6 REVERT JUMPDEST PUSH2 0x7EC DUP8 DUP3 DUP5 ADD PUSH2 0x5D2 JUMP JUMPDEST DUP5 MSTORE POP PUSH1 0x20 DUP2 ADD CALLDATALOAD DUP3 DUP2 GT ISZERO PUSH2 0x800 JUMPI DUP5 DUP6 REVERT JUMPDEST PUSH2 0x80C DUP8 DUP3 DUP5 ADD PUSH2 0x54B JUMP JUMPDEST PUSH1 0x20 DUP6 ADD MSTORE POP SWAP2 SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x82E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x845 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x70C DUP5 DUP3 DUP6 ADD PUSH2 0x5D2 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x863 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD DUP1 DUP5 MSTORE PUSH2 0x882 DUP2 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP7 ADD PUSH2 0xB03 JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x20 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD PUSH1 0x80 DUP5 MSTORE PUSH2 0x8C9 PUSH1 0x80 DUP6 ADD DUP3 PUSH2 0x86A JUMP JUMPDEST PUSH1 0x20 SWAP2 POP PUSH4 0xFFFFFFFF DUP3 DUP6 ADD MLOAD AND DUP3 DUP7 ADD MSTORE PUSH1 0x40 DUP5 ADD MLOAD DUP6 DUP3 SUB PUSH1 0x40 DUP8 ADD MSTORE DUP2 DUP2 MLOAD DUP1 DUP5 MSTORE DUP5 DUP5 ADD SWAP2 POP DUP5 DUP6 DUP3 MUL DUP6 ADD ADD DUP6 DUP5 ADD PUSH1 0x0 SWAP5 POP JUMPDEST DUP3 DUP6 LT ISZERO PUSH2 0x950 JUMPI PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 DUP7 DUP4 SUB ADD DUP5 MSTORE PUSH2 0x93C DUP3 DUP3 MLOAD PUSH2 0x86A JUMP JUMPDEST PUSH1 0x1 SWAP6 SWAP1 SWAP6 ADD SWAP5 SWAP4 DUP8 ADD SWAP4 SWAP2 POP DUP7 ADD PUSH2 0x902 JUMP JUMPDEST POP PUSH1 0x60 DUP9 ADD MLOAD SWAP6 POP DUP9 DUP2 SUB PUSH1 0x60 DUP11 ADD MSTORE PUSH2 0x96A DUP2 DUP8 PUSH2 0x86A JUMP JUMPDEST SWAP10 SWAP9 POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP4 MLOAD PUSH2 0x989 DUP2 DUP5 PUSH1 0x20 DUP9 ADD PUSH2 0xB03 JUMP JUMPDEST SWAP2 SWAP1 SWAP2 ADD SWAP2 DUP3 MSTORE POP PUSH1 0x20 ADD SWAP2 SWAP1 POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP2 SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST SWAP4 DUP5 MSTORE PUSH1 0xFF SWAP3 SWAP1 SWAP3 AND PUSH1 0x20 DUP5 ADD MSTORE PUSH1 0x40 DUP4 ADD MSTORE PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 MSTORE PUSH2 0x9EB PUSH1 0x20 DUP4 ADD DUP5 PUSH2 0x86A JUMP JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0xD SWAP1 DUP3 ADD MSTORE PUSH32 0x53494D504C455F52455645525400000000000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0xE SWAP1 DUP3 ADD MSTORE PUSH32 0x53494D504C455F52455155495245000000000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 MSTORE DUP3 MLOAD PUSH1 0x40 PUSH1 0x20 DUP5 ADD MSTORE PUSH2 0xA7C PUSH1 0x60 DUP5 ADD DUP3 PUSH2 0x8B4 JUMP JUMPDEST PUSH1 0x20 DUP6 ADD MLOAD SWAP2 POP PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 DUP5 DUP3 SUB ADD PUSH1 0x40 DUP6 ADD MSTORE PUSH2 0xAB7 DUP2 DUP4 PUSH2 0x86A JUMP JUMPDEST SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 MSTORE PUSH2 0x9EB PUSH1 0x20 DUP4 ADD DUP5 PUSH2 0x8B4 JUMP JUMPDEST SWAP1 DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP2 DUP2 ADD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT DUP3 DUP3 LT OR ISZERO PUSH2 0xAFB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x40 MSTORE SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0xB1E JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0xB06 JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0xB2D JUMPI PUSH1 0x0 DUP5 DUP5 ADD MSTORE JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND DUP2 EQ PUSH2 0x25F JUMPI PUSH1 0x0 DUP1 REVERT INVALID LOG3 PUSH6 0x627A7A723058 KECCAK256 DUP9 DUP16 MLOAD 0xdb DUP12 0xe2 0xb6 0x5e 0xeb LOG0 PUSH28 0x18B43CDC6DAD5D8E6807EB4AA7F11E06F111742AEF6C657870657269 PUSH14 0x656E74616CF564736F6C63430005 EXP STOP BLOCKHASH ", - "sourceMap": "641:2757:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;641:2757:0;;;;;;;" + "object": "0x608060405234801561001057600080fd5b506113c2806100206000396000f3fe608060405234801561001057600080fd5b50600436106101ce5760003560e01c8063647341eb11610104578063ae2dae17116100a2578063d88be12f11610071578063d88be12f14610388578063ee8b86fb14610390578063f408fb311461026e578063fa315f9d146103a3576101ce565b8063ae2dae171461033a578063bb60736214610348578063bdab16881461035e578063d6d7618c14610373576101ce565b80637a791e6e116100de5780637a791e6e1461030f5780638ee52b4e146103175780639a3b61851461032a578063a3c2f6b614610332576101ce565b8063647341eb146102d957806376f15d5b146102e75780637833bec0146102ef576101ce565b80634303a54211610171578063586f84b21161014b578063586f84b21461029457806359c28add146102a95780635ba3c7c0146102be57806363d69c88146102c6576101ce565b80634303a5421461027c5780634582eab21461028457806345fdbdb71461028c576101ce565b80632e1a7d4d116101ad5780632e1a7d4d146102195780633687617d1461022c57806336b323961461024e5780633e9ef66a1461026e576101ce565b806209e437146101d35780630527c28f146101dd5780631310e444146101f0575b600080fd5b6101db6103b1565b005b6101db6101eb366004610c35565b6103ee565b6102036101fe366004610cea565b6103f1565b60405161021091906112e4565b60405180910390f35b6101db610227366004610cea565b6103f8565b61023f61023a366004610e62565b610449565b604051610210939291906110b9565b61026161025c366004610c72565b6104e9565b6040516102109190610ffb565b6101db6101eb366004610cb5565b6102036105cb565b6101db6105d2565b6101db610637565b61029c610669565b604051610210919061126f565b6102b1610671565b604051610210919061127a565b6101db610679565b6102616102d4366004610be3565b6106de565b6101db6101eb366004610e2d565b6102036106e7565b6103026102fd366004610d03565b6106f5565b6040516102109190611183565b6101db6107b2565b610203610325366004610cea565b6107b7565b6101db6107bd565b6102036107c8565b6101db6101eb366004610d9d565b6103506107cd565b6040516102109291906112ed565b610366610806565b604051610210919061101c565b61037b61080b565b60405161021091906112d1565b610203610964565b6101db61039e366004610cea565b6101eb565b6101db6101eb366004610cea565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103e39061114c565b60405180910390fd5b565b50565b506107c790565b3373ffffffffffffffffffffffffffffffffffffffff167f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b658260405161043e91906112e4565b60405180910390a250565b505060408051808201825260048082527f1234567800000000000000000000000000000000000000000000000000000000602080840191909152835180850185528281527f87654321000000000000000000000000000000000000000000000000000000008183015284518086019095529184527f616d657400000000000000000000000000000000000000000000000000000000908401529093909250565b600060606040518060400160405280601c81526020017f19457468657265756d205369676e6564204d6573736167653a0a33320000000081525090506000818760405160200161053a929190610fd9565b60405160208183030381529060405280519060200120905060018187878760405160008152602001604052604051610575949392919061109b565b6020604051602081039080840390855afa158015610597573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015198975050505050505050565b6107c75b90565b604080518082018252601481527f5245564552545f574954485f434f4e5354414e54000000000000000000000000602082015290517f08c379a00000000000000000000000000000000000000000000000000000000081526103e391906004016110fb565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103e390611115565b6105cf61096a565b6105cf610982565b604080518082018252601581527f524551554952455f574954485f434f4e5354414e540000000000000000000000602082015290517f08c379a00000000000000000000000000000000000000000000000000000000081526103e391906004016110fb565b50929392505050565b600080546001019081905590565b6106fd6109a2565b50604080516080810182529182528051808201825260048082527f123456780000000000000000000000000000000000000000000000000000000060208381019190915280850192909252825180840184528181527f87654321000000000000000000000000000000000000000000000000000000008184015284840152825180840190935282527f616d65740000000000000000000000000000000000000000000000000000000090820152606082015290565b6103ec565b60010190565b600080546001019055565b600190565b60408051808201909152600581527f68656c6c6f0000000000000000000000000000000000000000000000000000006020820152600191565b606090565b6108136109d0565b6040805160028082526060828101909352816020015b60608152602001906001900390816108295790505090506040518060400160405280600581526020017f30783132330000000000000000000000000000000000000000000000000000008152508160008151811061088357fe5b60200260200101819052506040518060400160405280600581526020017f3078333231000000000000000000000000000000000000000000000000000000815250816001815181106108d157fe5b6020908102919091018101919091526040805160c0810182526005608082018181527f307831323300000000000000000000000000000000000000000000000000000060a0840152825281840152808201939093528051808201909152600381527f6162630000000000000000000000000000000000000000000000000000000000918101919091526060820152905090565b6104d290565b604051806020016040528061097d6109fe565b905290565b60405180604001604052806109956109d0565b8152602001606081525090565b60405180608001604052806109b5610a11565b81526020016060815260200160608152602001606081525090565b604051806080016040528060608152602001600063ffffffff16815260200160608152602001606081525090565b6040518060200160405280600081525090565b60405180606001604052806000815260200160608152602001606081525090565b600082601f830112610a42578081fd5b813567ffffffffffffffff811115610a58578182fd5b6020610a678182840201611306565b828152925080830184820160005b84811015610a9e57610a8c888584358a0101610aa9565b83529183019190830190600101610a75565b505050505092915050565b600082601f830112610ab9578081fd5b813567ffffffffffffffff811115610acf578182fd5b610b0060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601611306565b9150808252836020828501011115610b1757600080fd5b8060208401602084013760009082016020015292915050565b600060808284031215610b41578081fd5b610b4b6080611306565b90506000823567ffffffffffffffff80821115610b66578283fd5b610b7286838701610aa9565b84526020850135915063ffffffff82168214610b8c578283fd5b8160208501526040850135915080821115610ba5578283fd5b610bb186838701610a32565b60408501526060850135915080821115610bc9578283fd5b50610bd685828601610aa9565b6060840152505092915050565b600080600080600060a08688031215610bfb57600080fd5b8535610c068161135d565b945060208601359350604086013592506060860135610c248161135d565b949793965091946080013592915050565b600060208284031215610c4757600080fd5b813567ffffffffffffffff811115610c5e57600080fd5b610c6a84828501610a32565b949350505050565b60008060008060808587031215610c8857600080fd5b84359350602085013560ff81168114610ca057600080fd5b93969395505050506040820135916060013590565b600060208284031215610cc757600080fd5b813567ffffffffffffffff811115610cde57600080fd5b610c6a84828501610aa9565b600060208284031215610cfc57600080fd5b5035919050565b600060208284031215610d14578081fd5b813567ffffffffffffffff80821115610d2b578283fd5b81840160608187031215610d3d578384fd5b610d476060611306565b925080358352602081013582811115610d5e578485fd5b610d6a87828401610aa9565b602085015250604081013582811115610d81578485fd5b610d8d87828401610aa9565b6040850152509195945050505050565b600060208284031215610dae578081fd5b813567ffffffffffffffff80821115610dc5578283fd5b81840160408187031215610dd7578384fd5b610de16040611306565b9250803582811115610df1578485fd5b610dfd87828401610b30565b845250602081013582811115610e11578485fd5b610e1d87828401610aa9565b6020850152509195945050505050565b600060208284031215610e3f57600080fd5b813567ffffffffffffffff811115610e5657600080fd5b610c6a84828501610b30565b600080600060608486031215610e76578081fd5b83359250602084013567ffffffffffffffff80821115610e94578283fd5b610ea087838801610aa9565b93506040860135915080821115610eb5578283fd5b50610ec286828701610aa9565b9150509250925092565b60008151808452610ee481602086016020860161132d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000815160808452610f2b6080850182610ecc565b6020915063ffffffff82850151168286015260408401518582036040870152818151808452848401915084858202850101858401600094505b82851015610fb2577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0868303018452610f9e828251610ecc565b600195909501949387019391508601610f64565b506060880151955088810360608a0152610fcc8187610ecc565b9998505050505050505050565b60008351610feb81846020880161132d565b9190910191825250602001919050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b600060208083018184528085518083526040860191506040848202870101925083870160005b8281101561108e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261107c858351610f16565b94509285019290850190600101611042565b5092979650505050505050565b93845260ff9290921660208401526040830152606082015260800190565b6000606082526110cc6060830186610ecc565b82810360208401526110de8186610ecc565b83810360408501526110f08186610ecc565b979650505050505050565b60006020825261110e6020830184610ecc565b9392505050565b6020808252600d908201527f53494d504c455f52455645525400000000000000000000000000000000000000604082015260600190565b6020808252600e908201527f53494d504c455f52455155495245000000000000000000000000000000000000604082015260600190565b600060208252825160806020840152805160a08401526020810151606060c08501526111b3610100850182610ecc565b604083015191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff608582030160e08601526111ee8183610ecc565b9250505060208401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08085840301604086015261122c8383610ecc565b60408701519350818682030160608701526112478185610ecc565b9250506060860151925080858303016080860152506112668183610ecc565b95945050505050565b905151815260200190565b6000602082528251604060208401526112966060840182610f16565b602085015191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08482030160408501526112668183610ecc565b60006020825261110e6020830184610f16565b90815260200190565b600083825260406020830152610c6a6040830184610ecc565b60405181810167ffffffffffffffff8111828210171561132557600080fd5b604052919050565b60005b83811015611348578181015183820152602001611330565b83811115611357576000848401525b50505050565b73ffffffffffffffffffffffffffffffffffffffff811681146103ee57600080fdfea365627a7a72315820317467b7d0f0e7d2d63822db9997196e2e42b127bd2b1dd9c02856a6f5b591846c6578706572696d656e74616cf564736f6c634300050b0040", + "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x13C2 DUP1 PUSH2 0x20 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x1CE JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x647341EB GT PUSH2 0x104 JUMPI DUP1 PUSH4 0xAE2DAE17 GT PUSH2 0xA2 JUMPI DUP1 PUSH4 0xD88BE12F GT PUSH2 0x71 JUMPI DUP1 PUSH4 0xD88BE12F EQ PUSH2 0x388 JUMPI DUP1 PUSH4 0xEE8B86FB EQ PUSH2 0x390 JUMPI DUP1 PUSH4 0xF408FB31 EQ PUSH2 0x26E JUMPI DUP1 PUSH4 0xFA315F9D EQ PUSH2 0x3A3 JUMPI PUSH2 0x1CE JUMP JUMPDEST DUP1 PUSH4 0xAE2DAE17 EQ PUSH2 0x33A JUMPI DUP1 PUSH4 0xBB607362 EQ PUSH2 0x348 JUMPI DUP1 PUSH4 0xBDAB1688 EQ PUSH2 0x35E JUMPI DUP1 PUSH4 0xD6D7618C EQ PUSH2 0x373 JUMPI PUSH2 0x1CE JUMP JUMPDEST DUP1 PUSH4 0x7A791E6E GT PUSH2 0xDE JUMPI DUP1 PUSH4 0x7A791E6E EQ PUSH2 0x30F JUMPI DUP1 PUSH4 0x8EE52B4E EQ PUSH2 0x317 JUMPI DUP1 PUSH4 0x9A3B6185 EQ PUSH2 0x32A JUMPI DUP1 PUSH4 0xA3C2F6B6 EQ PUSH2 0x332 JUMPI PUSH2 0x1CE JUMP JUMPDEST DUP1 PUSH4 0x647341EB EQ PUSH2 0x2D9 JUMPI DUP1 PUSH4 0x76F15D5B EQ PUSH2 0x2E7 JUMPI DUP1 PUSH4 0x7833BEC0 EQ PUSH2 0x2EF JUMPI PUSH2 0x1CE JUMP JUMPDEST DUP1 PUSH4 0x4303A542 GT PUSH2 0x171 JUMPI DUP1 PUSH4 0x586F84B2 GT PUSH2 0x14B JUMPI DUP1 PUSH4 0x586F84B2 EQ PUSH2 0x294 JUMPI DUP1 PUSH4 0x59C28ADD EQ PUSH2 0x2A9 JUMPI DUP1 PUSH4 0x5BA3C7C0 EQ PUSH2 0x2BE JUMPI DUP1 PUSH4 0x63D69C88 EQ PUSH2 0x2C6 JUMPI PUSH2 0x1CE JUMP JUMPDEST DUP1 PUSH4 0x4303A542 EQ PUSH2 0x27C JUMPI DUP1 PUSH4 0x4582EAB2 EQ PUSH2 0x284 JUMPI DUP1 PUSH4 0x45FDBDB7 EQ PUSH2 0x28C JUMPI PUSH2 0x1CE JUMP JUMPDEST DUP1 PUSH4 0x2E1A7D4D GT PUSH2 0x1AD JUMPI DUP1 PUSH4 0x2E1A7D4D EQ PUSH2 0x219 JUMPI DUP1 PUSH4 0x3687617D EQ PUSH2 0x22C JUMPI DUP1 PUSH4 0x36B32396 EQ PUSH2 0x24E JUMPI DUP1 PUSH4 0x3E9EF66A EQ PUSH2 0x26E JUMPI PUSH2 0x1CE JUMP JUMPDEST DUP1 PUSH3 0x9E437 EQ PUSH2 0x1D3 JUMPI DUP1 PUSH4 0x527C28F EQ PUSH2 0x1DD JUMPI DUP1 PUSH4 0x1310E444 EQ PUSH2 0x1F0 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1DB PUSH2 0x3B1 JUMP JUMPDEST STOP JUMPDEST PUSH2 0x1DB PUSH2 0x1EB CALLDATASIZE PUSH1 0x4 PUSH2 0xC35 JUMP JUMPDEST PUSH2 0x3EE JUMP JUMPDEST PUSH2 0x203 PUSH2 0x1FE CALLDATASIZE PUSH1 0x4 PUSH2 0xCEA JUMP JUMPDEST PUSH2 0x3F1 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x210 SWAP2 SWAP1 PUSH2 0x12E4 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x1DB PUSH2 0x227 CALLDATASIZE PUSH1 0x4 PUSH2 0xCEA JUMP JUMPDEST PUSH2 0x3F8 JUMP JUMPDEST PUSH2 0x23F PUSH2 0x23A CALLDATASIZE PUSH1 0x4 PUSH2 0xE62 JUMP JUMPDEST PUSH2 0x449 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x210 SWAP4 SWAP3 SWAP2 SWAP1 PUSH2 0x10B9 JUMP JUMPDEST PUSH2 0x261 PUSH2 0x25C CALLDATASIZE PUSH1 0x4 PUSH2 0xC72 JUMP JUMPDEST PUSH2 0x4E9 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x210 SWAP2 SWAP1 PUSH2 0xFFB JUMP JUMPDEST PUSH2 0x1DB PUSH2 0x1EB CALLDATASIZE PUSH1 0x4 PUSH2 0xCB5 JUMP JUMPDEST PUSH2 0x203 PUSH2 0x5CB JUMP JUMPDEST PUSH2 0x1DB PUSH2 0x5D2 JUMP JUMPDEST PUSH2 0x1DB PUSH2 0x637 JUMP JUMPDEST PUSH2 0x29C PUSH2 0x669 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x210 SWAP2 SWAP1 PUSH2 0x126F JUMP JUMPDEST PUSH2 0x2B1 PUSH2 0x671 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x210 SWAP2 SWAP1 PUSH2 0x127A JUMP JUMPDEST PUSH2 0x1DB PUSH2 0x679 JUMP JUMPDEST PUSH2 0x261 PUSH2 0x2D4 CALLDATASIZE PUSH1 0x4 PUSH2 0xBE3 JUMP JUMPDEST PUSH2 0x6DE JUMP JUMPDEST PUSH2 0x1DB PUSH2 0x1EB CALLDATASIZE PUSH1 0x4 PUSH2 0xE2D JUMP JUMPDEST PUSH2 0x203 PUSH2 0x6E7 JUMP JUMPDEST PUSH2 0x302 PUSH2 0x2FD CALLDATASIZE PUSH1 0x4 PUSH2 0xD03 JUMP JUMPDEST PUSH2 0x6F5 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x210 SWAP2 SWAP1 PUSH2 0x1183 JUMP JUMPDEST PUSH2 0x1DB PUSH2 0x7B2 JUMP JUMPDEST PUSH2 0x203 PUSH2 0x325 CALLDATASIZE PUSH1 0x4 PUSH2 0xCEA JUMP JUMPDEST PUSH2 0x7B7 JUMP JUMPDEST PUSH2 0x1DB PUSH2 0x7BD JUMP JUMPDEST PUSH2 0x203 PUSH2 0x7C8 JUMP JUMPDEST PUSH2 0x1DB PUSH2 0x1EB CALLDATASIZE PUSH1 0x4 PUSH2 0xD9D JUMP JUMPDEST PUSH2 0x350 PUSH2 0x7CD JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x210 SWAP3 SWAP2 SWAP1 PUSH2 0x12ED JUMP JUMPDEST PUSH2 0x366 PUSH2 0x806 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x210 SWAP2 SWAP1 PUSH2 0x101C JUMP JUMPDEST PUSH2 0x37B PUSH2 0x80B JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x210 SWAP2 SWAP1 PUSH2 0x12D1 JUMP JUMPDEST PUSH2 0x203 PUSH2 0x964 JUMP JUMPDEST PUSH2 0x1DB PUSH2 0x39E CALLDATASIZE PUSH1 0x4 PUSH2 0xCEA JUMP JUMPDEST PUSH2 0x1EB JUMP JUMPDEST PUSH2 0x1DB PUSH2 0x1EB CALLDATASIZE PUSH1 0x4 PUSH2 0xCEA JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x3E3 SWAP1 PUSH2 0x114C JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST JUMP JUMPDEST POP JUMP JUMPDEST POP PUSH2 0x7C7 SWAP1 JUMP JUMPDEST CALLER PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH32 0x7FCF532C15F0A6DB0BD6D0E038BEA71D30D808C7D98CB3BF7268A95BF5081B65 DUP3 PUSH1 0x40 MLOAD PUSH2 0x43E SWAP2 SWAP1 PUSH2 0x12E4 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG2 POP JUMP JUMPDEST POP POP PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD DUP3 MSTORE PUSH1 0x4 DUP1 DUP3 MSTORE PUSH32 0x1234567800000000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP1 DUP5 ADD SWAP2 SWAP1 SWAP2 MSTORE DUP4 MLOAD DUP1 DUP6 ADD DUP6 MSTORE DUP3 DUP2 MSTORE PUSH32 0x8765432100000000000000000000000000000000000000000000000000000000 DUP2 DUP4 ADD MSTORE DUP5 MLOAD DUP1 DUP7 ADD SWAP1 SWAP6 MSTORE SWAP2 DUP5 MSTORE PUSH32 0x616D657400000000000000000000000000000000000000000000000000000000 SWAP1 DUP5 ADD MSTORE SWAP1 SWAP4 SWAP1 SWAP3 POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x60 PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x1C DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x19457468657265756D205369676E6564204D6573736167653A0A333200000000 DUP2 MSTORE POP SWAP1 POP PUSH1 0x0 DUP2 DUP8 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x53A SWAP3 SWAP2 SWAP1 PUSH2 0xFD9 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 SWAP1 POP PUSH1 0x1 DUP2 DUP8 DUP8 DUP8 PUSH1 0x40 MLOAD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD PUSH2 0x575 SWAP5 SWAP4 SWAP3 SWAP2 SWAP1 PUSH2 0x109B JUMP JUMPDEST PUSH1 0x20 PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 SUB SWAP1 DUP1 DUP5 SUB SWAP1 DUP6 GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x597 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP PUSH1 0x40 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 ADD MLOAD SWAP9 SWAP8 POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH2 0x7C7 JUMPDEST SWAP1 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD DUP3 MSTORE PUSH1 0x14 DUP2 MSTORE PUSH32 0x5245564552545F574954485F434F4E5354414E54000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE SWAP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH2 0x3E3 SWAP2 SWAP1 PUSH1 0x4 ADD PUSH2 0x10FB JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x3E3 SWAP1 PUSH2 0x1115 JUMP JUMPDEST PUSH2 0x5CF PUSH2 0x96A JUMP JUMPDEST PUSH2 0x5CF PUSH2 0x982 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD DUP3 MSTORE PUSH1 0x15 DUP2 MSTORE PUSH32 0x524551554952455F574954485F434F4E5354414E540000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE SWAP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH2 0x3E3 SWAP2 SWAP1 PUSH1 0x4 ADD PUSH2 0x10FB JUMP JUMPDEST POP SWAP3 SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 ADD SWAP1 DUP2 SWAP1 SSTORE SWAP1 JUMP JUMPDEST PUSH2 0x6FD PUSH2 0x9A2 JUMP JUMPDEST POP PUSH1 0x40 DUP1 MLOAD PUSH1 0x80 DUP2 ADD DUP3 MSTORE SWAP2 DUP3 MSTORE DUP1 MLOAD DUP1 DUP3 ADD DUP3 MSTORE PUSH1 0x4 DUP1 DUP3 MSTORE PUSH32 0x1234567800000000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP4 DUP2 ADD SWAP2 SWAP1 SWAP2 MSTORE DUP1 DUP6 ADD SWAP3 SWAP1 SWAP3 MSTORE DUP3 MLOAD DUP1 DUP5 ADD DUP5 MSTORE DUP2 DUP2 MSTORE PUSH32 0x8765432100000000000000000000000000000000000000000000000000000000 DUP2 DUP5 ADD MSTORE DUP5 DUP5 ADD MSTORE DUP3 MLOAD DUP1 DUP5 ADD SWAP1 SWAP4 MSTORE DUP3 MSTORE PUSH32 0x616D657400000000000000000000000000000000000000000000000000000000 SWAP1 DUP3 ADD MSTORE PUSH1 0x60 DUP3 ADD MSTORE SWAP1 JUMP JUMPDEST PUSH2 0x3EC JUMP JUMPDEST PUSH1 0x1 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 ADD SWAP1 SSTORE JUMP JUMPDEST PUSH1 0x1 SWAP1 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD SWAP1 SWAP2 MSTORE PUSH1 0x5 DUP2 MSTORE PUSH32 0x68656C6C6F000000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x1 SWAP2 JUMP JUMPDEST PUSH1 0x60 SWAP1 JUMP JUMPDEST PUSH2 0x813 PUSH2 0x9D0 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x2 DUP1 DUP3 MSTORE PUSH1 0x60 DUP3 DUP2 ADD SWAP1 SWAP4 MSTORE DUP2 PUSH1 0x20 ADD JUMPDEST PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD SWAP1 PUSH1 0x1 SWAP1 SUB SWAP1 DUP2 PUSH2 0x829 JUMPI SWAP1 POP POP SWAP1 POP PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x5 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x3078313233000000000000000000000000000000000000000000000000000000 DUP2 MSTORE POP DUP2 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0x883 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD DUP2 SWAP1 MSTORE POP PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x5 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x3078333231000000000000000000000000000000000000000000000000000000 DUP2 MSTORE POP DUP2 PUSH1 0x1 DUP2 MLOAD DUP2 LT PUSH2 0x8D1 JUMPI INVALID JUMPDEST PUSH1 0x20 SWAP1 DUP2 MUL SWAP2 SWAP1 SWAP2 ADD DUP2 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x40 DUP1 MLOAD PUSH1 0xC0 DUP2 ADD DUP3 MSTORE PUSH1 0x5 PUSH1 0x80 DUP3 ADD DUP2 DUP2 MSTORE PUSH32 0x3078313233000000000000000000000000000000000000000000000000000000 PUSH1 0xA0 DUP5 ADD MSTORE DUP3 MSTORE DUP2 DUP5 ADD MSTORE DUP1 DUP3 ADD SWAP4 SWAP1 SWAP4 MSTORE DUP1 MLOAD DUP1 DUP3 ADD SWAP1 SWAP2 MSTORE PUSH1 0x3 DUP2 MSTORE PUSH32 0x6162630000000000000000000000000000000000000000000000000000000000 SWAP2 DUP2 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x60 DUP3 ADD MSTORE SWAP1 POP SWAP1 JUMP JUMPDEST PUSH2 0x4D2 SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x20 ADD PUSH1 0x40 MSTORE DUP1 PUSH2 0x97D PUSH2 0x9FE JUMP JUMPDEST SWAP1 MSTORE SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH2 0x995 PUSH2 0x9D0 JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x80 ADD PUSH1 0x40 MSTORE DUP1 PUSH2 0x9B5 PUSH2 0xA11 JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x80 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH4 0xFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x20 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0xA42 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xA58 JUMPI DUP2 DUP3 REVERT JUMPDEST PUSH1 0x20 PUSH2 0xA67 DUP2 DUP3 DUP5 MUL ADD PUSH2 0x1306 JUMP JUMPDEST DUP3 DUP2 MSTORE SWAP3 POP DUP1 DUP4 ADD DUP5 DUP3 ADD PUSH1 0x0 JUMPDEST DUP5 DUP2 LT ISZERO PUSH2 0xA9E JUMPI PUSH2 0xA8C DUP9 DUP6 DUP5 CALLDATALOAD DUP11 ADD ADD PUSH2 0xAA9 JUMP JUMPDEST DUP4 MSTORE SWAP2 DUP4 ADD SWAP2 SWAP1 DUP4 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0xA75 JUMP JUMPDEST POP POP POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0xAB9 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xACF JUMPI DUP2 DUP3 REVERT JUMPDEST PUSH2 0xB00 PUSH1 0x20 PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 PUSH1 0x1F DUP5 ADD AND ADD PUSH2 0x1306 JUMP JUMPDEST SWAP2 POP DUP1 DUP3 MSTORE DUP4 PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0xB17 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH1 0x20 DUP5 ADD PUSH1 0x20 DUP5 ADD CALLDATACOPY PUSH1 0x0 SWAP1 DUP3 ADD PUSH1 0x20 ADD MSTORE SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x80 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xB41 JUMPI DUP1 DUP2 REVERT JUMPDEST PUSH2 0xB4B PUSH1 0x80 PUSH2 0x1306 JUMP JUMPDEST SWAP1 POP PUSH1 0x0 DUP3 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0xB66 JUMPI DUP3 DUP4 REVERT JUMPDEST PUSH2 0xB72 DUP7 DUP4 DUP8 ADD PUSH2 0xAA9 JUMP JUMPDEST DUP5 MSTORE PUSH1 0x20 DUP6 ADD CALLDATALOAD SWAP2 POP PUSH4 0xFFFFFFFF DUP3 AND DUP3 EQ PUSH2 0xB8C JUMPI DUP3 DUP4 REVERT JUMPDEST DUP2 PUSH1 0x20 DUP6 ADD MSTORE PUSH1 0x40 DUP6 ADD CALLDATALOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0xBA5 JUMPI DUP3 DUP4 REVERT JUMPDEST PUSH2 0xBB1 DUP7 DUP4 DUP8 ADD PUSH2 0xA32 JUMP JUMPDEST PUSH1 0x40 DUP6 ADD MSTORE PUSH1 0x60 DUP6 ADD CALLDATALOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0xBC9 JUMPI DUP3 DUP4 REVERT JUMPDEST POP PUSH2 0xBD6 DUP6 DUP3 DUP7 ADD PUSH2 0xAA9 JUMP JUMPDEST PUSH1 0x60 DUP5 ADD MSTORE POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x0 PUSH1 0xA0 DUP7 DUP9 SUB SLT ISZERO PUSH2 0xBFB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP6 CALLDATALOAD PUSH2 0xC06 DUP2 PUSH2 0x135D JUMP JUMPDEST SWAP5 POP PUSH1 0x20 DUP7 ADD CALLDATALOAD SWAP4 POP PUSH1 0x40 DUP7 ADD CALLDATALOAD SWAP3 POP PUSH1 0x60 DUP7 ADD CALLDATALOAD PUSH2 0xC24 DUP2 PUSH2 0x135D JUMP JUMPDEST SWAP5 SWAP8 SWAP4 SWAP7 POP SWAP2 SWAP5 PUSH1 0x80 ADD CALLDATALOAD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xC47 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xC5E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xC6A DUP5 DUP3 DUP6 ADD PUSH2 0xA32 JUMP JUMPDEST SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x80 DUP6 DUP8 SUB SLT ISZERO PUSH2 0xC88 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP5 CALLDATALOAD SWAP4 POP PUSH1 0x20 DUP6 ADD CALLDATALOAD PUSH1 0xFF DUP2 AND DUP2 EQ PUSH2 0xCA0 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP7 SWAP4 SWAP6 POP POP POP POP PUSH1 0x40 DUP3 ADD CALLDATALOAD SWAP2 PUSH1 0x60 ADD CALLDATALOAD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xCC7 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xCDE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xC6A DUP5 DUP3 DUP6 ADD PUSH2 0xAA9 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xCFC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xD14 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0xD2B JUMPI DUP3 DUP4 REVERT JUMPDEST DUP2 DUP5 ADD PUSH1 0x60 DUP2 DUP8 SUB SLT ISZERO PUSH2 0xD3D JUMPI DUP4 DUP5 REVERT JUMPDEST PUSH2 0xD47 PUSH1 0x60 PUSH2 0x1306 JUMP JUMPDEST SWAP3 POP DUP1 CALLDATALOAD DUP4 MSTORE PUSH1 0x20 DUP2 ADD CALLDATALOAD DUP3 DUP2 GT ISZERO PUSH2 0xD5E JUMPI DUP5 DUP6 REVERT JUMPDEST PUSH2 0xD6A DUP8 DUP3 DUP5 ADD PUSH2 0xAA9 JUMP JUMPDEST PUSH1 0x20 DUP6 ADD MSTORE POP PUSH1 0x40 DUP2 ADD CALLDATALOAD DUP3 DUP2 GT ISZERO PUSH2 0xD81 JUMPI DUP5 DUP6 REVERT JUMPDEST PUSH2 0xD8D DUP8 DUP3 DUP5 ADD PUSH2 0xAA9 JUMP JUMPDEST PUSH1 0x40 DUP6 ADD MSTORE POP SWAP2 SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xDAE JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0xDC5 JUMPI DUP3 DUP4 REVERT JUMPDEST DUP2 DUP5 ADD PUSH1 0x40 DUP2 DUP8 SUB SLT ISZERO PUSH2 0xDD7 JUMPI DUP4 DUP5 REVERT JUMPDEST PUSH2 0xDE1 PUSH1 0x40 PUSH2 0x1306 JUMP JUMPDEST SWAP3 POP DUP1 CALLDATALOAD DUP3 DUP2 GT ISZERO PUSH2 0xDF1 JUMPI DUP5 DUP6 REVERT JUMPDEST PUSH2 0xDFD DUP8 DUP3 DUP5 ADD PUSH2 0xB30 JUMP JUMPDEST DUP5 MSTORE POP PUSH1 0x20 DUP2 ADD CALLDATALOAD DUP3 DUP2 GT ISZERO PUSH2 0xE11 JUMPI DUP5 DUP6 REVERT JUMPDEST PUSH2 0xE1D DUP8 DUP3 DUP5 ADD PUSH2 0xAA9 JUMP JUMPDEST PUSH1 0x20 DUP6 ADD MSTORE POP SWAP2 SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xE3F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xE56 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xC6A DUP5 DUP3 DUP6 ADD PUSH2 0xB30 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 PUSH1 0x60 DUP5 DUP7 SUB SLT ISZERO PUSH2 0xE76 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP4 CALLDATALOAD SWAP3 POP PUSH1 0x20 DUP5 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0xE94 JUMPI DUP3 DUP4 REVERT JUMPDEST PUSH2 0xEA0 DUP8 DUP4 DUP9 ADD PUSH2 0xAA9 JUMP JUMPDEST SWAP4 POP PUSH1 0x40 DUP7 ADD CALLDATALOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0xEB5 JUMPI DUP3 DUP4 REVERT JUMPDEST POP PUSH2 0xEC2 DUP7 DUP3 DUP8 ADD PUSH2 0xAA9 JUMP JUMPDEST SWAP2 POP POP SWAP3 POP SWAP3 POP SWAP3 JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD DUP1 DUP5 MSTORE PUSH2 0xEE4 DUP2 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP7 ADD PUSH2 0x132D JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x20 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD PUSH1 0x80 DUP5 MSTORE PUSH2 0xF2B PUSH1 0x80 DUP6 ADD DUP3 PUSH2 0xECC JUMP JUMPDEST PUSH1 0x20 SWAP2 POP PUSH4 0xFFFFFFFF DUP3 DUP6 ADD MLOAD AND DUP3 DUP7 ADD MSTORE PUSH1 0x40 DUP5 ADD MLOAD DUP6 DUP3 SUB PUSH1 0x40 DUP8 ADD MSTORE DUP2 DUP2 MLOAD DUP1 DUP5 MSTORE DUP5 DUP5 ADD SWAP2 POP DUP5 DUP6 DUP3 MUL DUP6 ADD ADD DUP6 DUP5 ADD PUSH1 0x0 SWAP5 POP JUMPDEST DUP3 DUP6 LT ISZERO PUSH2 0xFB2 JUMPI PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 DUP7 DUP4 SUB ADD DUP5 MSTORE PUSH2 0xF9E DUP3 DUP3 MLOAD PUSH2 0xECC JUMP JUMPDEST PUSH1 0x1 SWAP6 SWAP1 SWAP6 ADD SWAP5 SWAP4 DUP8 ADD SWAP4 SWAP2 POP DUP7 ADD PUSH2 0xF64 JUMP JUMPDEST POP PUSH1 0x60 DUP9 ADD MLOAD SWAP6 POP DUP9 DUP2 SUB PUSH1 0x60 DUP11 ADD MSTORE PUSH2 0xFCC DUP2 DUP8 PUSH2 0xECC JUMP JUMPDEST SWAP10 SWAP9 POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP4 MLOAD PUSH2 0xFEB DUP2 DUP5 PUSH1 0x20 DUP9 ADD PUSH2 0x132D JUMP JUMPDEST SWAP2 SWAP1 SWAP2 ADD SWAP2 DUP3 MSTORE POP PUSH1 0x20 ADD SWAP2 SWAP1 POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP2 SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 ADD DUP2 DUP5 MSTORE DUP1 DUP6 MLOAD DUP1 DUP4 MSTORE PUSH1 0x40 DUP7 ADD SWAP2 POP PUSH1 0x40 DUP5 DUP3 MUL DUP8 ADD ADD SWAP3 POP DUP4 DUP8 ADD PUSH1 0x0 JUMPDEST DUP3 DUP2 LT ISZERO PUSH2 0x108E JUMPI PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 DUP9 DUP7 SUB ADD DUP5 MSTORE PUSH2 0x107C DUP6 DUP4 MLOAD PUSH2 0xF16 JUMP JUMPDEST SWAP5 POP SWAP3 DUP6 ADD SWAP3 SWAP1 DUP6 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x1042 JUMP JUMPDEST POP SWAP3 SWAP8 SWAP7 POP POP POP POP POP POP POP JUMP JUMPDEST SWAP4 DUP5 MSTORE PUSH1 0xFF SWAP3 SWAP1 SWAP3 AND PUSH1 0x20 DUP5 ADD MSTORE PUSH1 0x40 DUP4 ADD MSTORE PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x60 DUP3 MSTORE PUSH2 0x10CC PUSH1 0x60 DUP4 ADD DUP7 PUSH2 0xECC JUMP JUMPDEST DUP3 DUP2 SUB PUSH1 0x20 DUP5 ADD MSTORE PUSH2 0x10DE DUP2 DUP7 PUSH2 0xECC JUMP JUMPDEST DUP4 DUP2 SUB PUSH1 0x40 DUP6 ADD MSTORE PUSH2 0x10F0 DUP2 DUP7 PUSH2 0xECC JUMP JUMPDEST SWAP8 SWAP7 POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 MSTORE PUSH2 0x110E PUSH1 0x20 DUP4 ADD DUP5 PUSH2 0xECC JUMP JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0xD SWAP1 DUP3 ADD MSTORE PUSH32 0x53494D504C455F52455645525400000000000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0xE SWAP1 DUP3 ADD MSTORE PUSH32 0x53494D504C455F52455155495245000000000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 MSTORE DUP3 MLOAD PUSH1 0x80 PUSH1 0x20 DUP5 ADD MSTORE DUP1 MLOAD PUSH1 0xA0 DUP5 ADD MSTORE PUSH1 0x20 DUP2 ADD MLOAD PUSH1 0x60 PUSH1 0xC0 DUP6 ADD MSTORE PUSH2 0x11B3 PUSH2 0x100 DUP6 ADD DUP3 PUSH2 0xECC JUMP JUMPDEST PUSH1 0x40 DUP4 ADD MLOAD SWAP2 POP PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60 DUP6 DUP3 SUB ADD PUSH1 0xE0 DUP7 ADD MSTORE PUSH2 0x11EE DUP2 DUP4 PUSH2 0xECC JUMP JUMPDEST SWAP3 POP POP POP PUSH1 0x20 DUP5 ADD MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 DUP1 DUP6 DUP5 SUB ADD PUSH1 0x40 DUP7 ADD MSTORE PUSH2 0x122C DUP4 DUP4 PUSH2 0xECC JUMP JUMPDEST PUSH1 0x40 DUP8 ADD MLOAD SWAP4 POP DUP2 DUP7 DUP3 SUB ADD PUSH1 0x60 DUP8 ADD MSTORE PUSH2 0x1247 DUP2 DUP6 PUSH2 0xECC JUMP JUMPDEST SWAP3 POP POP PUSH1 0x60 DUP7 ADD MLOAD SWAP3 POP DUP1 DUP6 DUP4 SUB ADD PUSH1 0x80 DUP7 ADD MSTORE POP PUSH2 0x1266 DUP2 DUP4 PUSH2 0xECC JUMP JUMPDEST SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST SWAP1 MLOAD MLOAD DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 MSTORE DUP3 MLOAD PUSH1 0x40 PUSH1 0x20 DUP5 ADD MSTORE PUSH2 0x1296 PUSH1 0x60 DUP5 ADD DUP3 PUSH2 0xF16 JUMP JUMPDEST PUSH1 0x20 DUP6 ADD MLOAD SWAP2 POP PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 DUP5 DUP3 SUB ADD PUSH1 0x40 DUP6 ADD MSTORE PUSH2 0x1266 DUP2 DUP4 PUSH2 0xECC JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 MSTORE PUSH2 0x110E PUSH1 0x20 DUP4 ADD DUP5 PUSH2 0xF16 JUMP JUMPDEST SWAP1 DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP4 DUP3 MSTORE PUSH1 0x40 PUSH1 0x20 DUP4 ADD MSTORE PUSH2 0xC6A PUSH1 0x40 DUP4 ADD DUP5 PUSH2 0xECC JUMP JUMPDEST PUSH1 0x40 MLOAD DUP2 DUP2 ADD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT DUP3 DUP3 LT OR ISZERO PUSH2 0x1325 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x40 MSTORE SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1348 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x1330 JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0x1357 JUMPI PUSH1 0x0 DUP5 DUP5 ADD MSTORE JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND DUP2 EQ PUSH2 0x3EE JUMPI PUSH1 0x0 DUP1 REVERT INVALID LOG3 PUSH6 0x627A7A723158 KECCAK256 BALANCE PUSH21 0x67B7D0F0E7D2D63822DB9997196E2E42B127BD2B1D 0xd9 0xc0 0x28 JUMP 0xa6 CREATE2 0xb5 SWAP2 DUP5 PUSH13 0x6578706572696D656E74616CF5 PUSH5 0x736F6C6343 STOP SDIV SIGNEXTEND STOP BLOCKHASH ", + "sourceMap": "641:6596:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;641:6596:0;;;;;;;" }, "deployedBytecode": { "linkReferences": {}, - "object": "0x608060405234801561001057600080fd5b506004361061011a5760003560e01c806363d69c88116100b25780639a3b618511610081578063ae2dae1711610066578063ae2dae17146101f9578063d6d7618c14610207578063d88be12f1461021c5761011a565b80639a3b6185146101e9578063a3c2f6b6146101f15761011a565b806363d69c88146101a0578063647341eb146101b357806376f15d5b146101c15780638ee52b4e146101d65761011a565b80634582eab2116100ee5780634582eab21461017357806345fdbdb71461017b57806359c28add146101835780635ba3c7c0146101985761011a565b806209e4371461011f5780630527c28f1461012957806336b323961461013c5780633e9ef66a14610165575b600080fd5b610127610224565b005b6101276101373660046106d7565b61025f565b61014f61014a366004610714565b610262565b60405161015c9190610999565b60405180910390f35b610127610137366004610757565b610127610344565b6101276103a9565b61018b6103db565b60405161015c9190610a60565b6101276103e6565b61014f6101ae366004610685565b61044b565b61012761013736600461081c565b6101c9610454565b60405161015c9190610ad3565b6101c96101e4366004610851565b610462565b610127610468565b6101c9610473565b61012761013736600461078c565b61020f610478565b60405161015c9190610ac0565b6101c9610480565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161025690610a29565b60405180910390fd5b50565b600060606040518060400160405280601c81526020017f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152509050600081876040516020016102b3929190610977565b604051602081830303815290604052805190602001209050600181878787604051600081526020016040526040516102ee94939291906109ba565b6020604051602081039080840390855afa158015610310573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015198975050505050505050565b604080518082018252601481527f5245564552545f574954485f434f4e5354414e54000000000000000000000000602082015290517f08c379a000000000000000000000000000000000000000000000000000000000815261025691906004016109d8565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610256906109f2565b6103e3610486565b90565b604080518082018252601581527f524551554952455f574954485f434f4e5354414e540000000000000000000000602082015290517f08c379a000000000000000000000000000000000000000000000000000000000815261025691906004016109d8565b50929392505050565b600080546001019081905590565b60010190565b600080546001019055565b600190565b6103e36104a6565b6104d290565b6040518060a001604052806104996104a6565b8152602001606081525090565b604051806080016040528060608152602001600063ffffffff16815260200160608152602001606081525090565b600082601f8301126104e4578081fd5b813567ffffffffffffffff8111156104fa578182fd5b60206105098182840201610adc565b828152925080830184820160005b848110156105405761052e888584358a010161054b565b83529183019190830190600101610517565b505050505092915050565b600082601f83011261055b578081fd5b813567ffffffffffffffff811115610571578182fd5b6105a260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610adc565b91508082528360208285010111156105b957600080fd5b8060208401602084013760009082016020015292915050565b6000608082840312156105e3578081fd5b6105ed6080610adc565b90506000823567ffffffffffffffff80821115610608578283fd5b6106148683870161054b565b84526020850135915063ffffffff8216821461062e578283fd5b8160208501526040850135915080821115610647578283fd5b610653868387016104d4565b6040850152606085013591508082111561066b578283fd5b506106788582860161054b565b6060840152505092915050565b600080600080600060a0868803121561069d57600080fd5b85356106a881610b33565b9450602086013593506040860135925060608601356106c681610b33565b949793965091946080013592915050565b6000602082840312156106e957600080fd5b813567ffffffffffffffff81111561070057600080fd5b61070c848285016104d4565b949350505050565b6000806000806080858703121561072a57600080fd5b84359350602085013560ff8116811461074257600080fd5b93969395505050506040820135916060013590565b60006020828403121561076957600080fd5b813567ffffffffffffffff81111561078057600080fd5b61070c8482850161054b565b60006020828403121561079d578081fd5b813567ffffffffffffffff808211156107b4578283fd5b818401604081870312156107c6578384fd5b6107d06040610adc565b92508035828111156107e0578485fd5b6107ec878284016105d2565b845250602081013582811115610800578485fd5b61080c8782840161054b565b6020850152509195945050505050565b60006020828403121561082e57600080fd5b813567ffffffffffffffff81111561084557600080fd5b61070c848285016105d2565b60006020828403121561086357600080fd5b5035919050565b60008151808452610882816020860160208601610b03565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60008151608084526108c9608085018261086a565b6020915063ffffffff82850151168286015260408401518582036040870152818151808452848401915084858202850101858401600094505b82851015610950577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086830301845261093c82825161086a565b600195909501949387019391508601610902565b506060880151955088810360608a015261096a818761086a565b9998505050505050505050565b60008351610989818460208801610b03565b9190910191825250602001919050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b93845260ff9290921660208401526040830152606082015260800190565b6000602082526109eb602083018461086a565b9392505050565b6020808252600d908201527f53494d504c455f52455645525400000000000000000000000000000000000000604082015260600190565b6020808252600e908201527f53494d504c455f52455155495245000000000000000000000000000000000000604082015260600190565b600060208252825160406020840152610a7c60608401826108b4565b602085015191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0848203016040850152610ab7818361086a565b95945050505050565b6000602082526109eb60208301846108b4565b90815260200190565b60405181810167ffffffffffffffff81118282101715610afb57600080fd5b604052919050565b60005b83811015610b1e578181015183820152602001610b06565b83811115610b2d576000848401525b50505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461025f57600080fdfea365627a7a72305820888f51db8be2b65eeba07b18b43cdc6dad5d8e6807eb4aa7f11e06f111742aef6c6578706572696d656e74616cf564736f6c634300050a0040", - "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x11A JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x63D69C88 GT PUSH2 0xB2 JUMPI DUP1 PUSH4 0x9A3B6185 GT PUSH2 0x81 JUMPI DUP1 PUSH4 0xAE2DAE17 GT PUSH2 0x66 JUMPI DUP1 PUSH4 0xAE2DAE17 EQ PUSH2 0x1F9 JUMPI DUP1 PUSH4 0xD6D7618C EQ PUSH2 0x207 JUMPI DUP1 PUSH4 0xD88BE12F EQ PUSH2 0x21C JUMPI PUSH2 0x11A JUMP JUMPDEST DUP1 PUSH4 0x9A3B6185 EQ PUSH2 0x1E9 JUMPI DUP1 PUSH4 0xA3C2F6B6 EQ PUSH2 0x1F1 JUMPI PUSH2 0x11A JUMP JUMPDEST DUP1 PUSH4 0x63D69C88 EQ PUSH2 0x1A0 JUMPI DUP1 PUSH4 0x647341EB EQ PUSH2 0x1B3 JUMPI DUP1 PUSH4 0x76F15D5B EQ PUSH2 0x1C1 JUMPI DUP1 PUSH4 0x8EE52B4E EQ PUSH2 0x1D6 JUMPI PUSH2 0x11A JUMP JUMPDEST DUP1 PUSH4 0x4582EAB2 GT PUSH2 0xEE JUMPI DUP1 PUSH4 0x4582EAB2 EQ PUSH2 0x173 JUMPI DUP1 PUSH4 0x45FDBDB7 EQ PUSH2 0x17B JUMPI DUP1 PUSH4 0x59C28ADD EQ PUSH2 0x183 JUMPI DUP1 PUSH4 0x5BA3C7C0 EQ PUSH2 0x198 JUMPI PUSH2 0x11A JUMP JUMPDEST DUP1 PUSH3 0x9E437 EQ PUSH2 0x11F JUMPI DUP1 PUSH4 0x527C28F EQ PUSH2 0x129 JUMPI DUP1 PUSH4 0x36B32396 EQ PUSH2 0x13C JUMPI DUP1 PUSH4 0x3E9EF66A EQ PUSH2 0x165 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x127 PUSH2 0x224 JUMP JUMPDEST STOP JUMPDEST PUSH2 0x127 PUSH2 0x137 CALLDATASIZE PUSH1 0x4 PUSH2 0x6D7 JUMP JUMPDEST PUSH2 0x25F JUMP JUMPDEST PUSH2 0x14F PUSH2 0x14A CALLDATASIZE PUSH1 0x4 PUSH2 0x714 JUMP JUMPDEST PUSH2 0x262 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x15C SWAP2 SWAP1 PUSH2 0x999 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x127 PUSH2 0x137 CALLDATASIZE PUSH1 0x4 PUSH2 0x757 JUMP JUMPDEST PUSH2 0x127 PUSH2 0x344 JUMP JUMPDEST PUSH2 0x127 PUSH2 0x3A9 JUMP JUMPDEST PUSH2 0x18B PUSH2 0x3DB JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x15C SWAP2 SWAP1 PUSH2 0xA60 JUMP JUMPDEST PUSH2 0x127 PUSH2 0x3E6 JUMP JUMPDEST PUSH2 0x14F PUSH2 0x1AE CALLDATASIZE PUSH1 0x4 PUSH2 0x685 JUMP JUMPDEST PUSH2 0x44B JUMP JUMPDEST PUSH2 0x127 PUSH2 0x137 CALLDATASIZE PUSH1 0x4 PUSH2 0x81C JUMP JUMPDEST PUSH2 0x1C9 PUSH2 0x454 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x15C SWAP2 SWAP1 PUSH2 0xAD3 JUMP JUMPDEST PUSH2 0x1C9 PUSH2 0x1E4 CALLDATASIZE PUSH1 0x4 PUSH2 0x851 JUMP JUMPDEST PUSH2 0x462 JUMP JUMPDEST PUSH2 0x127 PUSH2 0x468 JUMP JUMPDEST PUSH2 0x1C9 PUSH2 0x473 JUMP JUMPDEST PUSH2 0x127 PUSH2 0x137 CALLDATASIZE PUSH1 0x4 PUSH2 0x78C JUMP JUMPDEST PUSH2 0x20F PUSH2 0x478 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x15C SWAP2 SWAP1 PUSH2 0xAC0 JUMP JUMPDEST PUSH2 0x1C9 PUSH2 0x480 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x256 SWAP1 PUSH2 0xA29 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x60 PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x1C DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x19457468657265756D205369676E6564204D6573736167653A0A333200000000 DUP2 MSTORE POP SWAP1 POP PUSH1 0x0 DUP2 DUP8 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x2B3 SWAP3 SWAP2 SWAP1 PUSH2 0x977 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 SWAP1 POP PUSH1 0x1 DUP2 DUP8 DUP8 DUP8 PUSH1 0x40 MLOAD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD PUSH2 0x2EE SWAP5 SWAP4 SWAP3 SWAP2 SWAP1 PUSH2 0x9BA JUMP JUMPDEST PUSH1 0x20 PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 SUB SWAP1 DUP1 DUP5 SUB SWAP1 DUP6 GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x310 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP PUSH1 0x40 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 ADD MLOAD SWAP9 SWAP8 POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD DUP3 MSTORE PUSH1 0x14 DUP2 MSTORE PUSH32 0x5245564552545F574954485F434F4E5354414E54000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE SWAP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH2 0x256 SWAP2 SWAP1 PUSH1 0x4 ADD PUSH2 0x9D8 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x256 SWAP1 PUSH2 0x9F2 JUMP JUMPDEST PUSH2 0x3E3 PUSH2 0x486 JUMP JUMPDEST SWAP1 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD DUP3 MSTORE PUSH1 0x15 DUP2 MSTORE PUSH32 0x524551554952455F574954485F434F4E5354414E540000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE SWAP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH2 0x256 SWAP2 SWAP1 PUSH1 0x4 ADD PUSH2 0x9D8 JUMP JUMPDEST POP SWAP3 SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 ADD SWAP1 DUP2 SWAP1 SSTORE SWAP1 JUMP JUMPDEST PUSH1 0x1 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 ADD SWAP1 SSTORE JUMP JUMPDEST PUSH1 0x1 SWAP1 JUMP JUMPDEST PUSH2 0x3E3 PUSH2 0x4A6 JUMP JUMPDEST PUSH2 0x4D2 SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0xA0 ADD PUSH1 0x40 MSTORE DUP1 PUSH2 0x499 PUSH2 0x4A6 JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x80 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH4 0xFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x4E4 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x4FA JUMPI DUP2 DUP3 REVERT JUMPDEST PUSH1 0x20 PUSH2 0x509 DUP2 DUP3 DUP5 MUL ADD PUSH2 0xADC JUMP JUMPDEST DUP3 DUP2 MSTORE SWAP3 POP DUP1 DUP4 ADD DUP5 DUP3 ADD PUSH1 0x0 JUMPDEST DUP5 DUP2 LT ISZERO PUSH2 0x540 JUMPI PUSH2 0x52E DUP9 DUP6 DUP5 CALLDATALOAD DUP11 ADD ADD PUSH2 0x54B JUMP JUMPDEST DUP4 MSTORE SWAP2 DUP4 ADD SWAP2 SWAP1 DUP4 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x517 JUMP JUMPDEST POP POP POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0x55B JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x571 JUMPI DUP2 DUP3 REVERT JUMPDEST PUSH2 0x5A2 PUSH1 0x20 PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 PUSH1 0x1F DUP5 ADD AND ADD PUSH2 0xADC JUMP JUMPDEST SWAP2 POP DUP1 DUP3 MSTORE DUP4 PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0x5B9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH1 0x20 DUP5 ADD PUSH1 0x20 DUP5 ADD CALLDATACOPY PUSH1 0x0 SWAP1 DUP3 ADD PUSH1 0x20 ADD MSTORE SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x80 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x5E3 JUMPI DUP1 DUP2 REVERT JUMPDEST PUSH2 0x5ED PUSH1 0x80 PUSH2 0xADC JUMP JUMPDEST SWAP1 POP PUSH1 0x0 DUP3 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x608 JUMPI DUP3 DUP4 REVERT JUMPDEST PUSH2 0x614 DUP7 DUP4 DUP8 ADD PUSH2 0x54B JUMP JUMPDEST DUP5 MSTORE PUSH1 0x20 DUP6 ADD CALLDATALOAD SWAP2 POP PUSH4 0xFFFFFFFF DUP3 AND DUP3 EQ PUSH2 0x62E JUMPI DUP3 DUP4 REVERT JUMPDEST DUP2 PUSH1 0x20 DUP6 ADD MSTORE PUSH1 0x40 DUP6 ADD CALLDATALOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x647 JUMPI DUP3 DUP4 REVERT JUMPDEST PUSH2 0x653 DUP7 DUP4 DUP8 ADD PUSH2 0x4D4 JUMP JUMPDEST PUSH1 0x40 DUP6 ADD MSTORE PUSH1 0x60 DUP6 ADD CALLDATALOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0x66B JUMPI DUP3 DUP4 REVERT JUMPDEST POP PUSH2 0x678 DUP6 DUP3 DUP7 ADD PUSH2 0x54B JUMP JUMPDEST PUSH1 0x60 DUP5 ADD MSTORE POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x0 PUSH1 0xA0 DUP7 DUP9 SUB SLT ISZERO PUSH2 0x69D JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP6 CALLDATALOAD PUSH2 0x6A8 DUP2 PUSH2 0xB33 JUMP JUMPDEST SWAP5 POP PUSH1 0x20 DUP7 ADD CALLDATALOAD SWAP4 POP PUSH1 0x40 DUP7 ADD CALLDATALOAD SWAP3 POP PUSH1 0x60 DUP7 ADD CALLDATALOAD PUSH2 0x6C6 DUP2 PUSH2 0xB33 JUMP JUMPDEST SWAP5 SWAP8 SWAP4 SWAP7 POP SWAP2 SWAP5 PUSH1 0x80 ADD CALLDATALOAD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x6E9 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x700 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x70C DUP5 DUP3 DUP6 ADD PUSH2 0x4D4 JUMP JUMPDEST SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x80 DUP6 DUP8 SUB SLT ISZERO PUSH2 0x72A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP5 CALLDATALOAD SWAP4 POP PUSH1 0x20 DUP6 ADD CALLDATALOAD PUSH1 0xFF DUP2 AND DUP2 EQ PUSH2 0x742 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP7 SWAP4 SWAP6 POP POP POP POP PUSH1 0x40 DUP3 ADD CALLDATALOAD SWAP2 PUSH1 0x60 ADD CALLDATALOAD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x769 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x780 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x70C DUP5 DUP3 DUP6 ADD PUSH2 0x54B JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x79D JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0x7B4 JUMPI DUP3 DUP4 REVERT JUMPDEST DUP2 DUP5 ADD PUSH1 0x40 DUP2 DUP8 SUB SLT ISZERO PUSH2 0x7C6 JUMPI DUP4 DUP5 REVERT JUMPDEST PUSH2 0x7D0 PUSH1 0x40 PUSH2 0xADC JUMP JUMPDEST SWAP3 POP DUP1 CALLDATALOAD DUP3 DUP2 GT ISZERO PUSH2 0x7E0 JUMPI DUP5 DUP6 REVERT JUMPDEST PUSH2 0x7EC DUP8 DUP3 DUP5 ADD PUSH2 0x5D2 JUMP JUMPDEST DUP5 MSTORE POP PUSH1 0x20 DUP2 ADD CALLDATALOAD DUP3 DUP2 GT ISZERO PUSH2 0x800 JUMPI DUP5 DUP6 REVERT JUMPDEST PUSH2 0x80C DUP8 DUP3 DUP5 ADD PUSH2 0x54B JUMP JUMPDEST PUSH1 0x20 DUP6 ADD MSTORE POP SWAP2 SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x82E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x845 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x70C DUP5 DUP3 DUP6 ADD PUSH2 0x5D2 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x863 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD DUP1 DUP5 MSTORE PUSH2 0x882 DUP2 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP7 ADD PUSH2 0xB03 JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x20 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD PUSH1 0x80 DUP5 MSTORE PUSH2 0x8C9 PUSH1 0x80 DUP6 ADD DUP3 PUSH2 0x86A JUMP JUMPDEST PUSH1 0x20 SWAP2 POP PUSH4 0xFFFFFFFF DUP3 DUP6 ADD MLOAD AND DUP3 DUP7 ADD MSTORE PUSH1 0x40 DUP5 ADD MLOAD DUP6 DUP3 SUB PUSH1 0x40 DUP8 ADD MSTORE DUP2 DUP2 MLOAD DUP1 DUP5 MSTORE DUP5 DUP5 ADD SWAP2 POP DUP5 DUP6 DUP3 MUL DUP6 ADD ADD DUP6 DUP5 ADD PUSH1 0x0 SWAP5 POP JUMPDEST DUP3 DUP6 LT ISZERO PUSH2 0x950 JUMPI PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 DUP7 DUP4 SUB ADD DUP5 MSTORE PUSH2 0x93C DUP3 DUP3 MLOAD PUSH2 0x86A JUMP JUMPDEST PUSH1 0x1 SWAP6 SWAP1 SWAP6 ADD SWAP5 SWAP4 DUP8 ADD SWAP4 SWAP2 POP DUP7 ADD PUSH2 0x902 JUMP JUMPDEST POP PUSH1 0x60 DUP9 ADD MLOAD SWAP6 POP DUP9 DUP2 SUB PUSH1 0x60 DUP11 ADD MSTORE PUSH2 0x96A DUP2 DUP8 PUSH2 0x86A JUMP JUMPDEST SWAP10 SWAP9 POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP4 MLOAD PUSH2 0x989 DUP2 DUP5 PUSH1 0x20 DUP9 ADD PUSH2 0xB03 JUMP JUMPDEST SWAP2 SWAP1 SWAP2 ADD SWAP2 DUP3 MSTORE POP PUSH1 0x20 ADD SWAP2 SWAP1 POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP2 SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST SWAP4 DUP5 MSTORE PUSH1 0xFF SWAP3 SWAP1 SWAP3 AND PUSH1 0x20 DUP5 ADD MSTORE PUSH1 0x40 DUP4 ADD MSTORE PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 MSTORE PUSH2 0x9EB PUSH1 0x20 DUP4 ADD DUP5 PUSH2 0x86A JUMP JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0xD SWAP1 DUP3 ADD MSTORE PUSH32 0x53494D504C455F52455645525400000000000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0xE SWAP1 DUP3 ADD MSTORE PUSH32 0x53494D504C455F52455155495245000000000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 MSTORE DUP3 MLOAD PUSH1 0x40 PUSH1 0x20 DUP5 ADD MSTORE PUSH2 0xA7C PUSH1 0x60 DUP5 ADD DUP3 PUSH2 0x8B4 JUMP JUMPDEST PUSH1 0x20 DUP6 ADD MLOAD SWAP2 POP PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 DUP5 DUP3 SUB ADD PUSH1 0x40 DUP6 ADD MSTORE PUSH2 0xAB7 DUP2 DUP4 PUSH2 0x86A JUMP JUMPDEST SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 MSTORE PUSH2 0x9EB PUSH1 0x20 DUP4 ADD DUP5 PUSH2 0x8B4 JUMP JUMPDEST SWAP1 DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP2 DUP2 ADD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT DUP3 DUP3 LT OR ISZERO PUSH2 0xAFB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x40 MSTORE SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0xB1E JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0xB06 JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0xB2D JUMPI PUSH1 0x0 DUP5 DUP5 ADD MSTORE JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND DUP2 EQ PUSH2 0x25F JUMPI PUSH1 0x0 DUP1 REVERT INVALID LOG3 PUSH6 0x627A7A723058 KECCAK256 DUP9 DUP16 MLOAD 0xdb DUP12 0xe2 0xb6 0x5e 0xeb LOG0 PUSH28 0x18B43CDC6DAD5D8E6807EB4AA7F11E06F111742AEF6C657870657269 PUSH14 0x656E74616CF564736F6C63430005 EXP STOP BLOCKHASH ", - "sourceMap": "641:2757:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;641:2757:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1496:107;;;:::i;:::-;;2581:63;;;;;;;;;:::i;1726:334::-;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;2419:52;;;;;;;1389:101;;;:::i;1286:97::-;;;:::i;3151:73::-;;;:::i;:::-;;;;;;;;1609:111;;;:::i;2214:166::-;;;;;;;;;:::i;2790:52::-;;;;;;;3250:72;;;:::i;:::-;;;;;;;;989:140;;;;;;;;;:::i;3327:69::-;;;:::i;862:121::-;;;:::i;3082:64::-;;;;;;;2924:63;;;:::i;:::-;;;;;;;;1135:145;;;:::i;1496:107::-;1564:32;;;;;;;;;;;;;;;;;;;2581:63;;:::o;1726:334::-;1837:21;1874:19;:56;;;;;;;;;;;;;;;;;;;1940:20;1990:6;1998:4;1973:30;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;1973:30:0;;;1963:41;;;;;;1940:64;;2021:32;2031:12;2045:1;2048;2051;2021:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;2021:32:0;;;;;;1726:334;-1:-1:-1;;;;;;;;1726:334:0:o;1389:101::-;1469:13;;;;;;;;;;;;;;;;1462:21;;;;;;;1469:13;1462:21;;;;1286:97;1353:23;;;;;;;;;;;3151:73;3201:19;;:::i;:::-;3151:73;:::o;1609:111::-;1698:14;;;;;;;;;;;;;;;;1683:30;;;;;;;1698:14;1683:30;;;;2214:166;-1:-1:-1;2372:1:0;;2214:166;-1:-1:-1;;;2214:166:0:o;3250:72::-;3290:4;3305:14;;3318:1;3305:14;;;;;3250:72;:::o;989:140::-;1117:1;:5;;989:140::o;3327:69::-;3379:9;:14;;3392:1;3379:14;;;3327:69::o;862:121::-;975:1;862:121;:::o;2924:63::-;2968:15;;:::i;1135:145::-;711:4;1135:145;:::o;641:2757::-;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;158:685:-1:-;;276:3;269:4;261:6;257:17;253:27;243:2;;-1:-1;;284:12;243:2;331:6;318:20;20177:18;20169:6;20166:30;20163:2;;;-1:-1;;20199:12;20163:2;20244:4;353:81;20307:4;20244;20236:6;20232:17;20297:15;353:81;;;462:21;;;344:90;-1:-1;519:14;;;494:17;;;614:1;599:238;624:6;621:1;618:13;599:238;;;731:42;769:3;506:4;707:3;694:17;498:6;682:30;;731:42;;;719:55;;788:14;;;;816;;;;646:1;639:9;599:238;;;603:14;;;;;236:607;;;;;1706:432;;1803:3;1796:4;1788:6;1784:17;1780:27;1770:2;;-1:-1;;1811:12;1770:2;1858:6;1845:20;20784:18;20776:6;20773:30;20770:2;;;-1:-1;;20806:12;20770:2;1880:60;20947:4;20879:9;1796:4;20864:6;20860:17;20856:33;20937:15;1880:60;;;1871:69;;1960:6;1953:5;1946:21;2064:3;20947:4;2055:6;1988;2046:16;;2043:25;2040:2;;;2081:1;;2071:12;2040:2;23898:6;20947:4;1988:6;1984:17;20947:4;2022:5;2018:16;23875:30;23954:1;23936:16;;;20947:4;23936:16;23929:27;2022:5;1763:375;-1:-1;;1763:375;3796:1071;;3904:4;3892:9;3887:3;3883:19;3879:30;3876:2;;;-1:-1;;3912:12;3876:2;3940:20;3904:4;3940:20;;;3931:29;;4043:1;4028:17;4015:31;4066:18;;4058:6;4055:30;4052:2;;;4098:1;4095;4088:12;4052:2;4132:54;4182:3;4173:6;4162:9;4158:22;4132:54;;;4115:15;4108:79;4253:2;4310:9;4306:22;6191:20;6182:29;;23705:10;24890:5;23694:22;24866:5;24863:34;24853:2;;24911:1;24908;24901:12;24853:2;4286:48;4253:2;4272:5;4268:16;4261:74;4440:2;4429:9;4425:18;4412:32;4398:46;;4464:18;4456:6;4453:30;4450:2;;;4496:1;4493;4486:12;4450:2;4531:75;4602:3;4593:6;4582:9;4578:22;4531:75;;;4440:2;4517:5;4513:16;4506:101;4699:2;4688:9;4684:18;4671:32;4657:46;;4723:18;4715:6;4712:30;4709:2;;;4755:1;4752;4745:12;4709:2;;4790:55;4841:3;4832:6;4821:9;4817:22;4790:55;;;4699:2;4776:5;4772:16;4765:81;;;3870:997;;;;;6393:743;;;;;;6565:3;6553:9;6544:7;6540:23;6536:33;6533:2;;;-1:-1;;6572:12;6533:2;85:6;72:20;97:33;124:5;97:33;;;6624:63;-1:-1;6724:2;6763:22;;6055:20;;-1:-1;6832:2;6871:22;;6055:20;;-1:-1;6940:2;6979:22;;72:20;97:33;72:20;97:33;;;6527:609;;;;-1:-1;6527:609;;7048:3;7088:22;6055:20;;6527:609;-1:-1;;6527:609;7143:387;;7277:2;7265:9;7256:7;7252:23;7248:32;7245:2;;;-1:-1;;7283:12;7245:2;7341:17;7328:31;7379:18;7371:6;7368:30;7365:2;;;-1:-1;;7401:12;7365:2;7431:83;7506:7;7497:6;7486:9;7482:22;7431:83;;;7421:93;7239:291;-1:-1;;;;7239:291;7537:613;;;;;7690:3;7678:9;7669:7;7665:23;7661:33;7658:2;;;-1:-1;;7697:12;7658:2;1648:6;1635:20;7749:63;;7849:2;7890:9;7886:22;6325:20;23799:4;25010:5;23788:16;24987:5;24984:33;24974:2;;-1:-1;;25021:12;24974:2;7652:498;;7857:61;;-1:-1;;;;7955:2;7994:22;;1635:20;;8063:2;8102:22;1635:20;;7652:498;8157:345;;8270:2;8258:9;8249:7;8245:23;8241:32;8238:2;;;-1:-1;;8276:12;8238:2;8334:17;8321:31;8372:18;8364:6;8361:30;8358:2;;;-1:-1;;8394:12;8358:2;8424:62;8478:7;8469:6;8458:9;8454:22;8424:62;;8509:385;;8642:2;8630:9;8621:7;8617:23;8613:32;8610:2;;;8658:1;8655;8648:12;8610:2;8706:17;8693:31;8744:18;;8736:6;8733:30;8730:2;;;8776:1;8773;8766:12;8730:2;8861:6;8850:9;8846:22;3194:4;3182:9;3177:3;3173:19;3169:30;3166:2;;;3212:1;3209;3202:12;3166:2;3230:20;3194:4;3230:20;;;3221:29;;3320:17;3307:31;3358:18;3350:6;3347:30;3344:2;;;3390:1;3387;3380:12;3344:2;3424:68;3488:3;3479:6;3468:9;3464:22;3424:68;;;3407:15;3400:93;;8642:2;3578:9;3574:18;3561:32;3613:18;3605:6;3602:30;3599:2;;;3645:1;3642;3635:12;3599:2;3680:55;3731:3;3722:6;3711:9;3707:22;3680:55;;;8642:2;3662:16;;3655:81;-1:-1;3666:5;;8604:290;-1:-1;;;;;8604:290;8901:373;;9028:2;9016:9;9007:7;9003:23;8999:32;8996:2;;;-1:-1;;9034:12;8996:2;9092:17;9079:31;9130:18;9122:6;9119:30;9116:2;;;-1:-1;;9152:12;9116:2;9182:76;9250:7;9241:6;9230:9;9226:22;9182:76;;9281:241;;9385:2;9373:9;9364:7;9360:23;9356:32;9353:2;;;-1:-1;;9391:12;9353:2;-1:-1;6055:20;;9347:175;-1:-1;9347:175;11364:315;;11488:5;21885:12;22545:6;22540:3;22533:19;11571:52;11616:6;22582:4;22577:3;22573:14;22582:4;11597:5;11593:16;11571:52;;;24416:2;24396:14;24412:7;24392:28;11635:39;;;;22582:4;11635:39;;11440:239;-1:-1;;11440:239;13930:1078;;14154:15;14148:22;14077:4;14190:13;14183:37;14235:67;14077:4;14072:3;14068:14;14283:12;14235:67;;;14392:4;;;23705:10;14392:4;14385:5;14381:16;14375:23;23694:22;14459:4;14454:3;14450:14;16326:36;14560:4;14553:5;14549:16;14543:23;14612:3;14606:4;14602:14;14560:4;14590:3;14586:14;14579:38;14632:109;10052:5;21885:12;22545:6;22540:3;22533:19;22582:4;22577:3;22573:14;10064:88;;14392:4;10217;10209:6;10205:17;22577:3;10196:27;;21747:4;10295:5;21738:14;-1:-1;10340:10;;10334:341;10359:6;10356:1;10353:13;10334:341;;;10411:20;22577:3;10415:4;10411:20;;10406:3;10399:33;9641:60;9697:3;10466:6;10460:13;9641:60;;;10381:1;10374:9;;;;;10654:14;;;;10480:82;-1:-1;22393:14;;10334:341;;;10338:14;14829:4;14822:5;14818:16;14812:23;14792:43;;14881:3;14875:4;14871:14;14829:4;14859:3;14855:14;14848:38;14901:69;14965:4;14951:12;14901:69;;;14992:11;14050:958;-1:-1;;;;;;;;;14050:958;16488:401;;11161:5;21885:12;11272:52;11317:6;11312:3;11305:4;11298:5;11294:16;11272:52;;;11336:16;;;;10793:37;;;-1:-1;11305:4;16852:12;;16641:248;-1:-1;16641:248;16896:213;23499:42;23488:54;;;;9786:37;;17014:2;16999:18;;16985:124;17116:539;10793:37;;;23799:4;23788:16;;;;17475:2;17460:18;;16441:35;17558:2;17543:18;;10793:37;17641:2;17626:18;;10793:37;17314:3;17299:19;;17285:370;17662:293;;17796:2;17817:17;17810:47;17871:74;17796:2;17785:9;17781:18;17931:6;17871:74;;;17863:82;17767:188;-1:-1;;;17767:188;17962:407;18153:2;18167:47;;;12583:2;18138:18;;;22533:19;12619:66;22573:14;;;12599:87;12705:12;;;18124:245;18376:407;18567:2;18581:47;;;12956:2;18552:18;;;22533:19;12992:66;22573:14;;;12972:87;13078:12;;;18538:245;18790:377;;18966:2;18987:17;18980:47;13415:15;13409:22;13336:4;18966:2;18955:9;18951:18;13444:37;13496:95;13327:14;18955:9;13327:14;13572:12;13496:95;;;18966:2;13676:5;13672:16;13666:23;13646:43;;13725:14;18955:9;13729:4;13725:14;;13336:4;18955:9;13709:14;13702:38;13755:69;13819:4;13805:12;13755:69;;;19033:124;18937:230;-1:-1;;;;;18937:230;19174:353;;19338:2;19359:17;19352:47;19413:104;19338:2;19327:9;19323:18;19503:6;19413:104;;19534:213;10793:37;;;19652:2;19637:18;;19623:124;19754:256;19816:2;19810:9;19842:17;;;19917:18;19902:34;;19938:22;;;19899:62;19896:2;;;19974:1;;19964:12;19896:2;19816;19983:22;19794:216;;-1:-1;19794:216;23971:268;24036:1;24043:101;24057:6;24054:1;24051:13;24043:101;;;24124:11;;;24118:18;24105:11;;;24098:39;24079:2;24072:10;24043:101;;;24159:6;24156:1;24153:13;24150:2;;;24036:1;24215:6;24210:3;24206:16;24199:27;24150:2;;24020:219;;;;24433:117;23499:42;24520:5;23488:54;24495:5;24492:35;24482:2;;24541:1;;24531:12" + "object": "0x608060405234801561001057600080fd5b50600436106101ce5760003560e01c8063647341eb11610104578063ae2dae17116100a2578063d88be12f11610071578063d88be12f14610388578063ee8b86fb14610390578063f408fb311461026e578063fa315f9d146103a3576101ce565b8063ae2dae171461033a578063bb60736214610348578063bdab16881461035e578063d6d7618c14610373576101ce565b80637a791e6e116100de5780637a791e6e1461030f5780638ee52b4e146103175780639a3b61851461032a578063a3c2f6b614610332576101ce565b8063647341eb146102d957806376f15d5b146102e75780637833bec0146102ef576101ce565b80634303a54211610171578063586f84b21161014b578063586f84b21461029457806359c28add146102a95780635ba3c7c0146102be57806363d69c88146102c6576101ce565b80634303a5421461027c5780634582eab21461028457806345fdbdb71461028c576101ce565b80632e1a7d4d116101ad5780632e1a7d4d146102195780633687617d1461022c57806336b323961461024e5780633e9ef66a1461026e576101ce565b806209e437146101d35780630527c28f146101dd5780631310e444146101f0575b600080fd5b6101db6103b1565b005b6101db6101eb366004610c35565b6103ee565b6102036101fe366004610cea565b6103f1565b60405161021091906112e4565b60405180910390f35b6101db610227366004610cea565b6103f8565b61023f61023a366004610e62565b610449565b604051610210939291906110b9565b61026161025c366004610c72565b6104e9565b6040516102109190610ffb565b6101db6101eb366004610cb5565b6102036105cb565b6101db6105d2565b6101db610637565b61029c610669565b604051610210919061126f565b6102b1610671565b604051610210919061127a565b6101db610679565b6102616102d4366004610be3565b6106de565b6101db6101eb366004610e2d565b6102036106e7565b6103026102fd366004610d03565b6106f5565b6040516102109190611183565b6101db6107b2565b610203610325366004610cea565b6107b7565b6101db6107bd565b6102036107c8565b6101db6101eb366004610d9d565b6103506107cd565b6040516102109291906112ed565b610366610806565b604051610210919061101c565b61037b61080b565b60405161021091906112d1565b610203610964565b6101db61039e366004610cea565b6101eb565b6101db6101eb366004610cea565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103e39061114c565b60405180910390fd5b565b50565b506107c790565b3373ffffffffffffffffffffffffffffffffffffffff167f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b658260405161043e91906112e4565b60405180910390a250565b505060408051808201825260048082527f1234567800000000000000000000000000000000000000000000000000000000602080840191909152835180850185528281527f87654321000000000000000000000000000000000000000000000000000000008183015284518086019095529184527f616d657400000000000000000000000000000000000000000000000000000000908401529093909250565b600060606040518060400160405280601c81526020017f19457468657265756d205369676e6564204d6573736167653a0a33320000000081525090506000818760405160200161053a929190610fd9565b60405160208183030381529060405280519060200120905060018187878760405160008152602001604052604051610575949392919061109b565b6020604051602081039080840390855afa158015610597573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015198975050505050505050565b6107c75b90565b604080518082018252601481527f5245564552545f574954485f434f4e5354414e54000000000000000000000000602082015290517f08c379a00000000000000000000000000000000000000000000000000000000081526103e391906004016110fb565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103e390611115565b6105cf61096a565b6105cf610982565b604080518082018252601581527f524551554952455f574954485f434f4e5354414e540000000000000000000000602082015290517f08c379a00000000000000000000000000000000000000000000000000000000081526103e391906004016110fb565b50929392505050565b600080546001019081905590565b6106fd6109a2565b50604080516080810182529182528051808201825260048082527f123456780000000000000000000000000000000000000000000000000000000060208381019190915280850192909252825180840184528181527f87654321000000000000000000000000000000000000000000000000000000008184015284840152825180840190935282527f616d65740000000000000000000000000000000000000000000000000000000090820152606082015290565b6103ec565b60010190565b600080546001019055565b600190565b60408051808201909152600581527f68656c6c6f0000000000000000000000000000000000000000000000000000006020820152600191565b606090565b6108136109d0565b6040805160028082526060828101909352816020015b60608152602001906001900390816108295790505090506040518060400160405280600581526020017f30783132330000000000000000000000000000000000000000000000000000008152508160008151811061088357fe5b60200260200101819052506040518060400160405280600581526020017f3078333231000000000000000000000000000000000000000000000000000000815250816001815181106108d157fe5b6020908102919091018101919091526040805160c0810182526005608082018181527f307831323300000000000000000000000000000000000000000000000000000060a0840152825281840152808201939093528051808201909152600381527f6162630000000000000000000000000000000000000000000000000000000000918101919091526060820152905090565b6104d290565b604051806020016040528061097d6109fe565b905290565b60405180604001604052806109956109d0565b8152602001606081525090565b60405180608001604052806109b5610a11565b81526020016060815260200160608152602001606081525090565b604051806080016040528060608152602001600063ffffffff16815260200160608152602001606081525090565b6040518060200160405280600081525090565b60405180606001604052806000815260200160608152602001606081525090565b600082601f830112610a42578081fd5b813567ffffffffffffffff811115610a58578182fd5b6020610a678182840201611306565b828152925080830184820160005b84811015610a9e57610a8c888584358a0101610aa9565b83529183019190830190600101610a75565b505050505092915050565b600082601f830112610ab9578081fd5b813567ffffffffffffffff811115610acf578182fd5b610b0060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601611306565b9150808252836020828501011115610b1757600080fd5b8060208401602084013760009082016020015292915050565b600060808284031215610b41578081fd5b610b4b6080611306565b90506000823567ffffffffffffffff80821115610b66578283fd5b610b7286838701610aa9565b84526020850135915063ffffffff82168214610b8c578283fd5b8160208501526040850135915080821115610ba5578283fd5b610bb186838701610a32565b60408501526060850135915080821115610bc9578283fd5b50610bd685828601610aa9565b6060840152505092915050565b600080600080600060a08688031215610bfb57600080fd5b8535610c068161135d565b945060208601359350604086013592506060860135610c248161135d565b949793965091946080013592915050565b600060208284031215610c4757600080fd5b813567ffffffffffffffff811115610c5e57600080fd5b610c6a84828501610a32565b949350505050565b60008060008060808587031215610c8857600080fd5b84359350602085013560ff81168114610ca057600080fd5b93969395505050506040820135916060013590565b600060208284031215610cc757600080fd5b813567ffffffffffffffff811115610cde57600080fd5b610c6a84828501610aa9565b600060208284031215610cfc57600080fd5b5035919050565b600060208284031215610d14578081fd5b813567ffffffffffffffff80821115610d2b578283fd5b81840160608187031215610d3d578384fd5b610d476060611306565b925080358352602081013582811115610d5e578485fd5b610d6a87828401610aa9565b602085015250604081013582811115610d81578485fd5b610d8d87828401610aa9565b6040850152509195945050505050565b600060208284031215610dae578081fd5b813567ffffffffffffffff80821115610dc5578283fd5b81840160408187031215610dd7578384fd5b610de16040611306565b9250803582811115610df1578485fd5b610dfd87828401610b30565b845250602081013582811115610e11578485fd5b610e1d87828401610aa9565b6020850152509195945050505050565b600060208284031215610e3f57600080fd5b813567ffffffffffffffff811115610e5657600080fd5b610c6a84828501610b30565b600080600060608486031215610e76578081fd5b83359250602084013567ffffffffffffffff80821115610e94578283fd5b610ea087838801610aa9565b93506040860135915080821115610eb5578283fd5b50610ec286828701610aa9565b9150509250925092565b60008151808452610ee481602086016020860161132d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000815160808452610f2b6080850182610ecc565b6020915063ffffffff82850151168286015260408401518582036040870152818151808452848401915084858202850101858401600094505b82851015610fb2577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0868303018452610f9e828251610ecc565b600195909501949387019391508601610f64565b506060880151955088810360608a0152610fcc8187610ecc565b9998505050505050505050565b60008351610feb81846020880161132d565b9190910191825250602001919050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b600060208083018184528085518083526040860191506040848202870101925083870160005b8281101561108e577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261107c858351610f16565b94509285019290850190600101611042565b5092979650505050505050565b93845260ff9290921660208401526040830152606082015260800190565b6000606082526110cc6060830186610ecc565b82810360208401526110de8186610ecc565b83810360408501526110f08186610ecc565b979650505050505050565b60006020825261110e6020830184610ecc565b9392505050565b6020808252600d908201527f53494d504c455f52455645525400000000000000000000000000000000000000604082015260600190565b6020808252600e908201527f53494d504c455f52455155495245000000000000000000000000000000000000604082015260600190565b600060208252825160806020840152805160a08401526020810151606060c08501526111b3610100850182610ecc565b604083015191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff608582030160e08601526111ee8183610ecc565b9250505060208401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08085840301604086015261122c8383610ecc565b60408701519350818682030160608701526112478185610ecc565b9250506060860151925080858303016080860152506112668183610ecc565b95945050505050565b905151815260200190565b6000602082528251604060208401526112966060840182610f16565b602085015191507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08482030160408501526112668183610ecc565b60006020825261110e6020830184610f16565b90815260200190565b600083825260406020830152610c6a6040830184610ecc565b60405181810167ffffffffffffffff8111828210171561132557600080fd5b604052919050565b60005b83811015611348578181015183820152602001611330565b83811115611357576000848401525b50505050565b73ffffffffffffffffffffffffffffffffffffffff811681146103ee57600080fdfea365627a7a72315820317467b7d0f0e7d2d63822db9997196e2e42b127bd2b1dd9c02856a6f5b591846c6578706572696d656e74616cf564736f6c634300050b0040", + "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x1CE JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x647341EB GT PUSH2 0x104 JUMPI DUP1 PUSH4 0xAE2DAE17 GT PUSH2 0xA2 JUMPI DUP1 PUSH4 0xD88BE12F GT PUSH2 0x71 JUMPI DUP1 PUSH4 0xD88BE12F EQ PUSH2 0x388 JUMPI DUP1 PUSH4 0xEE8B86FB EQ PUSH2 0x390 JUMPI DUP1 PUSH4 0xF408FB31 EQ PUSH2 0x26E JUMPI DUP1 PUSH4 0xFA315F9D EQ PUSH2 0x3A3 JUMPI PUSH2 0x1CE JUMP JUMPDEST DUP1 PUSH4 0xAE2DAE17 EQ PUSH2 0x33A JUMPI DUP1 PUSH4 0xBB607362 EQ PUSH2 0x348 JUMPI DUP1 PUSH4 0xBDAB1688 EQ PUSH2 0x35E JUMPI DUP1 PUSH4 0xD6D7618C EQ PUSH2 0x373 JUMPI PUSH2 0x1CE JUMP JUMPDEST DUP1 PUSH4 0x7A791E6E GT PUSH2 0xDE JUMPI DUP1 PUSH4 0x7A791E6E EQ PUSH2 0x30F JUMPI DUP1 PUSH4 0x8EE52B4E EQ PUSH2 0x317 JUMPI DUP1 PUSH4 0x9A3B6185 EQ PUSH2 0x32A JUMPI DUP1 PUSH4 0xA3C2F6B6 EQ PUSH2 0x332 JUMPI PUSH2 0x1CE JUMP JUMPDEST DUP1 PUSH4 0x647341EB EQ PUSH2 0x2D9 JUMPI DUP1 PUSH4 0x76F15D5B EQ PUSH2 0x2E7 JUMPI DUP1 PUSH4 0x7833BEC0 EQ PUSH2 0x2EF JUMPI PUSH2 0x1CE JUMP JUMPDEST DUP1 PUSH4 0x4303A542 GT PUSH2 0x171 JUMPI DUP1 PUSH4 0x586F84B2 GT PUSH2 0x14B JUMPI DUP1 PUSH4 0x586F84B2 EQ PUSH2 0x294 JUMPI DUP1 PUSH4 0x59C28ADD EQ PUSH2 0x2A9 JUMPI DUP1 PUSH4 0x5BA3C7C0 EQ PUSH2 0x2BE JUMPI DUP1 PUSH4 0x63D69C88 EQ PUSH2 0x2C6 JUMPI PUSH2 0x1CE JUMP JUMPDEST DUP1 PUSH4 0x4303A542 EQ PUSH2 0x27C JUMPI DUP1 PUSH4 0x4582EAB2 EQ PUSH2 0x284 JUMPI DUP1 PUSH4 0x45FDBDB7 EQ PUSH2 0x28C JUMPI PUSH2 0x1CE JUMP JUMPDEST DUP1 PUSH4 0x2E1A7D4D GT PUSH2 0x1AD JUMPI DUP1 PUSH4 0x2E1A7D4D EQ PUSH2 0x219 JUMPI DUP1 PUSH4 0x3687617D EQ PUSH2 0x22C JUMPI DUP1 PUSH4 0x36B32396 EQ PUSH2 0x24E JUMPI DUP1 PUSH4 0x3E9EF66A EQ PUSH2 0x26E JUMPI PUSH2 0x1CE JUMP JUMPDEST DUP1 PUSH3 0x9E437 EQ PUSH2 0x1D3 JUMPI DUP1 PUSH4 0x527C28F EQ PUSH2 0x1DD JUMPI DUP1 PUSH4 0x1310E444 EQ PUSH2 0x1F0 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x1DB PUSH2 0x3B1 JUMP JUMPDEST STOP JUMPDEST PUSH2 0x1DB PUSH2 0x1EB CALLDATASIZE PUSH1 0x4 PUSH2 0xC35 JUMP JUMPDEST PUSH2 0x3EE JUMP JUMPDEST PUSH2 0x203 PUSH2 0x1FE CALLDATASIZE PUSH1 0x4 PUSH2 0xCEA JUMP JUMPDEST PUSH2 0x3F1 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x210 SWAP2 SWAP1 PUSH2 0x12E4 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x1DB PUSH2 0x227 CALLDATASIZE PUSH1 0x4 PUSH2 0xCEA JUMP JUMPDEST PUSH2 0x3F8 JUMP JUMPDEST PUSH2 0x23F PUSH2 0x23A CALLDATASIZE PUSH1 0x4 PUSH2 0xE62 JUMP JUMPDEST PUSH2 0x449 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x210 SWAP4 SWAP3 SWAP2 SWAP1 PUSH2 0x10B9 JUMP JUMPDEST PUSH2 0x261 PUSH2 0x25C CALLDATASIZE PUSH1 0x4 PUSH2 0xC72 JUMP JUMPDEST PUSH2 0x4E9 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x210 SWAP2 SWAP1 PUSH2 0xFFB JUMP JUMPDEST PUSH2 0x1DB PUSH2 0x1EB CALLDATASIZE PUSH1 0x4 PUSH2 0xCB5 JUMP JUMPDEST PUSH2 0x203 PUSH2 0x5CB JUMP JUMPDEST PUSH2 0x1DB PUSH2 0x5D2 JUMP JUMPDEST PUSH2 0x1DB PUSH2 0x637 JUMP JUMPDEST PUSH2 0x29C PUSH2 0x669 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x210 SWAP2 SWAP1 PUSH2 0x126F JUMP JUMPDEST PUSH2 0x2B1 PUSH2 0x671 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x210 SWAP2 SWAP1 PUSH2 0x127A JUMP JUMPDEST PUSH2 0x1DB PUSH2 0x679 JUMP JUMPDEST PUSH2 0x261 PUSH2 0x2D4 CALLDATASIZE PUSH1 0x4 PUSH2 0xBE3 JUMP JUMPDEST PUSH2 0x6DE JUMP JUMPDEST PUSH2 0x1DB PUSH2 0x1EB CALLDATASIZE PUSH1 0x4 PUSH2 0xE2D JUMP JUMPDEST PUSH2 0x203 PUSH2 0x6E7 JUMP JUMPDEST PUSH2 0x302 PUSH2 0x2FD CALLDATASIZE PUSH1 0x4 PUSH2 0xD03 JUMP JUMPDEST PUSH2 0x6F5 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x210 SWAP2 SWAP1 PUSH2 0x1183 JUMP JUMPDEST PUSH2 0x1DB PUSH2 0x7B2 JUMP JUMPDEST PUSH2 0x203 PUSH2 0x325 CALLDATASIZE PUSH1 0x4 PUSH2 0xCEA JUMP JUMPDEST PUSH2 0x7B7 JUMP JUMPDEST PUSH2 0x1DB PUSH2 0x7BD JUMP JUMPDEST PUSH2 0x203 PUSH2 0x7C8 JUMP JUMPDEST PUSH2 0x1DB PUSH2 0x1EB CALLDATASIZE PUSH1 0x4 PUSH2 0xD9D JUMP JUMPDEST PUSH2 0x350 PUSH2 0x7CD JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x210 SWAP3 SWAP2 SWAP1 PUSH2 0x12ED JUMP JUMPDEST PUSH2 0x366 PUSH2 0x806 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x210 SWAP2 SWAP1 PUSH2 0x101C JUMP JUMPDEST PUSH2 0x37B PUSH2 0x80B JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x210 SWAP2 SWAP1 PUSH2 0x12D1 JUMP JUMPDEST PUSH2 0x203 PUSH2 0x964 JUMP JUMPDEST PUSH2 0x1DB PUSH2 0x39E CALLDATASIZE PUSH1 0x4 PUSH2 0xCEA JUMP JUMPDEST PUSH2 0x1EB JUMP JUMPDEST PUSH2 0x1DB PUSH2 0x1EB CALLDATASIZE PUSH1 0x4 PUSH2 0xCEA JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x3E3 SWAP1 PUSH2 0x114C JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 REVERT JUMPDEST JUMP JUMPDEST POP JUMP JUMPDEST POP PUSH2 0x7C7 SWAP1 JUMP JUMPDEST CALLER PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH32 0x7FCF532C15F0A6DB0BD6D0E038BEA71D30D808C7D98CB3BF7268A95BF5081B65 DUP3 PUSH1 0x40 MLOAD PUSH2 0x43E SWAP2 SWAP1 PUSH2 0x12E4 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG2 POP JUMP JUMPDEST POP POP PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD DUP3 MSTORE PUSH1 0x4 DUP1 DUP3 MSTORE PUSH32 0x1234567800000000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP1 DUP5 ADD SWAP2 SWAP1 SWAP2 MSTORE DUP4 MLOAD DUP1 DUP6 ADD DUP6 MSTORE DUP3 DUP2 MSTORE PUSH32 0x8765432100000000000000000000000000000000000000000000000000000000 DUP2 DUP4 ADD MSTORE DUP5 MLOAD DUP1 DUP7 ADD SWAP1 SWAP6 MSTORE SWAP2 DUP5 MSTORE PUSH32 0x616D657400000000000000000000000000000000000000000000000000000000 SWAP1 DUP5 ADD MSTORE SWAP1 SWAP4 SWAP1 SWAP3 POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x60 PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x1C DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x19457468657265756D205369676E6564204D6573736167653A0A333200000000 DUP2 MSTORE POP SWAP1 POP PUSH1 0x0 DUP2 DUP8 PUSH1 0x40 MLOAD PUSH1 0x20 ADD PUSH2 0x53A SWAP3 SWAP2 SWAP1 PUSH2 0xFD9 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE DUP1 MLOAD SWAP1 PUSH1 0x20 ADD KECCAK256 SWAP1 POP PUSH1 0x1 DUP2 DUP8 DUP8 DUP8 PUSH1 0x40 MLOAD PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MSTORE PUSH1 0x40 MLOAD PUSH2 0x575 SWAP5 SWAP4 SWAP3 SWAP2 SWAP1 PUSH2 0x109B JUMP JUMPDEST PUSH1 0x20 PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 SUB SWAP1 DUP1 DUP5 SUB SWAP1 DUP6 GAS STATICCALL ISZERO DUP1 ISZERO PUSH2 0x597 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP PUSH1 0x40 MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 ADD MLOAD SWAP9 SWAP8 POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH2 0x7C7 JUMPDEST SWAP1 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD DUP3 MSTORE PUSH1 0x14 DUP2 MSTORE PUSH32 0x5245564552545F574954485F434F4E5354414E54000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE SWAP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH2 0x3E3 SWAP2 SWAP1 PUSH1 0x4 ADD PUSH2 0x10FB JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH1 0x4 ADD PUSH2 0x3E3 SWAP1 PUSH2 0x1115 JUMP JUMPDEST PUSH2 0x5CF PUSH2 0x96A JUMP JUMPDEST PUSH2 0x5CF PUSH2 0x982 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD DUP3 MSTORE PUSH1 0x15 DUP2 MSTORE PUSH32 0x524551554952455F574954485F434F4E5354414E540000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE SWAP1 MLOAD PUSH32 0x8C379A000000000000000000000000000000000000000000000000000000000 DUP2 MSTORE PUSH2 0x3E3 SWAP2 SWAP1 PUSH1 0x4 ADD PUSH2 0x10FB JUMP JUMPDEST POP SWAP3 SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 ADD SWAP1 DUP2 SWAP1 SSTORE SWAP1 JUMP JUMPDEST PUSH2 0x6FD PUSH2 0x9A2 JUMP JUMPDEST POP PUSH1 0x40 DUP1 MLOAD PUSH1 0x80 DUP2 ADD DUP3 MSTORE SWAP2 DUP3 MSTORE DUP1 MLOAD DUP1 DUP3 ADD DUP3 MSTORE PUSH1 0x4 DUP1 DUP3 MSTORE PUSH32 0x1234567800000000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP4 DUP2 ADD SWAP2 SWAP1 SWAP2 MSTORE DUP1 DUP6 ADD SWAP3 SWAP1 SWAP3 MSTORE DUP3 MLOAD DUP1 DUP5 ADD DUP5 MSTORE DUP2 DUP2 MSTORE PUSH32 0x8765432100000000000000000000000000000000000000000000000000000000 DUP2 DUP5 ADD MSTORE DUP5 DUP5 ADD MSTORE DUP3 MLOAD DUP1 DUP5 ADD SWAP1 SWAP4 MSTORE DUP3 MSTORE PUSH32 0x616D657400000000000000000000000000000000000000000000000000000000 SWAP1 DUP3 ADD MSTORE PUSH1 0x60 DUP3 ADD MSTORE SWAP1 JUMP JUMPDEST PUSH2 0x3EC JUMP JUMPDEST PUSH1 0x1 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 ADD SWAP1 SSTORE JUMP JUMPDEST PUSH1 0x1 SWAP1 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD DUP1 DUP3 ADD SWAP1 SWAP2 MSTORE PUSH1 0x5 DUP2 MSTORE PUSH32 0x68656C6C6F000000000000000000000000000000000000000000000000000000 PUSH1 0x20 DUP3 ADD MSTORE PUSH1 0x1 SWAP2 JUMP JUMPDEST PUSH1 0x60 SWAP1 JUMP JUMPDEST PUSH2 0x813 PUSH2 0x9D0 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD PUSH1 0x2 DUP1 DUP3 MSTORE PUSH1 0x60 DUP3 DUP2 ADD SWAP1 SWAP4 MSTORE DUP2 PUSH1 0x20 ADD JUMPDEST PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD SWAP1 PUSH1 0x1 SWAP1 SUB SWAP1 DUP2 PUSH2 0x829 JUMPI SWAP1 POP POP SWAP1 POP PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x5 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x3078313233000000000000000000000000000000000000000000000000000000 DUP2 MSTORE POP DUP2 PUSH1 0x0 DUP2 MLOAD DUP2 LT PUSH2 0x883 JUMPI INVALID JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD DUP2 SWAP1 MSTORE POP PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x5 DUP2 MSTORE PUSH1 0x20 ADD PUSH32 0x3078333231000000000000000000000000000000000000000000000000000000 DUP2 MSTORE POP DUP2 PUSH1 0x1 DUP2 MLOAD DUP2 LT PUSH2 0x8D1 JUMPI INVALID JUMPDEST PUSH1 0x20 SWAP1 DUP2 MUL SWAP2 SWAP1 SWAP2 ADD DUP2 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x40 DUP1 MLOAD PUSH1 0xC0 DUP2 ADD DUP3 MSTORE PUSH1 0x5 PUSH1 0x80 DUP3 ADD DUP2 DUP2 MSTORE PUSH32 0x3078313233000000000000000000000000000000000000000000000000000000 PUSH1 0xA0 DUP5 ADD MSTORE DUP3 MSTORE DUP2 DUP5 ADD MSTORE DUP1 DUP3 ADD SWAP4 SWAP1 SWAP4 MSTORE DUP1 MLOAD DUP1 DUP3 ADD SWAP1 SWAP2 MSTORE PUSH1 0x3 DUP2 MSTORE PUSH32 0x6162630000000000000000000000000000000000000000000000000000000000 SWAP2 DUP2 ADD SWAP2 SWAP1 SWAP2 MSTORE PUSH1 0x60 DUP3 ADD MSTORE SWAP1 POP SWAP1 JUMP JUMPDEST PUSH2 0x4D2 SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x20 ADD PUSH1 0x40 MSTORE DUP1 PUSH2 0x97D PUSH2 0x9FE JUMP JUMPDEST SWAP1 MSTORE SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH2 0x995 PUSH2 0x9D0 JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x80 ADD PUSH1 0x40 MSTORE DUP1 PUSH2 0x9B5 PUSH2 0xA11 JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x80 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 PUSH4 0xFFFFFFFF AND DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x20 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x60 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x60 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0xA42 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xA58 JUMPI DUP2 DUP3 REVERT JUMPDEST PUSH1 0x20 PUSH2 0xA67 DUP2 DUP3 DUP5 MUL ADD PUSH2 0x1306 JUMP JUMPDEST DUP3 DUP2 MSTORE SWAP3 POP DUP1 DUP4 ADD DUP5 DUP3 ADD PUSH1 0x0 JUMPDEST DUP5 DUP2 LT ISZERO PUSH2 0xA9E JUMPI PUSH2 0xA8C DUP9 DUP6 DUP5 CALLDATALOAD DUP11 ADD ADD PUSH2 0xAA9 JUMP JUMPDEST DUP4 MSTORE SWAP2 DUP4 ADD SWAP2 SWAP1 DUP4 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0xA75 JUMP JUMPDEST POP POP POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP3 PUSH1 0x1F DUP4 ADD SLT PUSH2 0xAB9 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xACF JUMPI DUP2 DUP3 REVERT JUMPDEST PUSH2 0xB00 PUSH1 0x20 PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 PUSH1 0x1F DUP5 ADD AND ADD PUSH2 0x1306 JUMP JUMPDEST SWAP2 POP DUP1 DUP3 MSTORE DUP4 PUSH1 0x20 DUP3 DUP6 ADD ADD GT ISZERO PUSH2 0xB17 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP1 PUSH1 0x20 DUP5 ADD PUSH1 0x20 DUP5 ADD CALLDATACOPY PUSH1 0x0 SWAP1 DUP3 ADD PUSH1 0x20 ADD MSTORE SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x80 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xB41 JUMPI DUP1 DUP2 REVERT JUMPDEST PUSH2 0xB4B PUSH1 0x80 PUSH2 0x1306 JUMP JUMPDEST SWAP1 POP PUSH1 0x0 DUP3 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0xB66 JUMPI DUP3 DUP4 REVERT JUMPDEST PUSH2 0xB72 DUP7 DUP4 DUP8 ADD PUSH2 0xAA9 JUMP JUMPDEST DUP5 MSTORE PUSH1 0x20 DUP6 ADD CALLDATALOAD SWAP2 POP PUSH4 0xFFFFFFFF DUP3 AND DUP3 EQ PUSH2 0xB8C JUMPI DUP3 DUP4 REVERT JUMPDEST DUP2 PUSH1 0x20 DUP6 ADD MSTORE PUSH1 0x40 DUP6 ADD CALLDATALOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0xBA5 JUMPI DUP3 DUP4 REVERT JUMPDEST PUSH2 0xBB1 DUP7 DUP4 DUP8 ADD PUSH2 0xA32 JUMP JUMPDEST PUSH1 0x40 DUP6 ADD MSTORE PUSH1 0x60 DUP6 ADD CALLDATALOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0xBC9 JUMPI DUP3 DUP4 REVERT JUMPDEST POP PUSH2 0xBD6 DUP6 DUP3 DUP7 ADD PUSH2 0xAA9 JUMP JUMPDEST PUSH1 0x60 DUP5 ADD MSTORE POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x0 PUSH1 0xA0 DUP7 DUP9 SUB SLT ISZERO PUSH2 0xBFB JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP6 CALLDATALOAD PUSH2 0xC06 DUP2 PUSH2 0x135D JUMP JUMPDEST SWAP5 POP PUSH1 0x20 DUP7 ADD CALLDATALOAD SWAP4 POP PUSH1 0x40 DUP7 ADD CALLDATALOAD SWAP3 POP PUSH1 0x60 DUP7 ADD CALLDATALOAD PUSH2 0xC24 DUP2 PUSH2 0x135D JUMP JUMPDEST SWAP5 SWAP8 SWAP4 SWAP7 POP SWAP2 SWAP5 PUSH1 0x80 ADD CALLDATALOAD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xC47 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xC5E JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xC6A DUP5 DUP3 DUP6 ADD PUSH2 0xA32 JUMP JUMPDEST SWAP5 SWAP4 POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 DUP1 PUSH1 0x80 DUP6 DUP8 SUB SLT ISZERO PUSH2 0xC88 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP5 CALLDATALOAD SWAP4 POP PUSH1 0x20 DUP6 ADD CALLDATALOAD PUSH1 0xFF DUP2 AND DUP2 EQ PUSH2 0xCA0 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST SWAP4 SWAP7 SWAP4 SWAP6 POP POP POP POP PUSH1 0x40 DUP3 ADD CALLDATALOAD SWAP2 PUSH1 0x60 ADD CALLDATALOAD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xCC7 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xCDE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xC6A DUP5 DUP3 DUP6 ADD PUSH2 0xAA9 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xCFC JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xD14 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0xD2B JUMPI DUP3 DUP4 REVERT JUMPDEST DUP2 DUP5 ADD PUSH1 0x60 DUP2 DUP8 SUB SLT ISZERO PUSH2 0xD3D JUMPI DUP4 DUP5 REVERT JUMPDEST PUSH2 0xD47 PUSH1 0x60 PUSH2 0x1306 JUMP JUMPDEST SWAP3 POP DUP1 CALLDATALOAD DUP4 MSTORE PUSH1 0x20 DUP2 ADD CALLDATALOAD DUP3 DUP2 GT ISZERO PUSH2 0xD5E JUMPI DUP5 DUP6 REVERT JUMPDEST PUSH2 0xD6A DUP8 DUP3 DUP5 ADD PUSH2 0xAA9 JUMP JUMPDEST PUSH1 0x20 DUP6 ADD MSTORE POP PUSH1 0x40 DUP2 ADD CALLDATALOAD DUP3 DUP2 GT ISZERO PUSH2 0xD81 JUMPI DUP5 DUP6 REVERT JUMPDEST PUSH2 0xD8D DUP8 DUP3 DUP5 ADD PUSH2 0xAA9 JUMP JUMPDEST PUSH1 0x40 DUP6 ADD MSTORE POP SWAP2 SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xDAE JUMPI DUP1 DUP2 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0xDC5 JUMPI DUP3 DUP4 REVERT JUMPDEST DUP2 DUP5 ADD PUSH1 0x40 DUP2 DUP8 SUB SLT ISZERO PUSH2 0xDD7 JUMPI DUP4 DUP5 REVERT JUMPDEST PUSH2 0xDE1 PUSH1 0x40 PUSH2 0x1306 JUMP JUMPDEST SWAP3 POP DUP1 CALLDATALOAD DUP3 DUP2 GT ISZERO PUSH2 0xDF1 JUMPI DUP5 DUP6 REVERT JUMPDEST PUSH2 0xDFD DUP8 DUP3 DUP5 ADD PUSH2 0xB30 JUMP JUMPDEST DUP5 MSTORE POP PUSH1 0x20 DUP2 ADD CALLDATALOAD DUP3 DUP2 GT ISZERO PUSH2 0xE11 JUMPI DUP5 DUP6 REVERT JUMPDEST PUSH2 0xE1D DUP8 DUP3 DUP5 ADD PUSH2 0xAA9 JUMP JUMPDEST PUSH1 0x20 DUP6 ADD MSTORE POP SWAP2 SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xE3F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0xE56 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0xC6A DUP5 DUP3 DUP6 ADD PUSH2 0xB30 JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 PUSH1 0x60 DUP5 DUP7 SUB SLT ISZERO PUSH2 0xE76 JUMPI DUP1 DUP2 REVERT JUMPDEST DUP4 CALLDATALOAD SWAP3 POP PUSH1 0x20 DUP5 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP1 DUP3 GT ISZERO PUSH2 0xE94 JUMPI DUP3 DUP4 REVERT JUMPDEST PUSH2 0xEA0 DUP8 DUP4 DUP9 ADD PUSH2 0xAA9 JUMP JUMPDEST SWAP4 POP PUSH1 0x40 DUP7 ADD CALLDATALOAD SWAP2 POP DUP1 DUP3 GT ISZERO PUSH2 0xEB5 JUMPI DUP3 DUP4 REVERT JUMPDEST POP PUSH2 0xEC2 DUP7 DUP3 DUP8 ADD PUSH2 0xAA9 JUMP JUMPDEST SWAP2 POP POP SWAP3 POP SWAP3 POP SWAP3 JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD DUP1 DUP5 MSTORE PUSH2 0xEE4 DUP2 PUSH1 0x20 DUP7 ADD PUSH1 0x20 DUP7 ADD PUSH2 0x132D JUMP JUMPDEST PUSH1 0x1F ADD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 AND SWAP3 SWAP1 SWAP3 ADD PUSH1 0x20 ADD SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD PUSH1 0x80 DUP5 MSTORE PUSH2 0xF2B PUSH1 0x80 DUP6 ADD DUP3 PUSH2 0xECC JUMP JUMPDEST PUSH1 0x20 SWAP2 POP PUSH4 0xFFFFFFFF DUP3 DUP6 ADD MLOAD AND DUP3 DUP7 ADD MSTORE PUSH1 0x40 DUP5 ADD MLOAD DUP6 DUP3 SUB PUSH1 0x40 DUP8 ADD MSTORE DUP2 DUP2 MLOAD DUP1 DUP5 MSTORE DUP5 DUP5 ADD SWAP2 POP DUP5 DUP6 DUP3 MUL DUP6 ADD ADD DUP6 DUP5 ADD PUSH1 0x0 SWAP5 POP JUMPDEST DUP3 DUP6 LT ISZERO PUSH2 0xFB2 JUMPI PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 DUP7 DUP4 SUB ADD DUP5 MSTORE PUSH2 0xF9E DUP3 DUP3 MLOAD PUSH2 0xECC JUMP JUMPDEST PUSH1 0x1 SWAP6 SWAP1 SWAP6 ADD SWAP5 SWAP4 DUP8 ADD SWAP4 SWAP2 POP DUP7 ADD PUSH2 0xF64 JUMP JUMPDEST POP PUSH1 0x60 DUP9 ADD MLOAD SWAP6 POP DUP9 DUP2 SUB PUSH1 0x60 DUP11 ADD MSTORE PUSH2 0xFCC DUP2 DUP8 PUSH2 0xECC JUMP JUMPDEST SWAP10 SWAP9 POP POP POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP4 MLOAD PUSH2 0xFEB DUP2 DUP5 PUSH1 0x20 DUP9 ADD PUSH2 0x132D JUMP JUMPDEST SWAP2 SWAP1 SWAP2 ADD SWAP2 DUP3 MSTORE POP PUSH1 0x20 ADD SWAP2 SWAP1 POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF SWAP2 SWAP1 SWAP2 AND DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP1 DUP4 ADD DUP2 DUP5 MSTORE DUP1 DUP6 MLOAD DUP1 DUP4 MSTORE PUSH1 0x40 DUP7 ADD SWAP2 POP PUSH1 0x40 DUP5 DUP3 MUL DUP8 ADD ADD SWAP3 POP DUP4 DUP8 ADD PUSH1 0x0 JUMPDEST DUP3 DUP2 LT ISZERO PUSH2 0x108E JUMPI PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 DUP9 DUP7 SUB ADD DUP5 MSTORE PUSH2 0x107C DUP6 DUP4 MLOAD PUSH2 0xF16 JUMP JUMPDEST SWAP5 POP SWAP3 DUP6 ADD SWAP3 SWAP1 DUP6 ADD SWAP1 PUSH1 0x1 ADD PUSH2 0x1042 JUMP JUMPDEST POP SWAP3 SWAP8 SWAP7 POP POP POP POP POP POP POP JUMP JUMPDEST SWAP4 DUP5 MSTORE PUSH1 0xFF SWAP3 SWAP1 SWAP3 AND PUSH1 0x20 DUP5 ADD MSTORE PUSH1 0x40 DUP4 ADD MSTORE PUSH1 0x60 DUP3 ADD MSTORE PUSH1 0x80 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x60 DUP3 MSTORE PUSH2 0x10CC PUSH1 0x60 DUP4 ADD DUP7 PUSH2 0xECC JUMP JUMPDEST DUP3 DUP2 SUB PUSH1 0x20 DUP5 ADD MSTORE PUSH2 0x10DE DUP2 DUP7 PUSH2 0xECC JUMP JUMPDEST DUP4 DUP2 SUB PUSH1 0x40 DUP6 ADD MSTORE PUSH2 0x10F0 DUP2 DUP7 PUSH2 0xECC JUMP JUMPDEST SWAP8 SWAP7 POP POP POP POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 MSTORE PUSH2 0x110E PUSH1 0x20 DUP4 ADD DUP5 PUSH2 0xECC JUMP JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0xD SWAP1 DUP3 ADD MSTORE PUSH32 0x53494D504C455F52455645525400000000000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x20 DUP1 DUP3 MSTORE PUSH1 0xE SWAP1 DUP3 ADD MSTORE PUSH32 0x53494D504C455F52455155495245000000000000000000000000000000000000 PUSH1 0x40 DUP3 ADD MSTORE PUSH1 0x60 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 MSTORE DUP3 MLOAD PUSH1 0x80 PUSH1 0x20 DUP5 ADD MSTORE DUP1 MLOAD PUSH1 0xA0 DUP5 ADD MSTORE PUSH1 0x20 DUP2 ADD MLOAD PUSH1 0x60 PUSH1 0xC0 DUP6 ADD MSTORE PUSH2 0x11B3 PUSH2 0x100 DUP6 ADD DUP3 PUSH2 0xECC JUMP JUMPDEST PUSH1 0x40 DUP4 ADD MLOAD SWAP2 POP PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60 DUP6 DUP3 SUB ADD PUSH1 0xE0 DUP7 ADD MSTORE PUSH2 0x11EE DUP2 DUP4 PUSH2 0xECC JUMP JUMPDEST SWAP3 POP POP POP PUSH1 0x20 DUP5 ADD MLOAD PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 DUP1 DUP6 DUP5 SUB ADD PUSH1 0x40 DUP7 ADD MSTORE PUSH2 0x122C DUP4 DUP4 PUSH2 0xECC JUMP JUMPDEST PUSH1 0x40 DUP8 ADD MLOAD SWAP4 POP DUP2 DUP7 DUP3 SUB ADD PUSH1 0x60 DUP8 ADD MSTORE PUSH2 0x1247 DUP2 DUP6 PUSH2 0xECC JUMP JUMPDEST SWAP3 POP POP PUSH1 0x60 DUP7 ADD MLOAD SWAP3 POP DUP1 DUP6 DUP4 SUB ADD PUSH1 0x80 DUP7 ADD MSTORE POP PUSH2 0x1266 DUP2 DUP4 PUSH2 0xECC JUMP JUMPDEST SWAP6 SWAP5 POP POP POP POP POP JUMP JUMPDEST SWAP1 MLOAD MLOAD DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 MSTORE DUP3 MLOAD PUSH1 0x40 PUSH1 0x20 DUP5 ADD MSTORE PUSH2 0x1296 PUSH1 0x60 DUP5 ADD DUP3 PUSH2 0xF16 JUMP JUMPDEST PUSH1 0x20 DUP6 ADD MLOAD SWAP2 POP PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 DUP5 DUP3 SUB ADD PUSH1 0x40 DUP6 ADD MSTORE PUSH2 0x1266 DUP2 DUP4 PUSH2 0xECC JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 MSTORE PUSH2 0x110E PUSH1 0x20 DUP4 ADD DUP5 PUSH2 0xF16 JUMP JUMPDEST SWAP1 DUP2 MSTORE PUSH1 0x20 ADD SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP4 DUP3 MSTORE PUSH1 0x40 PUSH1 0x20 DUP4 ADD MSTORE PUSH2 0xC6A PUSH1 0x40 DUP4 ADD DUP5 PUSH2 0xECC JUMP JUMPDEST PUSH1 0x40 MLOAD DUP2 DUP2 ADD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT DUP3 DUP3 LT OR ISZERO PUSH2 0x1325 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x40 MSTORE SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x1348 JUMPI DUP2 DUP2 ADD MLOAD DUP4 DUP3 ADD MSTORE PUSH1 0x20 ADD PUSH2 0x1330 JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0x1357 JUMPI PUSH1 0x0 DUP5 DUP5 ADD MSTORE JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP2 AND DUP2 EQ PUSH2 0x3EE JUMPI PUSH1 0x0 DUP1 REVERT INVALID LOG3 PUSH6 0x627A7A723158 KECCAK256 BALANCE PUSH21 0x67B7D0F0E7D2D63822DB9997196E2E42B127BD2B1D 0xd9 0xc0 0x28 JUMP 0xa6 CREATE2 0xb5 SWAP2 DUP5 PUSH13 0x6578706572696D656E74616CF5 PUSH5 0x736F6C6343 STOP SDIV SIGNEXTEND STOP BLOCKHASH ", + "sourceMap": "641:6596:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;641:6596:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1496:107;;;:::i;:::-;;3294:63;;;;;;;;;:::i;6201:128::-;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;2689:84;;;;;;;;;:::i;6824:345::-;;;;;;;;;:::i;:::-;;;;;;;;;;2288:334;;;;;;;;;:::i;:::-;;;;;;;;3132:52;;;;;;;5806:117;;;:::i;1389:101::-;;;:::i;1286:97::-;;;:::i;4505:153::-;;;:::i;:::-;;;;;;;;4237:73;;;:::i;:::-;;;;;;;;1609:111;;;:::i;2927:166::-;;;;;;;;;:::i;3503:52::-;;;;;;;4684:72;;;:::i;6402:317::-;;;;;;;;;:::i;:::-;;;;;;;;5615:112;;;:::i;989:140::-;;;;;;;;;:::i;4761:69::-;;;:::i;862:121::-;;;:::i;4168:64::-;;;;;;;4836:134;;;:::i;:::-;;;;;;;;;3993:80;;;:::i;:::-;;;;;;;;3637:350;;;:::i;:::-;;;;;;;;1135:145;;;:::i;6002:123::-;;;;;;;;;:::i;4976:47::-;;;;;;;1496:107;1564:32;;;;;;;;;;;;;;;;;;;;1496:107::o;3294:63::-;;:::o;6201:128::-;-1:-1:-1;6318:4:0;;6201:128::o;2689:84::-;2750:10;2739:27;;;2762:3;2739:27;;;;;;;;;;;;;;;2689:84;:::o;6824:345::-;-1:-1:-1;;7071:91:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;6824:345:0:o;2288:334::-;2399:21;2436:19;:56;;;;;;;;;;;;;;;;;;;2502:20;2552:6;2560:4;2535:30;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;2535:30:0;;;2525:41;;;;;;2502:64;;2583:32;2593:12;2607:1;2610;2613;2583:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;-1:-1;;2583:32:0;;;;;;2288:334;-1:-1:-1;;;;;;;;2288:334:0:o;5806:117::-;5912:4;5806:117;;:::o;1389:101::-;1469:13;;;;;;;;;;;;;;;;1462:21;;;;;;;1469:13;1462:21;;;;1286:97;1353:23;;;;;;;;;;;4505:153;4599:51;;:::i;4237:73::-;4287:19;;:::i;1609:111::-;1698:14;;;;;;;;;;;;;;;;1683:30;;;;;;;1698:14;1683:30;;;;2927:166;-1:-1:-1;3085:1:0;;2927:166;-1:-1:-1;;;2927:166:0:o;4684:72::-;4724:4;4739:14;;4752:1;4739:14;;;;;4684:72;:::o;6402:317::-;6516:20;;:::i;:::-;-1:-1:-1;6559:153:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6402:317::o;5615:112::-;5699:21;;989:140;1117:1;:5;;989:140::o;4761:69::-;4813:9;:14;;4826:1;4813:14;;;4761:69::o;862:121::-;975:1;862:121;:::o;4836:134::-;4944:19;;;;;;;;;;;;;;;;;4952:1;4836:134;:::o;3993:80::-;4054:15;3993:80;:::o;3637:350::-;3681:15;;:::i;:::-;3735:14;;;3747:1;3735:14;;;3708:24;3735:14;;;;;;;;;;;;;;;;;;;;;;;;;;3708:41;;3759:22;;;;;;;;;;;;;;;;;:9;3769:1;3759:12;;;;;;;;;;;;;:22;;;;3791;;;;;;;;;;;;;;;;;:9;3801:1;3791:12;;;;;;;;;;;;;;;;;;:22;;;;3831:149;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3831:149:0;;;;-1:-1:-1;3637:350:0;:::o;1135:145::-;711:4;1135:145;:::o;641:6596::-;;;;;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::o;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::o;158:685:-1:-;;276:3;269:4;261:6;257:17;253:27;243:2;;-1:-1;;284:12;243:2;331:6;318:20;31012:18;31004:6;31001:30;30998:2;;;-1:-1;;31034:12;30998:2;31079:4;353:81;31142:4;31079;31071:6;31067:17;31132:15;353:81;;;462:21;;;344:90;-1:-1;519:14;;;494:17;;;614:1;599:238;624:6;621:1;618:13;599:238;;;731:42;769:3;506:4;707:3;694:17;498:6;682:30;;731:42;;;719:55;;788:14;;;;816;;;;646:1;639:9;599:238;;;603:14;;;;;236:607;;;;;1706:432;;1803:3;1796:4;1788:6;1784:17;1780:27;1770:2;;-1:-1;;1811:12;1770:2;1858:6;1845:20;31619:18;31611:6;31608:30;31605:2;;;-1:-1;;31641:12;31605:2;1880:60;31782:4;31714:9;1796:4;31699:6;31695:17;31691:33;31772:15;1880:60;;;1871:69;;1960:6;1953:5;1946:21;2064:3;31782:4;2055:6;1988;2046:16;;2043:25;2040:2;;;2081:1;;2071:12;2040:2;36120:6;31782:4;1988:6;1984:17;31782:4;2022:5;2018:16;36097:30;36176:1;36158:16;;;31782:4;36158:16;36151:27;2022:5;1763:375;-1:-1;;1763:375;5221:1071;;5329:4;5317:9;5312:3;5308:19;5304:30;5301:2;;;-1:-1;;5337:12;5301:2;5365:20;5329:4;5365:20;;;5356:29;;5468:1;5453:17;5440:31;5491:18;;5483:6;5480:30;5477:2;;;5523:1;5520;5513:12;5477:2;5557:54;5607:3;5598:6;5587:9;5583:22;5557:54;;;5540:15;5533:79;5678:2;5735:9;5731:22;7616:20;7607:29;;35927:10;37234:5;35916:22;37210:5;37207:34;37197:2;;37255:1;37252;37245:12;37197:2;5711:48;5678:2;5697:5;5693:16;5686:74;5865:2;5854:9;5850:18;5837:32;5823:46;;5889:18;5881:6;5878:30;5875:2;;;5921:1;5918;5911:12;5875:2;5956:75;6027:3;6018:6;6007:9;6003:22;5956:75;;;5865:2;5942:5;5938:16;5931:101;6124:2;6113:9;6109:18;6096:32;6082:46;;6148:18;6140:6;6137:30;6134:2;;;6180:1;6177;6170:12;6134:2;;6215:55;6266:3;6257:6;6246:9;6242:22;6215:55;;;6124:2;6201:5;6197:16;6190:81;;;5295:997;;;;;7818:743;;;;;;7990:3;7978:9;7969:7;7965:23;7961:33;7958:2;;;-1:-1;;7997:12;7958:2;85:6;72:20;97:33;124:5;97:33;;;8049:63;-1:-1;8149:2;8188:22;;7480:20;;-1:-1;8257:2;8296:22;;7480:20;;-1:-1;8365:2;8404:22;;72:20;97:33;72:20;97:33;;;7952:609;;;;-1:-1;7952:609;;8473:3;8513:22;7480:20;;7952:609;-1:-1;;7952:609;8568:387;;8702:2;8690:9;8681:7;8677:23;8673:32;8670:2;;;-1:-1;;8708:12;8670:2;8766:17;8753:31;8804:18;8796:6;8793:30;8790:2;;;-1:-1;;8826:12;8790:2;8856:83;8931:7;8922:6;8911:9;8907:22;8856:83;;;8846:93;8664:291;-1:-1;;;;8664:291;8962:613;;;;;9115:3;9103:9;9094:7;9090:23;9086:33;9083:2;;;-1:-1;;9122:12;9083:2;1648:6;1635:20;9174:63;;9274:2;9315:9;9311:22;7750:20;36021:4;37354:5;36010:16;37331:5;37328:33;37318:2;;-1:-1;;37365:12;37318:2;9077:498;;9282:61;;-1:-1;;;;9380:2;9419:22;;1635:20;;9488:2;9527:22;1635:20;;9077:498;9582:345;;9695:2;9683:9;9674:7;9670:23;9666:32;9663:2;;;-1:-1;;9701:12;9663:2;9759:17;9746:31;9797:18;9789:6;9786:30;9783:2;;;-1:-1;;9819:12;9783:2;9849:62;9903:7;9894:6;9883:9;9879:22;9849:62;;9934:239;;10037:2;10025:9;10016:7;10012:23;10008:32;10005:2;;;-1:-1;;10043:12;10005:2;-1:-1;2661:20;;9999:174;-1:-1;9999:174;10534:385;;10667:2;10655:9;10646:7;10642:23;10638:32;10635:2;;;10683:1;10680;10673:12;10635:2;10731:17;10718:31;10769:18;;10761:6;10758:30;10755:2;;;10801:1;10798;10791:12;10755:2;10886:6;10875:9;10871:22;3780:4;3768:9;3763:3;3759:19;3755:30;3752:2;;;3798:1;3795;3788:12;3752:2;3816:20;3780:4;3816:20;;;3807:29;;7493:6;7480:20;3899:15;3892:74;10667:2;4043:9;4039:18;4026:32;4078:18;4070:6;4067:30;4064:2;;;4110:1;4107;4100:12;4064:2;4145:54;4195:3;4186:6;4175:9;4171:22;4145:54;;;10667:2;4131:5;4127:16;4120:80;;4288:2;4277:9;4273:18;4260:32;4312:18;4304:6;4301:30;4298:2;;;4344:1;4341;4334:12;4298:2;4379:55;4430:3;4421:6;4410:9;4406:22;4379:55;;;4288:2;4361:16;;4354:81;-1:-1;4365:5;;10629:290;-1:-1;;;;;10629:290;10926:385;;11059:2;11047:9;11038:7;11034:23;11030:32;11027:2;;;11075:1;11072;11065:12;11027:2;11123:17;11110:31;11161:18;;11153:6;11150:30;11147:2;;;11193:1;11190;11183:12;11147:2;11278:6;11267:9;11263:22;4619:4;4607:9;4602:3;4598:19;4594:30;4591:2;;;4637:1;4634;4627:12;4591:2;4655:20;4619:4;4655:20;;;4646:29;;4745:17;4732:31;4783:18;4775:6;4772:30;4769:2;;;4815:1;4812;4805:12;4769:2;4849:68;4913:3;4904:6;4893:9;4889:22;4849:68;;;4832:15;4825:93;;11059:2;5003:9;4999:18;4986:32;5038:18;5030:6;5027:30;5024:2;;;5070:1;5067;5060:12;5024:2;5105:55;5156:3;5147:6;5136:9;5132:22;5105:55;;;11059:2;5087:16;;5080:81;-1:-1;5091:5;;11021:290;-1:-1;;;;;11021:290;11318:373;;11445:2;11433:9;11424:7;11420:23;11416:32;11413:2;;;-1:-1;;11451:12;11413:2;11509:17;11496:31;11547:18;11539:6;11536:30;11533:2;;;-1:-1;;11569:12;11533:2;11599:76;11667:7;11658:6;11647:9;11643:22;11599:76;;11946:701;;;;12103:2;12091:9;12082:7;12078:23;12074:32;12071:2;;;12119:1;12116;12109:12;12071:2;7493:6;7480:20;12161:63;;12289:2;12278:9;12274:18;12261:32;12313:18;;12305:6;12302:30;12299:2;;;12345:1;12342;12335:12;12299:2;12365:62;12419:7;12410:6;12399:9;12395:22;12365:62;;;12355:72;;12492:2;12481:9;12477:18;12464:32;12450:46;;12516:18;12508:6;12505:30;12502:2;;;12548:1;12545;12538:12;12502:2;;12568:63;12623:7;12614:6;12603:9;12599:22;12568:63;;;12558:73;;;12065:582;;;;;;15443:343;;15585:5;33226:12;34312:6;34307:3;34300:19;15678:52;15723:6;34349:4;34344:3;34340:14;34349:4;15704:5;15700:16;15678:52;;;36638:2;36618:14;36634:7;36614:28;15742:39;;;;34349:4;15742:39;;15533:253;-1:-1;;15533:253;22246:1078;;22470:15;22464:22;22393:4;22506:13;22499:37;22551:67;22393:4;22388:3;22384:14;22599:12;22551:67;;;22708:4;;;35927:10;22708:4;22701:5;22697:16;22691:23;35916:22;22775:4;22770:3;22766:14;24752:36;22876:4;22869:5;22865:16;22859:23;22928:3;22922:4;22918:14;22876:4;22906:3;22902:14;22895:38;22948:109;13419:5;33226:12;34312:6;34307:3;34300:19;34349:4;34344:3;34340:14;13431:88;;22708:4;13584;13576:6;13572:17;34344:3;13563:27;;32911:4;13662:5;32902:14;-1:-1;13707:10;;13701:341;13726:6;13723:1;13720:13;13701:341;;;13778:20;34344:3;13782:4;13778:20;;13773:3;13766:33;12766:60;12822:3;13833:6;13827:13;12766:60;;;13748:1;13741:9;;;;;14021:14;;;;13847:82;-1:-1;34026:14;;13701:341;;;13705:14;23145:4;23138:5;23134:16;23128:23;23108:43;;23197:3;23191:4;23187:14;23145:4;23175:3;23171:14;23164:38;23217:69;23281:4;23267:12;23217:69;;;23308:11;22366:958;-1:-1;;;;;;;;;22366:958;24914:401;;15953:5;33226:12;16064:52;16109:6;16104:3;16097:4;16090:5;16086:16;16064:52;;;16128:16;;;;15235:37;;;-1:-1;16097:4;25278:12;;25067:248;-1:-1;25067:248;25322:213;35721:42;35710:54;;;;13153:37;;25440:2;25425:18;;25411:124;25542:437;;25748:2;;25737:9;25733:18;25788:20;25769:17;25762:47;25823:146;14406:5;33226:12;34312:6;34307:3;34300:19;34340:14;25737:9;34340:14;14418:112;;34340:14;14595:4;14587:6;14583:17;25737:9;14574:27;;14562:39;;32911:4;14691:5;32902:14;-1:-1;14730:387;14755:6;14752:1;14749:13;14730:387;;;14807:20;25737:9;14811:4;14807:20;;14802:3;14795:33;12980:88;13064:3;14862:6;14856:13;12980:88;;;14876:110;-1:-1;15096:14;;;;34026;;;;14777:1;14770:9;14730:387;;;-1:-1;25815:154;;25719:260;-1:-1;;;;;;;25719:260;25986:539;15235:37;;;36021:4;36010:16;;;;26345:2;26330:18;;24867:35;26428:2;26413:18;;15235:37;26511:2;26496:18;;15235:37;26184:3;26169:19;;26155:370;26532:691;;26762:2;26783:17;26776:47;26837:76;26762:2;26751:9;26747:18;26899:6;26837:76;;;26961:9;26955:4;26951:20;26946:2;26935:9;26931:18;26924:48;26986:76;27057:4;27048:6;26986:76;;;27110:9;27104:4;27100:20;27095:2;27084:9;27080:18;27073:48;27135:78;27208:4;27199:6;27135:78;;;27127:86;26733:490;-1:-1;;;;;;;26733:490;27230:293;;27364:2;27385:17;27378:47;27439:74;27364:2;27353:9;27349:18;27499:6;27439:74;;;27431:82;27335:188;-1:-1;;;27335:188;27530:407;27721:2;27735:47;;;17729:2;27706:18;;;34300:19;17765:66;34340:14;;;17745:87;17851:12;;;27692:245;27944:407;28135:2;28149:47;;;18102:2;28120:18;;;34300:19;18138:66;34340:14;;;18118:87;18224:12;;;28106:245;28358:381;;28536:2;28557:17;28550:47;19419:15;19413:22;19346:4;28536:2;28525:9;28521:18;19448:37;18539:15;18533:22;19337:14;28525:9;19337:14;15235:37;28536:2;18694:5;18690:16;18684:23;18468:4;18727:14;28525:9;18727:14;18720:38;18773:67;18459:14;28525:9;18459:14;18821:12;18773:67;;;18924:4;18917:5;18913:16;18907:23;18887:43;;18966:14;28525:9;18970:4;18966:14;;18950;28525:9;18950:14;18943:38;18996:69;19060:4;19046:12;18996:69;;;19087:11;;;;28536:2;19686:5;19682:16;19676:23;19735:14;;28525:9;19739:4;19735:14;;18924:4;28525:9;19719:14;19712:38;19765:67;19827:4;19813:12;19765:67;;;18924:4;19911:5;19907:16;19901:23;19881:43;;19960:14;28525:9;19964:4;19960:14;;18468:4;28525:9;19944:14;19937:38;19990:67;20052:4;20038:12;19990:67;;;19982:75;;;18468:4;20136:5;20132:16;20126:23;20106:43;;20185:14;28525:9;20189:4;20185:14;;19346:4;28525:9;20169:14;20162:38;;20215:69;20279:4;20265:12;20215:69;;;28603:126;28507:232;-1:-1;;;;;28507:232;28746:453;20750:22;;22067;15235:37;;28984:2;28969:18;;28955:244;29206:377;;29382:2;29403:17;29396:47;21267:15;21261:22;21188:4;29382:2;29371:9;29367:18;21296:37;21348:95;21179:14;29371:9;21179:14;21424:12;21348:95;;;29382:2;21528:5;21524:16;21518:23;21498:43;;21577:14;29371:9;21581:4;21577:14;;21188:4;29371:9;21561:14;21554:38;21607:69;21671:4;21657:12;21607:69;;29590:353;;29754:2;29775:17;29768:47;29829:104;29754:2;29743:9;29739:18;29919:6;29829:104;;29950:213;15235:37;;;30068:2;30053:18;;30039:124;30170:412;;15265:5;15242:3;15235:37;30336:2;30454;30443:9;30439:18;30432:48;30494:78;30336:2;30325:9;30321:18;30558:6;30494:78;;30589:256;30651:2;30645:9;30677:17;;;30752:18;30737:34;;30773:22;;;30734:62;30731:2;;;30809:1;;30799:12;30731:2;30651;30818:22;30629:216;;-1:-1;30629:216;36193:268;36258:1;36265:101;36279:6;36276:1;36273:13;36265:101;;;36346:11;;;36340:18;36327:11;;;36320:39;36301:2;36294:10;36265:101;;;36381:6;36378:1;36375:13;36372:2;;;36258:1;36437:6;36432:3;36428:16;36421:27;36372:2;;36242:219;;;;36655:117;35721:42;36742:5;35710:54;36717:5;36714:35;36704:2;;36763:1;;36753:12" } } }, @@ -399,12 +798,12 @@ } }, "sourceCodes": { - "AbiGenDummy.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma experimental ABIEncoderV2;\n\npragma solidity ^0.5.5;\n\n\ncontract AbiGenDummy\n{\n\n uint256 constant internal SOME_CONSTANT = 1234;\n string constant internal REVERT_REASON = \"REVERT_WITH_CONSTANT\";\n string constant internal REQUIRE_REASON = \"REQUIRE_WITH_CONSTANT\";\n\n function simplePureFunction ()\n public\n pure\n returns (uint256 result)\n {\n return 1;\n }\n\n function simplePureFunctionWithInput (uint256 x)\n public\n pure\n returns (uint256 sum)\n {\n return 1 + x;\n }\n\n function pureFunctionWithConstant ()\n public\n pure\n returns (uint256 someConstant)\n {\n return SOME_CONSTANT;\n }\n\n function simpleRevert ()\n public\n pure\n {\n revert(\"SIMPLE_REVERT\");\n }\n\n function revertWithConstant ()\n public\n pure\n {\n revert(REVERT_REASON);\n }\n\n function simpleRequire ()\n public\n pure\n {\n require(0 > 1, \"SIMPLE_REQUIRE\");\n }\n\n function requireWithConstant ()\n public\n pure\n {\n require(0 > 1, REQUIRE_REASON);\n }\n\n function ecrecoverFn(bytes32 hash, uint8 v, bytes32 r, bytes32 s)\n public\n pure\n returns (address signerAddress)\n {\n bytes memory prefix = \"\\x19Ethereum Signed Message:\\n32\";\n bytes32 prefixedHash = keccak256(abi.encodePacked(prefix, hash));\n return ecrecover(prefixedHash, v, r, s);\n }\n\n // test: generated code should normalize address inputs to lowercase\n // add extra inputs to make sure it works with address in any position\n function withAddressInput(address x, uint256 a, uint256 b, address y, uint256 c)\n public\n pure\n returns (address z)\n {\n return x;\n }\n\n event AnEvent(uint8 param);\n\n function acceptsBytes(bytes memory a) public pure {}\n\n /// @dev a method that accepts an array of bytes\n /// @param a the array of bytes being accepted\n function acceptsAnArrayOfBytes(bytes[] memory a) public pure {}\n\n struct Struct {\n bytes someBytes;\n uint32 anInteger;\n bytes[] aDynamicArrayOfBytes;\n string aString;\n }\n\n function structInput(Struct memory s) public pure {}\n\n /// @dev a method that returns a struct\n /// @return a Struct struct\n function structOutput() public pure returns(Struct memory s) {}\n\n struct NestedStruct {\n Struct innerStruct;\n string description;\n }\n\n function nestedStructInput(NestedStruct memory n) public pure {}\n function nestedStructOutput() public pure returns(NestedStruct memory) {}\n\n uint someState;\n function nonPureMethod() public returns(uint) { return someState += 1; }\n function nonPureMethodThatReturnsNothing() public { someState += 1; }\n}\n" + "AbiGenDummy.sol": "/*\n\n Copyright 2018 ZeroEx Intl.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n*/\n\npragma experimental ABIEncoderV2;\n\npragma solidity ^0.5.5;\n\n\ncontract AbiGenDummy\n{\n\n uint256 constant internal SOME_CONSTANT = 1234;\n string constant internal REVERT_REASON = \"REVERT_WITH_CONSTANT\";\n string constant internal REQUIRE_REASON = \"REQUIRE_WITH_CONSTANT\";\n\n function simplePureFunction ()\n public\n pure\n returns (uint256 result)\n {\n return 1;\n }\n\n function simplePureFunctionWithInput (uint256 x)\n public\n pure\n returns (uint256 sum)\n {\n return 1 + x;\n }\n\n function pureFunctionWithConstant ()\n public\n pure\n returns (uint256 someConstant)\n {\n return SOME_CONSTANT;\n }\n\n function simpleRevert ()\n public\n pure\n {\n revert(\"SIMPLE_REVERT\");\n }\n\n function revertWithConstant ()\n public\n pure\n {\n revert(REVERT_REASON);\n }\n\n function simpleRequire ()\n public\n pure\n {\n require(0 > 1, \"SIMPLE_REQUIRE\");\n }\n\n function requireWithConstant ()\n public\n pure\n {\n require(0 > 1, REQUIRE_REASON);\n }\n\n /// @dev test that devdocs will be generated and\n /// that multiline devdocs will look okay\n /// @param hash description of some hash. Let's make this line super long to demonstrate hanging indents for method params. It has to be more than one hundred twenty columns.\n /// @param v some v, recovery id\n /// @param r ECDSA r output\n /// @param s ECDSA s output\n /// @return the signerAddress that created this signature. this line too is super long in order to demonstrate the proper hanging indentation in generated code.\n function ecrecoverFn(bytes32 hash, uint8 v, bytes32 r, bytes32 s)\n public\n pure\n returns (address signerAddress)\n {\n bytes memory prefix = \"\\x19Ethereum Signed Message:\\n32\";\n bytes32 prefixedHash = keccak256(abi.encodePacked(prefix, hash));\n return ecrecover(prefixedHash, v, r, s);\n }\n\n event Withdrawal(address indexed _owner, uint _value);\n\n function withdraw(uint wad) public {\n emit Withdrawal(msg.sender, wad);\n }\n\n // test: generated code should normalize address inputs to lowercase\n // add extra inputs to make sure it works with address in any position\n function withAddressInput(address x, uint256 a, uint256 b, address y, uint256 c)\n public\n pure\n returns (address z)\n {\n return x;\n }\n\n event AnEvent(uint8 param);\n\n function acceptsBytes(bytes memory a) public pure {}\n\n /// @dev a method that accepts an array of bytes\n /// @param a the array of bytes being accepted\n function acceptsAnArrayOfBytes(bytes[] memory a) public pure {}\n\n struct Struct {\n bytes someBytes;\n uint32 anInteger;\n bytes[] aDynamicArrayOfBytes;\n string aString;\n }\n\n function structInput(Struct memory s) public pure {}\n\n /// @dev a method that returns a struct\n /// @return a Struct struct\n function structOutput() public pure returns(Struct memory s) {\n bytes[] memory byteArray = new bytes[](2);\n byteArray[0] = \"0x123\";\n byteArray[1] = \"0x321\";\n\n return Struct({\n someBytes: \"0x123\",\n anInteger: 5,\n aDynamicArrayOfBytes: byteArray,\n aString: \"abc\"\n });\n }\n\n function methodReturningArrayOfStructs() public pure returns(Struct[] memory) {}\n\n struct NestedStruct {\n Struct innerStruct;\n string description;\n }\n\n function nestedStructInput(NestedStruct memory n) public pure {}\n function nestedStructOutput() public pure returns(NestedStruct memory) {}\n\n struct StructNotDirectlyUsedAnywhere {\n uint256 aField;\n }\n\n struct NestedStructWithInnerStructNotUsedElsewhere {\n StructNotDirectlyUsedAnywhere innerStruct;\n }\n\n function methodUsingNestedStructWithInnerStructNotUsedElsewhere()\n public pure returns(NestedStructWithInnerStructNotUsedElsewhere memory)\n {}\n\n uint someState;\n function nonPureMethod() public returns(uint) { return someState += 1; }\n function nonPureMethodThatReturnsNothing() public { someState += 1; }\n\n function methodReturningMultipleValues()\n public pure returns (uint256, string memory)\n {\n return (1, \"hello\");\n }\n\n function overloadedMethod(int a) public pure {}\n function overloadedMethod(string memory a) public pure {}\n\n // begin tests for `decodeTransactionData`, `decodeReturnData`\n /// @dev complex input is dynamic and more difficult to decode than simple input.\n struct ComplexInput {\n uint256 foo;\n bytes bar;\n string car;\n }\n\n /// @dev complex input is dynamic and more difficult to decode than simple input.\n struct ComplexOutput {\n ComplexInput input;\n bytes lorem;\n bytes ipsum;\n string dolor;\n }\n\n /// @dev Tests decoding when both input and output are empty.\n function noInputNoOutput()\n public\n pure\n {\n // NOP\n require(true == true);\n }\n\n /// @dev Tests decoding when input is empty and output is non-empty.\n function noInputSimpleOutput()\n public\n pure\n returns (uint256)\n {\n return 1991;\n }\n\n /// @dev Tests decoding when input is not empty but output is empty.\n function simpleInputNoOutput(uint256)\n public\n pure\n {\n // NOP\n require(true == true);\n }\n\n /// @dev Tests decoding when both input and output are non-empty.\n function simpleInputSimpleOutput(uint256)\n public\n pure\n returns (uint256)\n {\n return 1991;\n }\n\n /// @dev Tests decoding when the input and output are complex.\n function complexInputComplexOutput(ComplexInput memory complexInput)\n public\n pure\n returns (ComplexOutput memory)\n {\n return ComplexOutput({\n input: complexInput,\n lorem: hex'12345678',\n ipsum: hex'87654321',\n dolor: \"amet\"\n });\n }\n\n /// @dev Tests decoding when the input and output are complex and have more than one argument.\n function multiInputMultiOutput(\n uint256,\n bytes memory,\n string memory\n )\n public\n pure\n returns (\n bytes memory,\n bytes memory,\n string memory\n )\n {\n return (\n hex'12345678',\n hex'87654321',\n \"amet\"\n );\n }\n\n // end tests for `decodeTransactionData`, `decodeReturnData`\n}\n" }, - "sourceTreeHashHex": "0xafbcbb2a469a1062791f49abdf3076b97d06d1994fbaf9f07f46a4fe95e07880", + "sourceTreeHashHex": "0x97df728d31cf5c513594f73accc8748aec8f8302797b10cd882ebc0be9dc7884", "compiler": { "name": "solc", - "version": "soljson-v0.5.10+commit.5a6ea5b1.js", + "version": "soljson-v0.5.11+commit.c082d0b4.js", "settings": { "optimizer": { "enabled": true, diff --git a/packages/abi-gen/test-cli/fixtures/contracts/AbiGenDummy.sol b/packages/abi-gen/test-cli/fixtures/contracts/AbiGenDummy.sol index d5fb6250b2..79d5de4cb8 100644 --- a/packages/abi-gen/test-cli/fixtures/contracts/AbiGenDummy.sol +++ b/packages/abi-gen/test-cli/fixtures/contracts/AbiGenDummy.sol @@ -80,6 +80,13 @@ contract AbiGenDummy require(0 > 1, REQUIRE_REASON); } + /// @dev test that devdocs will be generated and + /// that multiline devdocs will look okay + /// @param hash description of some hash. Let's make this line super long to demonstrate hanging indents for method params. It has to be more than one hundred twenty columns. + /// @param v some v, recovery id + /// @param r ECDSA r output + /// @param s ECDSA s output + /// @return the signerAddress that created this signature. this line too is super long in order to demonstrate the proper hanging indentation in generated code. function ecrecoverFn(bytes32 hash, uint8 v, bytes32 r, bytes32 s) public pure @@ -90,6 +97,12 @@ contract AbiGenDummy return ecrecover(prefixedHash, v, r, s); } + event Withdrawal(address indexed _owner, uint _value); + + function withdraw(uint wad) public { + emit Withdrawal(msg.sender, wad); + } + // test: generated code should normalize address inputs to lowercase // add extra inputs to make sure it works with address in any position function withAddressInput(address x, uint256 a, uint256 b, address y, uint256 c) @@ -119,7 +132,20 @@ contract AbiGenDummy /// @dev a method that returns a struct /// @return a Struct struct - function structOutput() public pure returns(Struct memory s) {} + function structOutput() public pure returns(Struct memory s) { + bytes[] memory byteArray = new bytes[](2); + byteArray[0] = "0x123"; + byteArray[1] = "0x321"; + + return Struct({ + someBytes: "0x123", + anInteger: 5, + aDynamicArrayOfBytes: byteArray, + aString: "abc" + }); + } + + function methodReturningArrayOfStructs() public pure returns(Struct[] memory) {} struct NestedStruct { Struct innerStruct; @@ -129,7 +155,117 @@ contract AbiGenDummy function nestedStructInput(NestedStruct memory n) public pure {} function nestedStructOutput() public pure returns(NestedStruct memory) {} + struct StructNotDirectlyUsedAnywhere { + uint256 aField; + } + + struct NestedStructWithInnerStructNotUsedElsewhere { + StructNotDirectlyUsedAnywhere innerStruct; + } + + function methodUsingNestedStructWithInnerStructNotUsedElsewhere() + public pure returns(NestedStructWithInnerStructNotUsedElsewhere memory) + {} + uint someState; function nonPureMethod() public returns(uint) { return someState += 1; } function nonPureMethodThatReturnsNothing() public { someState += 1; } + + function methodReturningMultipleValues() + public pure returns (uint256, string memory) + { + return (1, "hello"); + } + + function overloadedMethod(int a) public pure {} + function overloadedMethod(string memory a) public pure {} + + // begin tests for `decodeTransactionData`, `decodeReturnData` + /// @dev complex input is dynamic and more difficult to decode than simple input. + struct ComplexInput { + uint256 foo; + bytes bar; + string car; + } + + /// @dev complex input is dynamic and more difficult to decode than simple input. + struct ComplexOutput { + ComplexInput input; + bytes lorem; + bytes ipsum; + string dolor; + } + + /// @dev Tests decoding when both input and output are empty. + function noInputNoOutput() + public + pure + { + // NOP + require(true == true); + } + + /// @dev Tests decoding when input is empty and output is non-empty. + function noInputSimpleOutput() + public + pure + returns (uint256) + { + return 1991; + } + + /// @dev Tests decoding when input is not empty but output is empty. + function simpleInputNoOutput(uint256) + public + pure + { + // NOP + require(true == true); + } + + /// @dev Tests decoding when both input and output are non-empty. + function simpleInputSimpleOutput(uint256) + public + pure + returns (uint256) + { + return 1991; + } + + /// @dev Tests decoding when the input and output are complex. + function complexInputComplexOutput(ComplexInput memory complexInput) + public + pure + returns (ComplexOutput memory) + { + return ComplexOutput({ + input: complexInput, + lorem: hex'12345678', + ipsum: hex'87654321', + dolor: "amet" + }); + } + + /// @dev Tests decoding when the input and output are complex and have more than one argument. + function multiInputMultiOutput( + uint256, + bytes memory, + string memory + ) + public + pure + returns ( + bytes memory, + bytes memory, + string memory + ) + { + return ( + hex'12345678', + hex'87654321', + "amet" + ); + } + + // end tests for `decodeTransactionData`, `decodeReturnData` } diff --git a/packages/abi-gen/test-cli/fixtures/pylintrc b/packages/abi-gen/test-cli/fixtures/pylintrc new file mode 100644 index 0000000000..0bad5f64e8 --- /dev/null +++ b/packages/abi-gen/test-cli/fixtures/pylintrc @@ -0,0 +1,7 @@ +[MESSAGES CONTROL] +disable=C0330,line-too-long,fixme,too-few-public-methods,too-many-ancestors,duplicate-code,blacklisted-name +# C0330 is "bad hanging indent". we use indents per `black`. + +[BASIC] +argument-rgx=[a-z_][a-z0-9_]{0,31}$ +# above differs from the default only in that it allows 2-character names diff --git a/packages/abi-gen/test-cli/fixtures/python-requirements.txt b/packages/abi-gen/test-cli/fixtures/python-requirements.txt new file mode 100644 index 0000000000..8609654621 --- /dev/null +++ b/packages/abi-gen/test-cli/fixtures/python-requirements.txt @@ -0,0 +1,6 @@ +black +eth_utils +hexbytes +mypy_extensions +pylint +web3 diff --git a/packages/abi-gen/test-cli/test_typescript/test/abi_gen_dummy_test.ts b/packages/abi-gen/test-cli/test_typescript/test/abi_gen_dummy_test.ts index ec12d5c55a..33fce30f72 100644 --- a/packages/abi-gen/test-cli/test_typescript/test/abi_gen_dummy_test.ts +++ b/packages/abi-gen/test-cli/test_typescript/test/abi_gen_dummy_test.ts @@ -7,8 +7,9 @@ import * as chai from 'chai'; import * as chaiAsPromised from 'chai-as-promised'; import * as ChaiBigNumber from 'chai-bignumber'; import * as dirtyChai from 'dirty-chai'; +import * as Sinon from 'sinon'; -import { AbiGenDummyContract, artifacts, TestLibDummyContract } from '../src'; +import { AbiGenDummyContract, AbiGenDummyEvents, artifacts, TestLibDummyContract } from '../src'; const txDefaults = { from: devConstants.TESTRPC_FIRST_ADDRESS, @@ -27,9 +28,28 @@ const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); describe('AbiGenDummy Contract', () => { let abiGenDummy: AbiGenDummyContract; + const runTestAsync = async (contractMethod: any, input: any, output: any) => { + const transaction = contractMethod.getABIEncodedTransactionData(input); + // try decoding transaction + const decodedInput = contractMethod.getABIDecodedTransactionData(transaction); + expect(decodedInput, 'decoded input').to.be.deep.equal(input); + // execute transaction + const rawOutput = await web3Wrapper.callAsync({ + to: abiGenDummy.address, + data: transaction, + }); + // try decoding output + const decodedOutput = contractMethod.getABIDecodedReturnData(rawOutput); + expect(decodedOutput, 'decoded output').to.be.deep.equal(output); + }; before(async () => { providerUtils.startProviderEngine(provider); - abiGenDummy = await AbiGenDummyContract.deployFrom0xArtifactAsync(artifacts.AbiGenDummy, provider, txDefaults); + abiGenDummy = await AbiGenDummyContract.deployFrom0xArtifactAsync( + artifacts.AbiGenDummy, + provider, + txDefaults, + artifacts, + ); await blockchainLifecycle.startAsync(); }); after(async () => { @@ -74,6 +94,19 @@ describe('AbiGenDummy Contract', () => { }); }); + describe('struct handling', () => { + const sampleStruct = { + aDynamicArrayOfBytes: ['0x3078313233', '0x3078333231'], + anInteger: new BigNumber(5), + aString: 'abc', + someBytes: '0x3078313233', + }; + it('should be able to handle struct output', async () => { + const result = await abiGenDummy.structOutput.callAsync(); + expect(result).to.deep.equal(sampleStruct); + }); + }); + describe('ecrecoverFn', () => { it('should implement ecrecover', async () => { const signerAddress = devConstants.TESTRPC_FIRST_ADDRESS; @@ -92,6 +125,44 @@ describe('AbiGenDummy Contract', () => { }); }); + describe('validate and send transaction', () => { + it('should call validateAndSendTransactionAsync', async () => { + const txHash = await abiGenDummy.nonPureMethod.validateAndSendTransactionAsync(); + const hexRegex = /^0x[a-fA-F0-9]+$/; + expect(txHash.match(hexRegex)).to.deep.equal([txHash]); + }); + }); + + describe('event subscription', () => { + const indexFilterValues = {}; + const emptyCallback = () => {}; // tslint:disable-line:no-empty + let stubs: Sinon.SinonStub[] = []; + + afterEach(() => { + stubs.forEach(s => s.restore()); + stubs = []; + }); + it('should return a subscription token', done => { + const subscriptionToken = abiGenDummy.subscribe( + AbiGenDummyEvents.Withdrawal, + indexFilterValues, + emptyCallback, + ); + expect(subscriptionToken).to.be.a('string'); + done(); + }); + it('should allow unsubscribeAll to be called successfully after an error', done => { + abiGenDummy.subscribe(AbiGenDummyEvents.Withdrawal, indexFilterValues, emptyCallback); + stubs.push( + Sinon.stub((abiGenDummy as any)._web3Wrapper, 'getBlockIfExistsAsync').throws( + new Error('JSON RPC error'), + ), + ); + abiGenDummy.unsubscribeAll(); + done(); + }); + }); + describe('withAddressInput', () => { it('should normalize address inputs to lowercase', async () => { const xAddress = devConstants.TESTRPC_FIRST_ADDRESS.toUpperCase(); @@ -104,6 +175,63 @@ describe('AbiGenDummy Contract', () => { expect(output).to.equal(xAddress.toLowerCase()); }); }); + + describe('Encoding/Decoding Transaction Data and Return Values', () => { + it('should successfully encode/decode (no input / no output)', async () => { + const input = undefined; + const output = undefined; + await runTestAsync(abiGenDummy.noInputNoOutput, input, output); + }); + it('should successfully encode/decode (no input / simple output)', async () => { + const input = undefined; + const output = new BigNumber(1991); + await runTestAsync(abiGenDummy.noInputSimpleOutput, input, output); + }); + it('should successfully encode/decode (simple input / no output)', async () => { + const input = new BigNumber(1991); + const output = undefined; + await runTestAsync(abiGenDummy.simpleInputNoOutput, input, output); + }); + it('should successfully encode/decode (simple input / simple output)', async () => { + const input = new BigNumber(16); + const output = new BigNumber(1991); + await runTestAsync(abiGenDummy.simpleInputSimpleOutput, input, output); + }); + it('should successfully encode/decode (complex input / complex output)', async () => { + const input = { + foo: new BigNumber(1991), + bar: '0x1234', + car: 'zoom zoom', + }; + const output = { + input, + lorem: '0x12345678', + ipsum: '0x87654321', + dolor: 'amet', + }; + await runTestAsync(abiGenDummy.complexInputComplexOutput, input, output); + }); + it('should successfully encode/decode (multi-input / multi-output)', async () => { + const input = [new BigNumber(1991), '0x1234', 'zoom zoom']; + const output = ['0x12345678', '0x87654321', 'amet']; + const transaction = abiGenDummy.multiInputMultiOutput.getABIEncodedTransactionData( + input[0] as BigNumber, + input[1] as string, + input[2] as string, + ); + // try decoding transaction + const decodedInput = abiGenDummy.multiInputMultiOutput.getABIDecodedTransactionData(transaction); + expect(decodedInput, 'decoded input').to.be.deep.equal(input); + // execute transaction + const rawOutput = await web3Wrapper.callAsync({ + to: abiGenDummy.address, + data: transaction, + }); + // try decoding output + const decodedOutput = abiGenDummy.multiInputMultiOutput.getABIDecodedReturnData(rawOutput); + expect(decodedOutput, 'decoded output').to.be.deep.equal(output); + }); + }); }); describe('Lib dummy contract', () => { @@ -115,7 +243,12 @@ describe('Lib dummy contract', () => { await blockchainLifecycle.revertAsync(); }); before(async () => { - libDummy = await TestLibDummyContract.deployFrom0xArtifactAsync(artifacts.TestLibDummy, provider, txDefaults); + libDummy = await TestLibDummyContract.deployFrom0xArtifactAsync( + artifacts.TestLibDummy, + provider, + txDefaults, + artifacts, + ); }); beforeEach(async () => { await blockchainLifecycle.startAsync(); diff --git a/packages/assert/CHANGELOG.json b/packages/assert/CHANGELOG.json index bd5f882d2e..936ba15ef1 100644 --- a/packages/assert/CHANGELOG.json +++ b/packages/assert/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1565296576, + "version": "2.1.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1564604963, + "version": "2.1.2", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1563957393, + "version": "2.1.1", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.1.0", "changes": [ diff --git a/packages/assert/CHANGELOG.md b/packages/assert/CHANGELOG.md index f0a0b473fc..198728bb26 100644 --- a/packages/assert/CHANGELOG.md +++ b/packages/assert/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.1.3 - _August 8, 2019_ + + * Dependencies updated + +## v2.1.2 - _July 31, 2019_ + + * Dependencies updated + +## v2.1.1 - _July 24, 2019_ + + * Dependencies updated + ## v2.1.0 - _July 13, 2019_ * Add new assertions: `isArray`, `isBlockParam` and `isNumberOrBigNumber` (#1823) diff --git a/packages/assert/package.json b/packages/assert/package.json index 87d78cbdee..8332258b88 100644 --- a/packages/assert/package.json +++ b/packages/assert/package.json @@ -1,6 +1,6 @@ { "name": "@0x/assert", - "version": "2.1.0", + "version": "2.1.3", "engines": { "node": ">=6.12" }, @@ -32,12 +32,12 @@ "devDependencies": { "@0x/tslint-config": "^3.0.1", "@types/lodash": "4.14.104", - "@types/mocha": "^2.2.42", + "@types/mocha": "^5.2.7", "@types/valid-url": "^1.0.2", "chai": "^4.0.1", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "shx": "^0.2.2", @@ -45,9 +45,9 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/json-schemas": "^3.0.11", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", + "@0x/json-schemas": "^3.1.13", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", "lodash": "^4.17.11", "valid-url": "^1.0.9" }, diff --git a/packages/asset-buyer/CHANGELOG.json b/packages/asset-buyer/CHANGELOG.json index 7c4b452e1e..ae577af8a2 100644 --- a/packages/asset-buyer/CHANGELOG.json +++ b/packages/asset-buyer/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1565296576, + "version": "6.1.11", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1564604963, + "version": "6.1.10", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1563957393, + "version": "6.1.9", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563193019, "version": "6.1.8", diff --git a/packages/asset-buyer/CHANGELOG.md b/packages/asset-buyer/CHANGELOG.md index e135ceac65..a33650f58a 100644 --- a/packages/asset-buyer/CHANGELOG.md +++ b/packages/asset-buyer/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v6.1.11 - _August 8, 2019_ + + * Dependencies updated + +## v6.1.10 - _July 31, 2019_ + + * Dependencies updated + +## v6.1.9 - _July 24, 2019_ + + * Dependencies updated + ## v6.1.8 - _July 15, 2019_ * Dependencies updated diff --git a/packages/asset-buyer/package.json b/packages/asset-buyer/package.json index 78c7f838b5..df12abe0e3 100644 --- a/packages/asset-buyer/package.json +++ b/packages/asset-buyer/package.json @@ -1,6 +1,6 @@ { "name": "@0x/asset-buyer", - "version": "6.1.8", + "version": "6.1.11", "engines": { "node": ">=6.12" }, @@ -37,30 +37,30 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/asset-buyer/README.md", "dependencies": { - "@0x/assert": "^2.1.0", - "@0x/connect": "^5.0.13", - "@0x/contract-wrappers": "^9.1.7", - "@0x/json-schemas": "^3.0.11", - "@0x/order-utils": "^8.2.2", - "@0x/subproviders": "^4.1.1", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", - "ethereum-types": "^2.1.3", + "@0x/assert": "^2.1.3", + "@0x/connect": "^5.0.16", + "@0x/contract-wrappers": "^11.0.0", + "@0x/json-schemas": "^3.1.13", + "@0x/order-utils": "^8.2.5", + "@0x/subproviders": "^5.0.1", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", + "ethereum-types": "^2.1.4", "lodash": "^4.17.11" }, "devDependencies": { "@0x/tslint-config": "^3.0.1", "@types/lodash": "4.14.104", - "@types/mocha": "^2.2.42", + "@types/mocha": "^5.2.7", "@types/node": "*", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^3.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "shx": "^0.2.2", diff --git a/packages/asset-buyer/src/asset_buyer.ts b/packages/asset-buyer/src/asset_buyer.ts index eb9c1f2036..ca468c8085 100644 --- a/packages/asset-buyer/src/asset_buyer.ts +++ b/packages/asset-buyer/src/asset_buyer.ts @@ -1,6 +1,6 @@ -import { ContractWrappers, ContractWrappersError, ForwarderWrapperError } from '@0x/contract-wrappers'; +import { ContractError, ContractWrappers, ForwarderError } from '@0x/contract-wrappers'; import { schemas } from '@0x/json-schemas'; -import { SignedOrder } from '@0x/order-utils'; +import { assetDataUtils, SignedOrder } from '@0x/order-utils'; import { ObjectMap } from '@0x/types'; import { BigNumber, providerUtils } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; @@ -21,11 +21,10 @@ import { OrderProvider, OrdersAndFillableAmounts, } from './types'; - import { assert } from './utils/assert'; -import { assetDataUtils } from './utils/asset_data_utils'; import { buyQuoteCalculator } from './utils/buy_quote_calculator'; import { calculateLiquidity } from './utils/calculate_liquidity'; +import { numberPercentageToEtherTokenAmountPercentage } from './utils/number_percentage_to_ethertoken_amount_percentage'; import { orderProviderResponseProcessor } from './utils/order_provider_response_processor'; interface OrdersEntry { @@ -263,26 +262,32 @@ export class AssetBuyer { } } try { + // format fee percentage + const formattedFeePercentage = numberPercentageToEtherTokenAmountPercentage(feePercentage || 0); // if no ethAmount is provided, default to the worst ethAmount from buyQuote - const txHash = await this._contractWrappers.forwarder.marketBuyOrdersWithEthAsync( + const value = ethAmount || worstCaseQuoteInfo.totalEthAmount; + + const txHash = await this._contractWrappers.forwarder.marketBuyOrdersWithEth.validateAndSendTransactionAsync( orders, assetBuyAmount, - finalTakerAddress, - ethAmount || worstCaseQuoteInfo.totalEthAmount, + orders.map(o => o.signature), feeOrders, - feePercentage, + feeOrders.map(o => o.signature), + formattedFeePercentage, feeRecipient, { - gasLimit, + value, + from: finalTakerAddress.toLowerCase(), + gas: gasLimit, gasPrice, - shouldValidate: true, }, ); + return txHash; } catch (err) { - if (_.includes(err.message, ContractWrappersError.SignatureRequestDenied)) { + if (_.includes(err.message, ContractError.SignatureRequestDenied)) { throw new Error(AssetBuyerError.SignatureRequestDenied); - } else if (_.includes(err.message, ForwarderWrapperError.CompleteFillFailed)) { + } else if (_.includes(err.message, ForwarderError.CompleteFillFailed)) { throw new Error(AssetBuyerError.TransactionValueTooLow); } else { throw err; @@ -357,13 +362,13 @@ export class AssetBuyer { * Will throw if WETH does not exist for the current network. */ private _getEtherTokenAssetDataOrThrow(): string { - return assetDataUtils.getEtherTokenAssetData(this._contractWrappers); + return assetDataUtils.encodeERC20AssetData(this._contractWrappers.contractAddresses.etherToken); } /** * Get the assetData that represents the ZRX token. * Will throw if ZRX does not exist for the current network. */ private _getZrxTokenAssetDataOrThrow(): string { - return this._contractWrappers.exchange.getZRXAssetData(); + return assetDataUtils.encodeERC20AssetData(this._contractWrappers.contractAddresses.zrxToken); } } diff --git a/packages/asset-buyer/src/utils/asset_data_utils.ts b/packages/asset-buyer/src/utils/asset_data_utils.ts deleted file mode 100644 index 70f6469020..0000000000 --- a/packages/asset-buyer/src/utils/asset_data_utils.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ContractWrappers } from '@0x/contract-wrappers'; -import { assetDataUtils as sharedAssetDataUtils } from '@0x/order-utils'; -import * as _ from 'lodash'; - -export const assetDataUtils = { - ...sharedAssetDataUtils, - getEtherTokenAssetData(contractWrappers: ContractWrappers): string { - const etherTokenAddress = contractWrappers.forwarder.etherTokenAddress; - const etherTokenAssetData = sharedAssetDataUtils.encodeERC20AssetData(etherTokenAddress); - return etherTokenAssetData; - }, -}; diff --git a/packages/asset-buyer/src/utils/number_percentage_to_ethertoken_amount_percentage.ts b/packages/asset-buyer/src/utils/number_percentage_to_ethertoken_amount_percentage.ts new file mode 100644 index 0000000000..05c3830a9d --- /dev/null +++ b/packages/asset-buyer/src/utils/number_percentage_to_ethertoken_amount_percentage.ts @@ -0,0 +1,9 @@ +import { BigNumber } from '@0x/utils'; +import { Web3Wrapper } from '@0x/web3-wrapper'; + +// HACK (xianny): copied from asset-swapper, which will replace this package +const ONE_AMOUNT = new BigNumber(1); +const ETHER_TOKEN_DECIMALS = 18; +export const numberPercentageToEtherTokenAmountPercentage = (percentage: number): BigNumber => { + return Web3Wrapper.toBaseUnitAmount(ONE_AMOUNT, ETHER_TOKEN_DECIMALS).multipliedBy(percentage); +}; diff --git a/packages/asset-buyer/src/utils/order_provider_response_processor.ts b/packages/asset-buyer/src/utils/order_provider_response_processor.ts index cb25f98701..300cb14299 100644 --- a/packages/asset-buyer/src/utils/order_provider_response_processor.ts +++ b/packages/asset-buyer/src/utils/order_provider_response_processor.ts @@ -1,4 +1,4 @@ -import { OrderAndTraderInfo, OrderStatus, OrderValidatorWrapper } from '@0x/contract-wrappers'; +import { OrderAndTraderInfo, OrderStatus, OrderValidatorContract } from '@0x/contract-wrappers'; import { orderCalculationUtils, sortingUtils } from '@0x/order-utils'; import { RemainingFillableCalculator } from '@0x/order-utils/lib/src/remaining_fillable_calculator'; import { SignedOrder } from '@0x/types'; @@ -34,7 +34,7 @@ export const orderProviderResponseProcessor = { orderProviderResponse: OrderProviderResponse, isMakerAssetZrxToken: boolean, expiryBufferSeconds: number, - orderValidator?: OrderValidatorWrapper, + orderValidator?: OrderValidatorContract, ): Promise { // drop orders that are expired or not open const filteredOrders = filterOutExpiredAndNonOpenOrders(orderProviderResponse.orders, expiryBufferSeconds); @@ -44,10 +44,16 @@ export const orderProviderResponseProcessor = { if (orderValidator !== undefined) { const takerAddresses = _.map(filteredOrders, () => constants.NULL_ADDRESS); try { - const ordersAndTradersInfo = await orderValidator.getOrdersAndTradersInfoAsync( + const [ordersInfo, tradersInfo] = await orderValidator.getOrdersAndTradersInfo.callAsync( filteredOrders, takerAddresses, ); + const ordersAndTradersInfo = ordersInfo.map((orderInfo, index) => { + return { + orderInfo, + traderInfo: tradersInfo[index], + }; + }); // take orders + on chain information and find the valid orders and remaining fillable maker asset amounts unsortedOrders = getValidOrdersWithRemainingFillableMakerAssetAmountsFromOnChain( filteredOrders, diff --git a/packages/asset-swapper/CHANGELOG.json b/packages/asset-swapper/CHANGELOG.json index 4557ada8a2..fec40f559b 100644 --- a/packages/asset-swapper/CHANGELOG.json +++ b/packages/asset-swapper/CHANGELOG.json @@ -1,10 +1,47 @@ [ + { + "timestamp": 1565296576, + "version": "1.0.1", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "version": "1.0.0", + "changes": [ + { + "note": "Added optimization utils to consumer output", + "pr": 1988 + }, + { + "note": "Expanded test coverage", + "pr": 1980 + } + ], + "timestamp": 1564604963 + }, + { + "timestamp": 1563957393, + "version": "0.0.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563193019, "version": "0.0.4", "changes": [ { - "note": "Dependencies updated" + "note": "Switched MarketOperation type to enum and expanded default constants configuration", + "pr": 1959 + }, + { + "note": "Added additional options to control asset-swapper behavior and optimized consumer output", + "pr": 1966 } ] }, diff --git a/packages/asset-swapper/CHANGELOG.md b/packages/asset-swapper/CHANGELOG.md index 332671a5ba..c9f3939d50 100644 --- a/packages/asset-swapper/CHANGELOG.md +++ b/packages/asset-swapper/CHANGELOG.md @@ -5,10 +5,24 @@ Edit the package's CHANGELOG.json file only. CHANGELOG -## v0.0.4 - _July 15, 2019_ +## v1.0.1 - _August 8, 2019_ * Dependencies updated +## v1.0.0 - _July 31, 2019_ + + * Added optimization utils to consumer output (#1988) + * Expanded test coverage (#1980) + +## v0.0.5 - _July 24, 2019_ + + * Dependencies updated + +## v0.0.4 - _July 15, 2019_ + + * Switched MarketOperation type to enum and expanded default constants configuration (#1959) + * Added additional options to control asset-swapper behavior and optimized consumer output (#1966) + ## v0.0.3 - _July 13, 2019_ * Dependencies updated diff --git a/packages/asset-swapper/package.json b/packages/asset-swapper/package.json index 5413f057c2..1c9d003bea 100644 --- a/packages/asset-swapper/package.json +++ b/packages/asset-swapper/package.json @@ -1,6 +1,6 @@ { "name": "@0x/asset-swapper", - "version": "0.0.4", + "version": "1.0.1", "engines": { "node": ">=6.12" }, @@ -37,34 +37,34 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/asset-buyer/README.md", "dependencies": { - "@0x/assert": "^2.1.0", - "@0x/connect": "^5.0.13", - "@0x/contract-addresses": "^3.0.2", - "@0x/contract-wrappers": "^9.1.7", - "@0x/dev-utils": "^2.2.4", - "@0x/fill-scenarios": "^3.0.13", - "@0x/json-schemas": "^3.0.11", - "@0x/migrations": "^4.1.9", - "@0x/order-utils": "^8.2.2", - "@0x/subproviders": "^4.1.1", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", - "ethereum-types": "^2.1.3", + "@0x/assert": "^2.1.3", + "@0x/connect": "^5.0.16", + "@0x/contract-addresses": "^3.0.3", + "@0x/contract-wrappers": "^11.0.0", + "@0x/dev-utils": "^2.3.0", + "@0x/fill-scenarios": "^3.0.16", + "@0x/json-schemas": "^3.1.13", + "@0x/migrations": "^4.2.0", + "@0x/order-utils": "^8.2.5", + "@0x/subproviders": "^5.0.1", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", + "ethereum-types": "^2.1.4", "lodash": "^4.17.11" }, "devDependencies": { "@0x/tslint-config": "^3.0.1", "@types/lodash": "4.14.104", - "@types/mocha": "^2.2.42", + "@types/mocha": "^5.2.7", "@types/node": "*", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^3.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "shx": "^0.2.2", diff --git a/packages/asset-swapper/src/constants.ts b/packages/asset-swapper/src/constants.ts index f7654046d4..4c9d0772c6 100644 --- a/packages/asset-swapper/src/constants.ts +++ b/packages/asset-swapper/src/constants.ts @@ -10,6 +10,7 @@ import { SwapQuoterOpts, } from './types'; +const NULL_BYTES = '0x'; const NULL_ADDRESS = '0x0000000000000000000000000000000000000000'; const MAINNET_NETWORK_ID = 1; const ONE_SECOND_MS = 1000; @@ -44,6 +45,7 @@ const DEFAULT_LIQUIDITY_REQUEST_OPTS: LiquidityRequestOpts = { }; export const constants = { + NULL_BYTES, ZERO_AMOUNT: new BigNumber(0), NULL_ADDRESS, MAINNET_NETWORK_ID, diff --git a/packages/asset-swapper/src/index.ts b/packages/asset-swapper/src/index.ts index 3321fff960..079a38e4c6 100644 --- a/packages/asset-swapper/src/index.ts +++ b/packages/asset-swapper/src/index.ts @@ -16,10 +16,10 @@ export { DataItem, StateMutability, EventParameter, + TupleDataItem, ConstructorStateMutability, } from 'ethereum-types'; -// TODO(dave4506): if this lives under the 0x.js library, then these type exports should be removed in favor of minimizing redundancy export { SignedOrder } from '@0x/types'; export { BigNumber } from '@0x/utils'; @@ -36,6 +36,7 @@ export { SwapQuote, SwapQuoteConsumerOpts, CalldataInfo, + ConsumerType, SwapQuoteGetOutputOpts, SwapQuoteExecutionOpts, SwapQuoteInfo, diff --git a/packages/asset-swapper/src/quote_consumers/exchange_swap_quote_consumer.ts b/packages/asset-swapper/src/quote_consumers/exchange_swap_quote_consumer.ts index 140d6ee856..981513fcf3 100644 --- a/packages/asset-swapper/src/quote_consumers/exchange_swap_quote_consumer.ts +++ b/packages/asset-swapper/src/quote_consumers/exchange_swap_quote_consumer.ts @@ -1,4 +1,4 @@ -import { ContractWrappers, ContractWrappersError, ForwarderWrapperError } from '@0x/contract-wrappers'; +import { ContractError, ContractWrappers, ForwarderError } from '@0x/contract-wrappers'; import { MarketOperation } from '@0x/types'; import { AbiEncoder, providerUtils } from '@0x/utils'; import { SupportedProvider, ZeroExProvider } from '@0x/web3-wrapper'; @@ -45,7 +45,7 @@ export class ExchangeSwapQuoteConsumer implements SwapQuoteConsumerBase { assert.isValidSwapQuote('quote', quote); - const { to, methodAbi, ethAmount, params } = await this.getSmartContractParamsOrThrowAsync(quote, opts); + const { toAddress, methodAbi, ethAmount, params } = await this.getSmartContractParamsOrThrowAsync(quote, opts); const abiEncoder = new AbiEncoder.Method(methodAbi); @@ -58,11 +58,11 @@ export class ExchangeSwapQuoteConsumer implements SwapQuoteConsumerBase o.signature); + const optimizedOrders = swapQuoteConsumerUtils.optimizeOrdersForMarketExchangeOperation(orders, quote.type); + let params: ExchangeSmartContractParams; let methodName: string; @@ -84,7 +86,7 @@ export class ExchangeSwapQuoteConsumer implements SwapQuoteConsumerBase o.signature), { - gasLimit, + from: finalTakerAddress, + gas: gasLimit, gasPrice, - shouldValidate: true, }, ); } else { const { takerAssetFillAmount } = quote; - txHash = await this._contractWrappers.exchange.marketSellOrdersNoThrowAsync( + txHash = await this._contractWrappers.exchange.marketSellOrdersNoThrow.validateAndSendTransactionAsync( orders, takerAssetFillAmount, - finalTakerAddress, + orders.map(o => o.signature), { - gasLimit, + from: finalTakerAddress, + gas: gasLimit, gasPrice, - shouldValidate: true, }, ); } return txHash; } catch (err) { - if (_.includes(err.message, ContractWrappersError.SignatureRequestDenied)) { + if (_.includes(err.message, ContractError.SignatureRequestDenied)) { throw new Error(SwapQuoteConsumerError.SignatureRequestDenied); - } else if (_.includes(err.message, ForwarderWrapperError.CompleteFillFailed)) { + } else if (_.includes(err.message, ForwarderError.CompleteFillFailed)) { throw new Error(SwapQuoteConsumerError.TransactionValueTooLow); } else { throw err; diff --git a/packages/asset-swapper/src/quote_consumers/forwarder_swap_quote_consumer.ts b/packages/asset-swapper/src/quote_consumers/forwarder_swap_quote_consumer.ts index 45b6a75e43..afce2133a0 100644 --- a/packages/asset-swapper/src/quote_consumers/forwarder_swap_quote_consumer.ts +++ b/packages/asset-swapper/src/quote_consumers/forwarder_swap_quote_consumer.ts @@ -1,5 +1,5 @@ -import { ContractWrappers, ContractWrappersError, ForwarderWrapperError } from '@0x/contract-wrappers'; -import { calldataOptimizationUtils } from '@0x/contract-wrappers/lib/src/utils/calldata_optimization_utils'; +import { ContractError, ContractWrappers, ForwarderError } from '@0x/contract-wrappers'; +import { assetDataUtils } from '@0x/order-utils'; import { MarketOperation } from '@0x/types'; import { AbiEncoder, providerUtils } from '@0x/utils'; import { SupportedProvider, ZeroExProvider } from '@0x/web3-wrapper'; @@ -20,7 +20,6 @@ import { } from '../types'; import { affiliateFeeUtils } from '../utils/affiliate_fee_utils'; import { assert } from '../utils/assert'; -import { assetDataUtils } from '../utils/asset_data_utils'; import { swapQuoteConsumerUtils } from '../utils/swap_quote_consumer_utils'; import { utils } from '../utils/utils'; @@ -53,10 +52,9 @@ export class ForwarderSwapQuoteConsumer implements SwapQuoteConsumerBase { assert.isValidForwarderSwapQuote('quote', quote, this._getEtherTokenAssetDataOrThrow()); - const { to, methodAbi, ethAmount, params } = await this.getSmartContractParamsOrThrowAsync(quote, opts); + const { toAddress, methodAbi, ethAmount, params } = await this.getSmartContractParamsOrThrowAsync(quote, opts); const abiEncoder = new AbiEncoder.Method(methodAbi); - const { orders, signatures, feeOrders, feeSignatures, feePercentage, feeRecipient } = params; let args: any[]; @@ -66,11 +64,11 @@ export class ForwarderSwapQuoteConsumer implements SwapQuoteConsumerBase o.signature); const feeSignatures = _.map(feeOrders, o => o.signature); @@ -120,10 +115,10 @@ export class ForwarderSwapQuoteConsumer implements SwapQuoteConsumerBase o.signature), feeOrders, - feePercentage, + feeOrders.map(o => o.signature), + formattedFeePercentage, feeRecipient, { - gasLimit, + value, + from: finalTakerAddress.toLowerCase(), + gas: gasLimit, gasPrice, - shouldValidate: true, }, ); } else { - txHash = await this._contractWrappers.forwarder.marketSellOrdersWithEthAsync( + txHash = await this._contractWrappers.forwarder.marketSellOrdersWithEth.validateAndSendTransactionAsync( orders, - finalTakerAddress, - ethAmount || worstCaseQuoteInfo.totalTakerTokenAmount, + orders.map(o => o.signature), feeOrders, - feePercentage, + feeOrders.map(o => o.signature), + formattedFeePercentage, feeRecipient, { - gasLimit, + value, + from: finalTakerAddress.toLowerCase(), + gas: gasLimit, gasPrice, - shouldValidate: true, }, ); } return txHash; } catch (err) { - if (_.includes(err.message, ContractWrappersError.SignatureRequestDenied)) { + if (_.includes(err.message, ContractError.SignatureRequestDenied)) { throw new Error(SwapQuoteConsumerError.SignatureRequestDenied); - } else if (_.includes(err.message, ForwarderWrapperError.CompleteFillFailed)) { + } else if (_.includes(err.message, ForwarderError.CompleteFillFailed)) { throw new Error(SwapQuoteConsumerError.TransactionValueTooLow); } else { throw err; @@ -240,6 +241,6 @@ export class ForwarderSwapQuoteConsumer implements SwapQuoteConsumerBase, @@ -53,6 +58,11 @@ export class SwapQuoteConsumer implements SwapQuoteConsumerBase, @@ -62,6 +72,11 @@ export class SwapQuoteConsumer implements SwapQuoteConsumerBase, @@ -75,19 +90,19 @@ export class SwapQuoteConsumer implements SwapQuoteConsumerBase, ): Promise> { - if (opts.useConsumerType === ConsumerType.Exchange) { - return this._exchangeConsumer; - } else if (opts.useConsumerType === ConsumerType.Forwarder) { - return this._forwarderConsumer; - } else { - return swapQuoteConsumerUtils.getConsumerForSwapQuoteAsync( + const useConsumerType = + opts.useConsumerType || + (await swapQuoteConsumerUtils.getConsumerTypeForSwapQuoteAsync( quote, this._contractWrappers, this.provider, - this._exchangeConsumer, - this._forwarderConsumer, opts, - ); + )); + if (useConsumerType === ConsumerType.Exchange) { + return this._exchangeConsumer; + } else if (useConsumerType === ConsumerType.Forwarder) { + return this._forwarderConsumer; } + return this._exchangeConsumer; } } diff --git a/packages/asset-swapper/src/swap_quoter.ts b/packages/asset-swapper/src/swap_quoter.ts index d48c6d303a..2a1f47cf3a 100644 --- a/packages/asset-swapper/src/swap_quoter.ts +++ b/packages/asset-swapper/src/swap_quoter.ts @@ -1,6 +1,6 @@ import { ContractWrappers } from '@0x/contract-wrappers'; import { schemas } from '@0x/json-schemas'; -import { SignedOrder } from '@0x/order-utils'; +import { assetDataUtils, SignedOrder } from '@0x/order-utils'; import { MarketOperation, ObjectMap } from '@0x/types'; import { BigNumber, providerUtils } from '@0x/utils'; import { SupportedProvider, ZeroExProvider } from 'ethereum-types'; @@ -23,7 +23,6 @@ import { } from './types'; import { assert } from './utils/assert'; -import { assetDataUtils } from './utils/asset_data_utils'; import { calculateLiquidity } from './utils/calculate_liquidity'; import { orderProviderResponseProcessor } from './utils/order_provider_response_processor'; import { swapQuoteCalculator } from './utils/swap_quote_calculator'; @@ -373,18 +372,24 @@ export class SwapQuoter { return ordersAndFillableAmounts; } + /** + * Util function to check if takerAddress's allowance is enough for 0x exchange contracts to conduct the swap specified by the swapQuote. + * @param swapQuote The swapQuote in question to check enough allowance enabled for 0x exchange contracts to conduct the swap. + * @param takerAddress The address of the taker of the provided swapQuote + */ public async isTakerAddressAllowanceEnoughForBestAndWorstQuoteInfoAsync( swapQuote: SwapQuote, takerAddress: string, ): Promise<[boolean, boolean]> { - const orderValidatorWrapper = this._contractWrappers.orderValidator; - const balanceAndAllowance = await orderValidatorWrapper.getBalanceAndAllowanceAsync( + const orderValidator = this._contractWrappers.orderValidator; + const balanceAndAllowance = await orderValidator.getBalanceAndAllowance.callAsync( takerAddress, swapQuote.takerAssetData, ); + const allowance = balanceAndAllowance[1]; return [ - balanceAndAllowance.allowance.isGreaterThanOrEqualTo(swapQuote.bestCaseQuoteInfo.totalTakerTokenAmount), - balanceAndAllowance.allowance.isGreaterThanOrEqualTo(swapQuote.worstCaseQuoteInfo.totalTakerTokenAmount), + allowance.isGreaterThanOrEqualTo(swapQuote.bestCaseQuoteInfo.totalTakerTokenAmount), + allowance.isGreaterThanOrEqualTo(swapQuote.worstCaseQuoteInfo.totalTakerTokenAmount), ]; } @@ -393,7 +398,7 @@ export class SwapQuoter { * Will throw if ZRX does not exist for the current network. */ private _getZrxTokenAssetDataOrThrow(): string { - return this._contractWrappers.exchange.getZRXAssetData(); + return assetDataUtils.encodeERC20AssetData(this._contractWrappers.contractAddresses.zrxToken); } /** diff --git a/packages/asset-swapper/src/types.ts b/packages/asset-swapper/src/types.ts index cf7502746d..29e13b8dd7 100644 --- a/packages/asset-swapper/src/types.ts +++ b/packages/asset-swapper/src/types.ts @@ -43,26 +43,26 @@ export interface OrderProvider { * Represents the metadata to call a smart contract with calldata. * calldataHexString: The hexstring of the calldata. * methodAbi: The ABI of the smart contract method to call. - * to: The contract address to call. + * toAddress: The contract address to call. * ethAmount: If provided, the eth amount in wei to send with the smart contract call. */ export interface CalldataInfo { calldataHexString: string; methodAbi: MethodAbi; - to: string; + toAddress: string; ethAmount?: BigNumber; } /** * Represents the metadata to call a smart contract with parameters. * params: The metadata object containing all the input parameters of a smart contract call. - * to: The contract address to call. + * toAddress: The contract address to call. * ethAmount: If provided, the eth amount in wei to send with the smart contract call. * methodAbi: The ABI of the smart contract method to call with params. */ export interface SmartContractParamsInfo { params: T; - to: string; + toAddress: string; ethAmount?: BigNumber; methodAbi: MethodAbi; } @@ -256,9 +256,10 @@ export interface MarketBuySwapQuoteWithAffiliateFee extends SwapQuoteWithAffilia export type SwapQuoteWithAffiliateFee = MarketBuySwapQuoteWithAffiliateFee | MarketSellSwapQuoteWithAffiliateFee; /** - * assetEthAmount: The amount of eth required to pay for the requested asset. - * feeEthAmount: The amount of eth required to pay any fee concerned with completing the swap. - * totalEthAmount: The total amount of eth required to complete the buy (filling orders, feeOrders, and paying affiliate fee). + * feeTakerTokenAmount: The amount of takerToken required any fee concerned with completing the swap. + * takerTokenAmount: The amount of takerToken required to conduct the swap. + * totalTakerTokenAmount: The total amount of takerToken required to complete the swap (filling orders, feeOrders, and paying affiliate fee) + * makerTokenAmount: The amount of makerToken that will be acquired through the swap. */ export interface SwapQuoteInfo { feeTakerTokenAmount: BigNumber; diff --git a/packages/asset-swapper/src/utils/assert.ts b/packages/asset-swapper/src/utils/assert.ts index 7a23fd464b..758ea253e6 100644 --- a/packages/asset-swapper/src/utils/assert.ts +++ b/packages/asset-swapper/src/utils/assert.ts @@ -12,6 +12,12 @@ export const assert = { sharedAssert.isHexString(`${variableName}.makerAssetData`, swapQuote.makerAssetData); sharedAssert.doesConformToSchema(`${variableName}.orders`, swapQuote.orders, schemas.signedOrdersSchema); sharedAssert.doesConformToSchema(`${variableName}.feeOrders`, swapQuote.feeOrders, schemas.signedOrdersSchema); + assert.isValidOrdersForSwapQuote( + `${variableName}.orders`, + swapQuote.orders, + swapQuote.makerAssetData, + swapQuote.takerAssetData, + ); assert.isValidSwapQuoteInfo(`${variableName}.bestCaseQuoteInfo`, swapQuote.bestCaseQuoteInfo); assert.isValidSwapQuoteInfo(`${variableName}.worstCaseQuoteInfo`, swapQuote.worstCaseQuoteInfo); if (swapQuote.type === MarketOperation.Buy) { @@ -20,6 +26,27 @@ export const assert = { sharedAssert.isBigNumber(`${variableName}.takerAssetFillAmount`, swapQuote.takerAssetFillAmount); } }, + isValidOrdersForSwapQuote( + variableName: string, + orders: SignedOrder[], + makerAssetData: string, + takerAssetData: string, + ): void { + _.every(orders, (order: SignedOrder, index: number) => { + assert.assert( + order.takerAssetData === takerAssetData, + `Expected ${variableName}[${index}].takerAssetData to be ${takerAssetData} but found ${ + order.takerAssetData + }`, + ); + assert.assert( + order.makerAssetData === makerAssetData, + `Expected ${variableName}[${index}].makerAssetData to be ${makerAssetData} but found ${ + order.makerAssetData + }`, + ); + }); + }, isValidForwarderSwapQuote(variableName: string, swapQuote: SwapQuote, wethAssetData: string): void { assert.isValidSwapQuote(variableName, swapQuote); assert.isValidForwarderSignedOrders(`${variableName}.orders`, swapQuote.orders, wethAssetData); diff --git a/packages/asset-swapper/src/utils/asset_data_utils.ts b/packages/asset-swapper/src/utils/asset_data_utils.ts deleted file mode 100644 index 70f6469020..0000000000 --- a/packages/asset-swapper/src/utils/asset_data_utils.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ContractWrappers } from '@0x/contract-wrappers'; -import { assetDataUtils as sharedAssetDataUtils } from '@0x/order-utils'; -import * as _ from 'lodash'; - -export const assetDataUtils = { - ...sharedAssetDataUtils, - getEtherTokenAssetData(contractWrappers: ContractWrappers): string { - const etherTokenAddress = contractWrappers.forwarder.etherTokenAddress; - const etherTokenAssetData = sharedAssetDataUtils.encodeERC20AssetData(etherTokenAddress); - return etherTokenAssetData; - }, -}; diff --git a/packages/asset-swapper/src/utils/order_provider_response_processor.ts b/packages/asset-swapper/src/utils/order_provider_response_processor.ts index 16dfe4bc1f..42d2f36f57 100644 --- a/packages/asset-swapper/src/utils/order_provider_response_processor.ts +++ b/packages/asset-swapper/src/utils/order_provider_response_processor.ts @@ -1,4 +1,4 @@ -import { OrderAndTraderInfo, OrderStatus, OrderValidatorWrapper } from '@0x/contract-wrappers'; +import { OrderAndTraderInfo, OrderStatus, OrderValidatorContract } from '@0x/contract-wrappers'; import { orderCalculationUtils, sortingUtils } from '@0x/order-utils'; import { RemainingFillableCalculator } from '@0x/order-utils/lib/src/remaining_fillable_calculator'; import { SignedOrder } from '@0x/types'; @@ -34,7 +34,7 @@ export const orderProviderResponseProcessor = { orderProviderResponse: OrderProviderResponse, isMakerAssetZrxToken: boolean, expiryBufferMs: number, - orderValidator?: OrderValidatorWrapper, + orderValidator?: OrderValidatorContract, ): Promise { // drop orders that are expired or not open const filteredOrders = filterOutExpiredAndNonOpenOrders( @@ -47,10 +47,17 @@ export const orderProviderResponseProcessor = { if (orderValidator !== undefined) { const takerAddresses = _.map(filteredOrders, () => constants.NULL_ADDRESS); try { - const ordersAndTradersInfo = await orderValidator.getOrdersAndTradersInfoAsync( + const [ordersInfo, tradersInfo] = await orderValidator.getOrdersAndTradersInfo.callAsync( filteredOrders, takerAddresses, ); + const ordersAndTradersInfo: OrderAndTraderInfo[] = ordersInfo.map((orderInfo, index) => { + const singleOrderAndTraderInfo: OrderAndTraderInfo = { + orderInfo, + traderInfo: tradersInfo[index], + }; + return singleOrderAndTraderInfo; + }); // take orders + on chain information and find the valid orders and remaining fillable maker asset amounts unsortedOrders = getValidOrdersWithRemainingFillableMakerAssetAmountsFromOnChain( filteredOrders, diff --git a/packages/asset-swapper/src/utils/swap_quote_calculator.ts b/packages/asset-swapper/src/utils/swap_quote_calculator.ts index 81a65b5f8a..9ae521f355 100644 --- a/packages/asset-swapper/src/utils/swap_quote_calculator.ts +++ b/packages/asset-swapper/src/utils/swap_quote_calculator.ts @@ -220,7 +220,7 @@ function calculateQuoteInfo( let takerTokenAmount = marketOperation === MarketOperation.Sell ? tokenAmount : constants.ZERO_AMOUNT; let zrxTakerTokenAmount = constants.ZERO_AMOUNT; - if (!shouldDisableFeeOrderCalculations && isMakerAssetZrxToken) { + if (isMakerAssetZrxToken) { if (marketOperation === MarketOperation.Buy) { takerTokenAmount = findTakerTokenAmountNeededToBuyZrx(ordersAndFillableAmounts, makerTokenAmount); } else { @@ -229,7 +229,7 @@ function calculateQuoteInfo( takerTokenAmount, ); } - } else if (!shouldDisableFeeOrderCalculations) { + } else { const findTokenAndZrxAmount = marketOperation === MarketOperation.Buy ? findTakerTokenAndZrxAmountNeededToBuyAsset @@ -246,7 +246,9 @@ function calculateQuoteInfo( } const zrxAmountToBuyAsset = tokenAndZrxAmountToBuyAsset[1]; // find eth amount needed to buy zrx - zrxTakerTokenAmount = findTakerTokenAmountNeededToBuyZrx(feeOrdersAndFillableAmounts, zrxAmountToBuyAsset); + zrxTakerTokenAmount = shouldDisableFeeOrderCalculations + ? constants.ZERO_AMOUNT + : findTakerTokenAmountNeededToBuyZrx(feeOrdersAndFillableAmounts, zrxAmountToBuyAsset); } const feeTakerTokenAmount = zrxTakerTokenAmount; diff --git a/packages/asset-swapper/src/utils/swap_quote_consumer_utils.ts b/packages/asset-swapper/src/utils/swap_quote_consumer_utils.ts index 66c3eea345..8420f2ad93 100644 --- a/packages/asset-swapper/src/utils/swap_quote_consumer_utils.ts +++ b/packages/asset-swapper/src/utils/swap_quote_consumer_utils.ts @@ -1,24 +1,21 @@ import { ContractWrappers } from '@0x/contract-wrappers'; -import { SignedOrder } from '@0x/types'; +import { assetDataUtils } from '@0x/order-utils'; +import { MarketOperation, SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; import { SupportedProvider, Web3Wrapper } from '@0x/web3-wrapper'; import { Provider } from 'ethereum-types'; import * as _ from 'lodash'; import { constants } from '../constants'; -import { ExchangeSwapQuoteConsumer } from '../quote_consumers/exchange_swap_quote_consumer'; -import { ForwarderSwapQuoteConsumer } from '../quote_consumers/forwarder_swap_quote_consumer'; import { - SmartContractParams, + ConsumerType, SwapQuote, - SwapQuoteConsumerBase, SwapQuoteConsumerError, SwapQuoteExecutionOpts, SwapQuoteGetOutputOpts, } from '../types'; import { assert } from './assert'; -import { assetDataUtils } from './asset_data_utils'; export const swapQuoteConsumerUtils = { async getTakerAddressOrThrowAsync( @@ -55,9 +52,8 @@ export const swapQuoteConsumerUtils = { takerAddress: string, ): Promise<[BigNumber, BigNumber]> { const web3Wrapper = new Web3Wrapper(provider); - const wethAddress = contractWrappers.forwarder.etherTokenAddress; const ethBalance = await web3Wrapper.getBalanceInWeiAsync(takerAddress); - const wethBalance = await contractWrappers.erc20Token.getBalanceAsync(wethAddress, takerAddress); + const wethBalance = await contractWrappers.weth9.balanceOf.callAsync(takerAddress); return [ethBalance, wethBalance]; }, isValidForwarderSwapQuote(swapQuote: SwapQuote, wethAssetData: string): boolean { @@ -72,15 +68,24 @@ export const swapQuoteConsumerUtils = { isValidForwarderSignedOrder(order: SignedOrder, wethAssetData: string): boolean { return order.takerAssetData === wethAssetData; }, - async getConsumerForSwapQuoteAsync( + optimizeOrdersForMarketExchangeOperation(orders: SignedOrder[], operation: MarketOperation): SignedOrder[] { + return _.map(orders, (order: SignedOrder, index: number) => { + const optimizedOrder = _.clone(order); + if (operation === MarketOperation.Sell && index !== 0) { + optimizedOrder.takerAssetData = constants.NULL_BYTES; + } else if (index !== 0) { + optimizedOrder.makerAssetData = constants.NULL_BYTES; + } + return optimizedOrder; + }); + }, + async getConsumerTypeForSwapQuoteAsync( quote: SwapQuote, contractWrappers: ContractWrappers, provider: Provider, - exchangeConsumer: ExchangeSwapQuoteConsumer, - forwarderConsumer: ForwarderSwapQuoteConsumer, opts: Partial, - ): Promise> { - const wethAssetData = assetDataUtils.getEtherTokenAssetData(contractWrappers); + ): Promise { + const wethAssetData = assetDataUtils.encodeERC20AssetData(contractWrappers.contractAddresses.etherToken); if (swapQuoteConsumerUtils.isValidForwarderSwapQuote(quote, wethAssetData)) { if (opts.takerAddress !== undefined) { assert.isETHAddressHex('takerAddress', opts.takerAddress); @@ -97,14 +102,14 @@ export const swapQuoteConsumerUtils = { ); if (isEnoughEthAndWethBalance[1]) { // should be more gas efficient to use exchange consumer, so if possible use it. - return exchangeConsumer; + return ConsumerType.Exchange; } else if (isEnoughEthAndWethBalance[0] && !isEnoughEthAndWethBalance[1]) { - return forwarderConsumer; + return ConsumerType.Forwarder; } // Note: defaulting to forwarderConsumer if takerAddress is null or not enough balance of either wEth or Eth - return forwarderConsumer; + return ConsumerType.Forwarder; } else { - return exchangeConsumer; + return ConsumerType.Exchange; } }, }; diff --git a/packages/asset-swapper/test/affiliate_fee_utils_test.ts b/packages/asset-swapper/test/affiliate_fee_utils_test.ts new file mode 100644 index 0000000000..a321eb95a6 --- /dev/null +++ b/packages/asset-swapper/test/affiliate_fee_utils_test.ts @@ -0,0 +1,92 @@ +import { MarketOperation } from '@0x/types'; +import { BigNumber } from '@0x/utils'; +import * as chai from 'chai'; +import 'mocha'; + +import { constants } from '../src/constants'; +import { affiliateFeeUtils } from '../src/utils/affiliate_fee_utils'; + +import { chaiSetup } from './utils/chai_setup'; +import { + getFullyFillableSwapQuoteWithFees, + getFullyFillableSwapQuoteWithNoFees, + getPartialSignedOrdersWithFees, + getPartialSignedOrdersWithNoFees, +} from './utils/swap_quote'; + +chaiSetup.configure(); +const expect = chai.expect; + +const FAKE_TAKER_ASSET_DATA = '0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48'; +const FAKE_MAKER_ASSET_DATA = '0xf47261b00000000000000000000000009f5B0C7e1623793bF0620569b9749e79DF6D0bC5'; +const NULL_ADDRESS = constants.NULL_ADDRESS; +const FEE_PERCENTAGE = 0.1; +const FILLABLE_AMOUNTS = [new BigNumber(2), new BigNumber(3), new BigNumber(5)]; +const FILLABLE_FEE_AMOUNTS = [new BigNumber(1), new BigNumber(1), new BigNumber(1)]; +const MARKET_OPERATION = MarketOperation.Sell; + +describe('affiliateFeeUtils', () => { + const fakeFeeOrders = getPartialSignedOrdersWithNoFees( + FAKE_MAKER_ASSET_DATA, + FAKE_TAKER_ASSET_DATA, + NULL_ADDRESS, + NULL_ADDRESS, + FILLABLE_FEE_AMOUNTS, + ); + const fakeOrders = getPartialSignedOrdersWithNoFees( + FAKE_MAKER_ASSET_DATA, + FAKE_TAKER_ASSET_DATA, + NULL_ADDRESS, + NULL_ADDRESS, + FILLABLE_AMOUNTS, + ); + + const fakeOrdersWithFees = getPartialSignedOrdersWithFees( + FAKE_MAKER_ASSET_DATA, + FAKE_TAKER_ASSET_DATA, + NULL_ADDRESS, + NULL_ADDRESS, + FILLABLE_AMOUNTS, + FILLABLE_FEE_AMOUNTS, + ); + + const fakeSwapQuote = getFullyFillableSwapQuoteWithNoFees( + FAKE_MAKER_ASSET_DATA, + FAKE_TAKER_ASSET_DATA, + fakeOrders, + MARKET_OPERATION, + ); + + const fakeSwapQuoteWithFees = getFullyFillableSwapQuoteWithFees( + FAKE_MAKER_ASSET_DATA, + FAKE_TAKER_ASSET_DATA, + fakeOrdersWithFees, + fakeFeeOrders, + MARKET_OPERATION, + ); + + describe('getSwapQuoteWithAffiliateFee', () => { + it('should return unchanged swapQuote if feePercentage is 0', () => { + const updatedSwapQuote = affiliateFeeUtils.getSwapQuoteWithAffiliateFee(fakeSwapQuote, 0); + const fakeSwapQuoteWithAffiliateFees = { ...fakeSwapQuote, ...{ feePercentage: 0 } }; + expect(updatedSwapQuote).to.deep.equal(fakeSwapQuoteWithAffiliateFees); + }); + it('should return correct feeTakerToken and totalTakerToken amounts when provided SwapQuote with no fees', () => { + const updatedSwapQuote = affiliateFeeUtils.getSwapQuoteWithAffiliateFee(fakeSwapQuote, FEE_PERCENTAGE); + expect(updatedSwapQuote.bestCaseQuoteInfo.feeTakerTokenAmount).to.deep.equal(new BigNumber(1)); + expect(updatedSwapQuote.bestCaseQuoteInfo.totalTakerTokenAmount).to.deep.equal(new BigNumber(11)); + expect(updatedSwapQuote.worstCaseQuoteInfo.feeTakerTokenAmount).to.deep.equal(new BigNumber(1)); + expect(updatedSwapQuote.worstCaseQuoteInfo.totalTakerTokenAmount).to.deep.equal(new BigNumber(11)); + }); + it('should return correct feeTakerToken and totalTakerToken amounts when provides SwapQuote with fees', () => { + const updatedSwapQuote = affiliateFeeUtils.getSwapQuoteWithAffiliateFee( + fakeSwapQuoteWithFees, + FEE_PERCENTAGE, + ); + expect(updatedSwapQuote.bestCaseQuoteInfo.feeTakerTokenAmount).to.deep.equal(new BigNumber(4)); + expect(updatedSwapQuote.bestCaseQuoteInfo.totalTakerTokenAmount).to.deep.equal(new BigNumber(14)); + expect(updatedSwapQuote.worstCaseQuoteInfo.feeTakerTokenAmount).to.deep.equal(new BigNumber(4)); + expect(updatedSwapQuote.worstCaseQuoteInfo.totalTakerTokenAmount).to.deep.equal(new BigNumber(14)); + }); + }); +}); diff --git a/packages/asset-swapper/test/exchange_swap_quote_consumer_test.ts b/packages/asset-swapper/test/exchange_swap_quote_consumer_test.ts new file mode 100644 index 0000000000..553c1990af --- /dev/null +++ b/packages/asset-swapper/test/exchange_swap_quote_consumer_test.ts @@ -0,0 +1,231 @@ +import { ContractAddresses, ContractWrappers, ERC20TokenContract } from '@0x/contract-wrappers'; +import { BlockchainLifecycle, tokenUtils } from '@0x/dev-utils'; +import { FillScenarios } from '@0x/fill-scenarios'; +import { assetDataUtils } from '@0x/order-utils'; +import { MarketOperation, SignedOrder } from '@0x/types'; +import { BigNumber } from '@0x/utils'; +import * as chai from 'chai'; +import 'mocha'; + +import { SwapQuote } from '../src'; +import { constants } from '../src/constants'; +import { ExchangeSwapQuoteConsumer } from '../src/quote_consumers/exchange_swap_quote_consumer'; +import { + ExchangeMarketBuySmartContractParams, + ExchangeMarketSellSmartContractParams, + MarketBuySwapQuote, + MarketSellSwapQuote, +} from '../src/types'; + +import { chaiSetup } from './utils/chai_setup'; +import { migrateOnceAsync } from './utils/migrate'; +import { getFullyFillableSwapQuoteWithNoFees } from './utils/swap_quote'; +import { provider, web3Wrapper } from './utils/web3_wrapper'; + +chaiSetup.configure(); +const expect = chai.expect; +const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); + +const ONE_ETH_IN_WEI = new BigNumber(1000000000000000000); +const TESTRPC_NETWORK_ID = 50; +const FILLABLE_AMOUNTS = [new BigNumber(3), new BigNumber(2), new BigNumber(5)].map(value => + value.multipliedBy(ONE_ETH_IN_WEI), +); + +describe('ExchangeSwapQuoteConsumer', () => { + let contractWrappers: ContractWrappers; + let userAddresses: string[]; + let erc20TokenContract: ERC20TokenContract; + let coinbaseAddress: string; + let makerAddress: string; + let takerAddress: string; + let fillScenarios: FillScenarios; + let feeRecipient: string; + let makerTokenAddress: string; + let takerTokenAddress: string; + let makerAssetData: string; + let takerAssetData: string; + let wethAssetData: string; + let contractAddresses: ContractAddresses; + + const networkId = TESTRPC_NETWORK_ID; + + let orders: SignedOrder[]; + let marketSellSwapQuote: SwapQuote; + let marketBuySwapQuote: SwapQuote; + let swapQuoteConsumer: ExchangeSwapQuoteConsumer; + + before(async () => { + contractAddresses = await migrateOnceAsync(); + await blockchainLifecycle.startAsync(); + userAddresses = await web3Wrapper.getAvailableAddressesAsync(); + fillScenarios = new FillScenarios( + provider, + userAddresses, + contractAddresses.zrxToken, + contractAddresses.exchange, + contractAddresses.erc20Proxy, + contractAddresses.erc721Proxy, + ); + const config = { + networkId, + contractAddresses, + }; + contractWrappers = new ContractWrappers(provider, config); + [coinbaseAddress, takerAddress, makerAddress, feeRecipient] = userAddresses; + [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); + [makerAssetData, takerAssetData, wethAssetData] = [ + assetDataUtils.encodeERC20AssetData(makerTokenAddress), + assetDataUtils.encodeERC20AssetData(takerTokenAddress), + assetDataUtils.encodeERC20AssetData(contractAddresses.etherToken), + ]; + erc20TokenContract = new ERC20TokenContract(makerTokenAddress, provider); + }); + after(async () => { + await blockchainLifecycle.revertAsync(); + }); + beforeEach(async () => { + await blockchainLifecycle.startAsync(); + orders = []; + for (const fillableAmmount of FILLABLE_AMOUNTS) { + const order = await fillScenarios.createFillableSignedOrderAsync( + makerAssetData, + takerAssetData, + makerAddress, + takerAddress, + fillableAmmount, + ); + orders.push(order); + } + + marketSellSwapQuote = getFullyFillableSwapQuoteWithNoFees( + makerAssetData, + takerAssetData, + orders, + MarketOperation.Sell, + ); + + marketBuySwapQuote = getFullyFillableSwapQuoteWithNoFees( + makerAssetData, + takerAssetData, + orders, + MarketOperation.Buy, + ); + + swapQuoteConsumer = new ExchangeSwapQuoteConsumer(provider, { + networkId, + }); + }); + afterEach(async () => { + await blockchainLifecycle.revertAsync(); + }); + describe('executeSwapQuoteOrThrowAsync', () => { + /* + * Testing that SwapQuoteConsumer logic correctly performs a execution (doesn't throw or revert) + * Does not test the validity of the state change performed by the forwarder smart contract + */ + it('should perform a marketSell execution when provided a MarketSell type swapQuote', async () => { + let makerBalance = await erc20TokenContract.balanceOf.callAsync(makerAddress); + let takerBalance = await erc20TokenContract.balanceOf.callAsync(takerAddress); + expect(makerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI)); + expect(takerBalance).to.bignumber.equal(constants.ZERO_AMOUNT); + await swapQuoteConsumer.executeSwapQuoteOrThrowAsync(marketSellSwapQuote, { takerAddress }); + makerBalance = await erc20TokenContract.balanceOf.callAsync(makerAddress); + takerBalance = await erc20TokenContract.balanceOf.callAsync(takerAddress); + expect(takerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI)); + expect(makerBalance).to.bignumber.equal(constants.ZERO_AMOUNT); + }); + it('should perform a marketBuy execution when provided a MarketBuy type swapQuote', async () => { + let makerBalance = await erc20TokenContract.balanceOf.callAsync(makerAddress); + let takerBalance = await erc20TokenContract.balanceOf.callAsync(takerAddress); + expect(makerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI)); + expect(takerBalance).to.bignumber.equal(constants.ZERO_AMOUNT); + await swapQuoteConsumer.executeSwapQuoteOrThrowAsync(marketBuySwapQuote, { takerAddress }); + makerBalance = await erc20TokenContract.balanceOf.callAsync(makerAddress); + takerBalance = await erc20TokenContract.balanceOf.callAsync(takerAddress); + expect(takerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI)); + expect(makerBalance).to.bignumber.equal(constants.ZERO_AMOUNT); + }); + }); + + describe('getSmartContractParamsOrThrow', () => { + describe('valid swap quote', async () => { + // TODO(david) Check for valid MethodAbi + it('provide correct and optimized smart contract params for a marketSell SwapQuote', async () => { + const { toAddress, params } = await swapQuoteConsumer.getSmartContractParamsOrThrowAsync( + marketSellSwapQuote, + {}, + ); + expect(toAddress).to.deep.equal(contractWrappers.exchange.address); + const { takerAssetFillAmount, signatures, type } = params as ExchangeMarketSellSmartContractParams; + expect(type).to.deep.equal(MarketOperation.Sell); + expect(takerAssetFillAmount).to.bignumber.equal( + (marketSellSwapQuote as MarketSellSwapQuote).takerAssetFillAmount, + ); + const orderSignatures = marketSellSwapQuote.orders.map(order => order.signature); + expect(signatures).to.deep.equal(orderSignatures); + }); + it('provide correct and optimized smart contract params for a marketBuy SwapQuote', async () => { + const { toAddress, params } = await swapQuoteConsumer.getSmartContractParamsOrThrowAsync( + marketBuySwapQuote, + {}, + ); + expect(toAddress).to.deep.equal(contractWrappers.exchange.address); + const { makerAssetFillAmount, signatures, type } = params as ExchangeMarketBuySmartContractParams; + expect(type).to.deep.equal(MarketOperation.Buy); + expect(makerAssetFillAmount).to.bignumber.equal( + (marketBuySwapQuote as MarketBuySwapQuote).makerAssetFillAmount, + ); + const orderSignatures = marketSellSwapQuote.orders.map(order => order.signature); + expect(signatures).to.deep.equal(orderSignatures); + }); + }); + }); + + describe('getCalldataOrThrow', () => { + describe('valid swap quote', async () => { + it('provide correct and optimized calldata options with default options for a marketSell SwapQuote (no affiliate fees)', async () => { + let makerBalance = await erc20TokenContract.balanceOf.callAsync(makerAddress); + let takerBalance = await erc20TokenContract.balanceOf.callAsync(takerAddress); + expect(makerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI)); + expect(takerBalance).to.bignumber.equal(constants.ZERO_AMOUNT); + const { calldataHexString, toAddress } = await swapQuoteConsumer.getCalldataOrThrowAsync( + marketSellSwapQuote, + {}, + ); + expect(toAddress).to.deep.equal(contractWrappers.exchange.address); + await web3Wrapper.sendTransactionAsync({ + from: takerAddress, + to: toAddress, + data: calldataHexString, + gas: 4000000, + }); + makerBalance = await erc20TokenContract.balanceOf.callAsync(makerAddress); + takerBalance = await erc20TokenContract.balanceOf.callAsync(takerAddress); + expect(takerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI)); + expect(makerBalance).to.bignumber.equal(constants.ZERO_AMOUNT); + }); + it('provide correct and optimized calldata options with default options for a marketBuy SwapQuote (no affiliate fees)', async () => { + let makerBalance = await erc20TokenContract.balanceOf.callAsync(makerAddress); + let takerBalance = await erc20TokenContract.balanceOf.callAsync(takerAddress); + expect(makerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI)); + expect(takerBalance).to.bignumber.equal(constants.ZERO_AMOUNT); + const { calldataHexString, toAddress } = await swapQuoteConsumer.getCalldataOrThrowAsync( + marketBuySwapQuote, + {}, + ); + expect(toAddress).to.deep.equal(contractWrappers.exchange.address); + await web3Wrapper.sendTransactionAsync({ + from: takerAddress, + to: toAddress, + data: calldataHexString, + gas: 4000000, + }); + makerBalance = await erc20TokenContract.balanceOf.callAsync(makerAddress); + takerBalance = await erc20TokenContract.balanceOf.callAsync(takerAddress); + expect(takerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI)); + expect(makerBalance).to.bignumber.equal(constants.ZERO_AMOUNT); + }); + }); + }); +}); diff --git a/packages/asset-swapper/test/forwarder_swap_quote_consumer_test.ts b/packages/asset-swapper/test/forwarder_swap_quote_consumer_test.ts index 02cbf83d65..c4ed8f1bcd 100644 --- a/packages/asset-swapper/test/forwarder_swap_quote_consumer_test.ts +++ b/packages/asset-swapper/test/forwarder_swap_quote_consumer_test.ts @@ -1,136 +1,418 @@ -// import { tokenUtils } from '@0x/contract-wrappers/lib/test/utils/token_utils'; -// import { BlockchainLifecycle } from '@0x/dev-utils'; -// import { FillScenarios } from '@0x/fill-scenarios'; -// import { assetDataUtils } from '@0x/order-utils'; -// import { BigNumber } from '@0x/utils'; -// import 'mocha'; +import { ContractAddresses, ContractWrappers, ERC20TokenContract } from '@0x/contract-wrappers'; +import { BlockchainLifecycle, tokenUtils } from '@0x/dev-utils'; +import { assetDataUtils } from '@0x/order-utils'; +import { MarketOperation, SignedOrder } from '@0x/types'; +import { BigNumber } from '@0x/utils'; +import * as chai from 'chai'; +import 'mocha'; -// import { ForwarderSwapQuoteConsumer } from '../src'; +import { SwapQuote } from '../src'; +import { constants } from '../src/constants'; +import { ForwarderSwapQuoteConsumer } from '../src/quote_consumers/forwarder_swap_quote_consumer'; +import { + ForwarderMarketBuySmartContractParams, + ForwarderMarketSellSmartContractParams, + MarketBuySwapQuote, +} from '../src/types'; -// import { chaiSetup } from './utils/chai_setup'; -// import { migrateOnceAsync } from './utils/migrate'; -// import { getFullyFillableSwapQuoteWithNoFees, getSignedOrdersWithNoFees } from './utils/swap_quote'; -// import { provider, web3Wrapper } from './utils/web3_wrapper'; +import { chaiSetup } from './utils/chai_setup'; +import { migrateOnceAsync } from './utils/migrate'; +import { getFullyFillableSwapQuoteWithNoFees, getSignedOrdersWithNoFeesAsync } from './utils/swap_quote'; +import { provider, web3Wrapper } from './utils/web3_wrapper'; -// chaiSetup.configure(); -// const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); +chaiSetup.configure(); +const expect = chai.expect; +const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); -// const FILLABLE_AMOUNTS = [new BigNumber(5), new BigNumber(10)]; -// const TESTRPC_NETWORK_ID = 50; +const ONE_ETH_IN_WEI = new BigNumber(1000000000000000000); +const TESTRPC_NETWORK_ID = 50; +const MARKET_OPERATION = MarketOperation.Sell; +const FILLABLE_AMOUNTS = [new BigNumber(2), new BigNumber(3), new BigNumber(5)].map(value => + value.multipliedBy(ONE_ETH_IN_WEI), +); +const UNLIMITED_ALLOWANCE_IN_BASE_UNITS = new BigNumber(2).pow(256).minus(1); // tslint:disable-line:custom-no-magic-numbers -// describe('ForwarderSwapQuoteConsumer', () => { -// // let userAddresses: string[]; -// // let makerAddress: string; -// // let takerAddress: string; -// // let fillScenarios: FillScenarios; -// // let feeRecipient: string; -// // let makerAssetData: string; -// // let takerAssetData: string; -// // let wethAssetData: string; -// // const networkId = TESTRPC_NETWORK_ID; -// before(async () => { -// // const contractAddresses = await migrateOnceAsync(); -// // await blockchainLifecycle.startAsync(); -// // userAddresses = await web3Wrapper.getAvailableAddressesAsync(); -// // fillScenarios = new FillScenarios( -// // provider, -// // userAddresses, -// // contractAddresses.zrxToken, -// // contractAddresses.exchange, -// // contractAddresses.erc20Proxy, -// // contractAddresses.erc721Proxy, -// // ); -// // [makerAddress, takerAddress, feeRecipient] = userAddresses; -// // const [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); -// // [makerAssetData, takerAssetData, wethAssetData] = [ -// // assetDataUtils.encodeERC20AssetData(makerTokenAddress), -// // assetDataUtils.encodeERC20AssetData(takerTokenAddress), -// // assetDataUtils.encodeERC20AssetData(contractAddresses.etherToken), -// // ]; -// }); -// after(async () => { -// // await blockchainLifecycle.revertAsync(); -// }); -// beforeEach(async () => { -// // await blockchainLifecycle.startAsync(); -// // This constructor has incorrect types -// }); -// afterEach(async () => { -// // await blockchainLifecycle.revertAsync(); -// }); -// describe('getSmartContractParamsOrThrow', () => { +describe('ForwarderSwapQuoteConsumer', () => { + let contractWrappers: ContractWrappers; + let erc20Token: ERC20TokenContract; + let userAddresses: string[]; + let coinbaseAddress: string; + let makerAddress: string; + let takerAddress: string; + let feeRecipient: string; + let makerTokenAddress: string; + let takerTokenAddress: string; + let makerAssetData: string; + let takerAssetData: string; + let wethAssetData: string; + let contractAddresses: ContractAddresses; -// describe('validation', () => { -// it('should throw if swap quote provided is not a valid forwarder SwapQuote (taker asset is WETH)', async () => { -// // const invalidSignedOrders = getSignedOrdersWithNoFees( -// // makerAssetData, -// // takerAssetData, -// // makerAddress, -// // takerAddress, -// // FILLABLE_AMOUNTS, -// // ); -// // const invalidSwapQuote = getFullyFillableSwapQuoteWithNoFees(makerAssetData, takerAssetData, invalidSignedOrders); -// // const swapQuoteConsumer = new ForwarderSwapQuoteConsumer(provider, {}); -// // TODO(dave4506) finish up testing/coverage -// // expect( -// // swapQuoteConsumer.getSmartContractParamsOrThrow(invalidSwapQuote, {}), -// // ).to.throws(); -// }); -// }); + let orders: SignedOrder[]; + let marketSellSwapQuote: SwapQuote; + let marketBuySwapQuote: SwapQuote; + let swapQuoteConsumer: ForwarderSwapQuoteConsumer; + let erc20ProxyAddress: string; -// describe('valid swap quote', async () => { -// it('provide correct smart contract params with default options', async () => { -// // const signedOrders = getSignedOrdersWithNoFees( -// // makerAssetData, -// // wethAssetData, -// // makerAddress, -// // takerAddress, -// // FILLABLE_AMOUNTS, -// // ); -// // const swapQuote = getFullyFillableSwapQuoteWithNoFees(makerAssetData, takerAssetData, signedOrders); -// // const swapQuoteConsumer = new ForwarderSwapQuoteConsumer(provider, { networkId }); -// // const smartContractParamsInfo = await swapQuoteConsumer.getSmartContractParamsOrThrowAsync(swapQuote, {}); -// // console.log(smartContractParamsInfo); -// // TODO(dave4506): Add elaborate testing -// }); -// }); -// }); + const networkId = TESTRPC_NETWORK_ID; + before(async () => { + contractAddresses = await migrateOnceAsync(); + await blockchainLifecycle.startAsync(); + userAddresses = await web3Wrapper.getAvailableAddressesAsync(); + const config = { + networkId, + contractAddresses, + }; + contractWrappers = new ContractWrappers(provider, config); + [coinbaseAddress, takerAddress, makerAddress, feeRecipient] = userAddresses; + [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); + erc20Token = new ERC20TokenContract(makerTokenAddress, provider); + [makerAssetData, takerAssetData, wethAssetData] = [ + assetDataUtils.encodeERC20AssetData(makerTokenAddress), + assetDataUtils.encodeERC20AssetData(takerTokenAddress), + assetDataUtils.encodeERC20AssetData(contractAddresses.etherToken), + ]; + }); + after(async () => { + await blockchainLifecycle.revertAsync(); + }); + beforeEach(async () => { + await blockchainLifecycle.startAsync(); + const UNLIMITED_ALLOWANCE = UNLIMITED_ALLOWANCE_IN_BASE_UNITS; + erc20ProxyAddress = contractWrappers.erc20Proxy.address; -// describe('getCalldataOrThrow', () => { + const totalFillableAmount = FILLABLE_AMOUNTS.reduce( + (a: BigNumber, c: BigNumber) => a.plus(c), + new BigNumber(0), + ); -// describe('validation', () => { -// it('should throw if swap quote provided is not a valid forwarder SwapQuote (taker asset is WETH)', async () => { -// // const invalidSignedOrders = getSignedOrdersWithNoFees( -// // makerAssetData, -// // takerAssetData, -// // makerAddress, -// // takerAddress, -// // FILLABLE_AMOUNTS, -// // ); -// // const invalidSwapQuote = getFullyFillableSwapQuoteWithNoFees(makerAssetData, takerAssetData, invalidSignedOrders); -// // const swapQuoteConsumer = new ForwarderSwapQuoteConsumer(provider, {}); -// // TODO(dave4506) finish up testing/coverage -// // expect( -// // swapQuoteConsumer.getSmartContractParamsOrThrow(invalidSwapQuote, {}), -// // ).to.throws(); -// }); -// }); + await erc20Token.transfer.sendTransactionAsync(makerAddress, totalFillableAmount, { + from: coinbaseAddress, + }); -// describe('valid swap quote', async () => { -// it('provide correct calldata hex with default options', async () => { -// // const signedOrders = getSignedOrdersWithNoFees( -// // makerAssetData, -// // wethAssetData, -// // makerAddress, -// // takerAddress, -// // FILLABLE_AMOUNTS, -// // ); -// // const swapQuote = getFullyFillableSwapQuoteWithNoFees(makerAssetData, takerAssetData, signedOrders); -// // const swapQuoteConsumer = new ForwarderSwapQuoteConsumer(provider, { networkId }); -// // const callDataInfo = await swapQuoteConsumer.getCalldataOrThrowAsync(swapQuote, {}); -// // console.log(callDataInfo); -// // TODO(dave4506): Add elaborate testing -// }); -// }); -// }); -// }); + await erc20Token.approve.sendTransactionAsync(erc20ProxyAddress, UNLIMITED_ALLOWANCE, { + from: makerAddress, + }); + orders = await getSignedOrdersWithNoFeesAsync( + provider, + makerAssetData, + wethAssetData, + makerAddress, + takerAddress, + FILLABLE_AMOUNTS, + contractAddresses.exchange, + ); + + marketSellSwapQuote = getFullyFillableSwapQuoteWithNoFees( + makerAssetData, + wethAssetData, + orders, + MarketOperation.Sell, + ); + + marketBuySwapQuote = getFullyFillableSwapQuoteWithNoFees( + makerAssetData, + wethAssetData, + orders, + MarketOperation.Buy, + ); + + swapQuoteConsumer = new ForwarderSwapQuoteConsumer(provider, { + networkId, + }); + }); + afterEach(async () => { + await blockchainLifecycle.revertAsync(); + }); + describe('executeSwapQuoteOrThrowAsync', () => { + describe('validation', () => { + it('should throw if swapQuote provided is not a valid forwarder SwapQuote (taker asset is wEth', async () => { + const invalidSignedOrders = await getSignedOrdersWithNoFeesAsync( + provider, + makerAssetData, + takerAssetData, + makerAddress, + takerAddress, + FILLABLE_AMOUNTS, + ); + const invalidSwapQuote = getFullyFillableSwapQuoteWithNoFees( + makerAssetData, + takerAssetData, + invalidSignedOrders, + MARKET_OPERATION, + ); + expect( + swapQuoteConsumer.executeSwapQuoteOrThrowAsync(invalidSwapQuote, { takerAddress }), + ).to.be.rejectedWith( + `Expected quote.orders[0] to have takerAssetData set as ${wethAssetData}, but is ${takerAssetData}`, + ); + }); + }); + + // TODO(david) test execution of swap quotes with fee orders + describe('valid swap quote', () => { + /* + * Testing that SwapQuoteConsumer logic correctly performs a execution (doesn't throw or revert) + * Does not test the validity of the state change performed by the forwarder smart contract + */ + it('should perform a marketSell execution when provided a MarketSell type swapQuote', async () => { + let makerBalance = await erc20Token.balanceOf.callAsync(makerAddress); + let takerBalance = await erc20Token.balanceOf.callAsync(takerAddress); + expect(makerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI)); + expect(takerBalance).to.bignumber.equal(constants.ZERO_AMOUNT); + await swapQuoteConsumer.executeSwapQuoteOrThrowAsync(marketSellSwapQuote, { takerAddress }); + makerBalance = await erc20Token.balanceOf.callAsync(makerAddress); + takerBalance = await erc20Token.balanceOf.callAsync(takerAddress); + expect(makerBalance).to.bignumber.equal(new BigNumber(0.5).multipliedBy(ONE_ETH_IN_WEI)); + expect(takerBalance).to.bignumber.equal(new BigNumber(9.5).multipliedBy(ONE_ETH_IN_WEI)); + }); + + it('should perform a marketBuy execution when provided a MarketBuy type swapQuote', async () => { + let makerBalance = await erc20Token.balanceOf.callAsync(makerAddress); + let takerBalance = await erc20Token.balanceOf.callAsync(takerAddress); + expect(makerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI)); + expect(takerBalance).to.bignumber.equal(constants.ZERO_AMOUNT); + await swapQuoteConsumer.executeSwapQuoteOrThrowAsync(marketBuySwapQuote, { takerAddress }); + makerBalance = await erc20Token.balanceOf.callAsync(makerAddress); + takerBalance = await erc20Token.balanceOf.callAsync(takerAddress); + expect(takerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI)); + expect(makerBalance).to.bignumber.equal(constants.ZERO_AMOUNT); + }); + + it('should perform a marketBuy execution with affiliate fees', async () => { + let makerBalance = await erc20Token.balanceOf.callAsync(makerAddress); + let takerBalance = await erc20Token.balanceOf.callAsync(takerAddress); + const feeRecipientEthBalanceBefore = await web3Wrapper.getBalanceInWeiAsync(feeRecipient); + expect(makerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI)); + expect(takerBalance).to.bignumber.equal(constants.ZERO_AMOUNT); + await swapQuoteConsumer.executeSwapQuoteOrThrowAsync(marketBuySwapQuote, { + takerAddress, + feePercentage: 0.05, + feeRecipient, + }); + makerBalance = await erc20Token.balanceOf.callAsync(makerAddress); + takerBalance = await erc20Token.balanceOf.callAsync(takerAddress); + const feeRecipientEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(feeRecipient); + expect(makerBalance).to.bignumber.equal(constants.ZERO_AMOUNT); + expect(takerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI)); + expect(feeRecipientEthBalanceAfter.minus(feeRecipientEthBalanceBefore)).to.bignumber.equal( + new BigNumber(0.5).multipliedBy(ONE_ETH_IN_WEI), + ); + }); + + // TODO(david) Finish marketSell affiliate fee excution testing + // it('should perform a marketSell execution with affiliate fees', async () => { + // let makerBalance = await erc20Token.balanceOf.callAsync(makerAddress); + // let takerBalance = await erc20Token.balanceOf.callAsync(takerAddress); + // const feeRecipientEthBalanceBefore = await web3Wrapper.getBalanceInWeiAsync(feeRecipient); + // expect(makerBalance).to.bignumber.equal((new BigNumber(10)).multipliedBy(ONE_ETH_IN_WEI)); + // expect(takerBalance).to.bignumber.equal(constants.ZERO_AMOUNT); + // console.log(makerBalance, takerBalance, feeRecipientEthBalanceBefore); + // await swapQuoteConsumer.executeSwapQuoteOrThrowAsync(marketSellSwapQuote, { takerAddress, feePercentage: 0.05, feeRecipient }); + // makerBalance = await erc20Token.balanceOf.callAsync(makerAddress); + // takerBalance = await erc20Token.balanceOf.callAsync(takerAddress); + // const feeRecipientEthBalanceAfter = await web3Wrapper.getBalanceInWeiAsync(feeRecipient); + // console.log(makerBalance, takerBalance, feeRecipientEthBalanceAfter); + // expect(makerBalance).to.bignumber.equal((new BigNumber(0.5)).multipliedBy(ONE_ETH_IN_WEI)); + // expect(takerBalance).to.bignumber.equal((new BigNumber(9.5)).multipliedBy(ONE_ETH_IN_WEI)); + // expect(feeRecipientEthBalanceAfter.minus(feeRecipientEthBalanceBefore)).to.bignumber.equal((new BigNumber(0.5)).multipliedBy(ONE_ETH_IN_WEI)); + // }); + }); + }); + + describe('getSmartContractParamsOrThrow', () => { + describe('validation', () => { + it('should throw if swap quote provided is not a valid forwarder SwapQuote (taker asset is WETH)', async () => { + const invalidSignedOrders = await getSignedOrdersWithNoFeesAsync( + provider, + makerAssetData, + takerAssetData, + makerAddress, + takerAddress, + FILLABLE_AMOUNTS, + ); + const invalidSwapQuote = getFullyFillableSwapQuoteWithNoFees( + makerAssetData, + takerAssetData, + invalidSignedOrders, + MARKET_OPERATION, + ); + expect(swapQuoteConsumer.getSmartContractParamsOrThrowAsync(invalidSwapQuote, {})).to.be.rejectedWith( + `Expected quote.orders[0] to have takerAssetData set as ${wethAssetData}, but is ${takerAssetData}`, + ); + }); + }); + + describe('valid swap quote', async () => { + it('provide correct and optimized smart contract params with default options for a marketSell SwapQuote (no affiliate fees)', async () => { + const { toAddress, params } = await swapQuoteConsumer.getSmartContractParamsOrThrowAsync( + marketSellSwapQuote, + {}, + ); + expect(toAddress).to.deep.equal(contractWrappers.forwarder.address); + const { + feeSignatures, + feePercentage, + feeRecipient: feeRecipientFromParams, + signatures, + type, + } = params as ForwarderMarketSellSmartContractParams; + expect(type).to.deep.equal(MarketOperation.Sell); + expect(feeRecipientFromParams).to.deep.equal(constants.NULL_ADDRESS); + const orderSignatures = marketSellSwapQuote.orders.map(order => order.signature); + expect(signatures).to.deep.equal(orderSignatures); + expect(feePercentage).to.bignumber.equal(0); + expect(feeSignatures).to.deep.equal([]); + }); + it('provide correct and optimized smart contract params with default options for a marketBuy SwapQuote (no affiliate fees)', async () => { + const { toAddress, params } = await swapQuoteConsumer.getSmartContractParamsOrThrowAsync( + marketBuySwapQuote, + {}, + ); + expect(toAddress).to.deep.equal(contractWrappers.forwarder.address); + const { + makerAssetFillAmount, + feeSignatures, + feePercentage, + feeRecipient: feeRecipientFromParams, + signatures, + type, + } = params as ForwarderMarketBuySmartContractParams; + expect(type).to.deep.equal(MarketOperation.Buy); + expect(feeRecipientFromParams).to.deep.equal(constants.NULL_ADDRESS); + expect(makerAssetFillAmount).to.bignumber.equal( + (marketBuySwapQuote as MarketBuySwapQuote).makerAssetFillAmount, + ); + const orderSignatures = marketBuySwapQuote.orders.map(order => order.signature); + expect(signatures).to.deep.equal(orderSignatures); + expect(feePercentage).to.bignumber.equal(0); + expect(feeSignatures).to.deep.equal([]); + }); + it('provide correct and optimized smart contract params with affiliate fees for a marketSell SwapQuote', async () => { + const { toAddress, params } = await swapQuoteConsumer.getSmartContractParamsOrThrowAsync( + marketSellSwapQuote, + { + feePercentage: 0.05, + feeRecipient, + }, + ); + expect(toAddress).to.deep.equal(contractWrappers.forwarder.address); + const { + feeSignatures, + feePercentage, + feeRecipient: feeRecipientFromParams, + signatures, + type, + } = params as ForwarderMarketSellSmartContractParams; + expect(type).to.deep.equal(MarketOperation.Sell); + expect(feeRecipientFromParams).to.deep.equal(feeRecipient); + const orderSignatures = marketSellSwapQuote.orders.map(order => order.signature); + expect(signatures).to.deep.equal(orderSignatures); + expect(feePercentage).to.bignumber.equal(new BigNumber(0.05).multipliedBy(ONE_ETH_IN_WEI)); + expect(feeSignatures).to.deep.equal([]); + }); + it('provide correct and optimized smart contract params with affiliate fees for a marketBuy SwapQuote', async () => { + const { toAddress, params } = await swapQuoteConsumer.getSmartContractParamsOrThrowAsync( + marketBuySwapQuote, + { + feePercentage: 0.05, + feeRecipient, + }, + ); + expect(toAddress).to.deep.equal(contractWrappers.forwarder.address); + const { + makerAssetFillAmount, + feeSignatures, + feePercentage, + feeRecipient: feeRecipientFromParams, + signatures, + type, + } = params as ForwarderMarketBuySmartContractParams; + expect(type).to.deep.equal(MarketOperation.Buy); + expect(feeRecipientFromParams).to.deep.equal(feeRecipient); + expect(makerAssetFillAmount).to.bignumber.equal( + (marketBuySwapQuote as MarketBuySwapQuote).makerAssetFillAmount, + ); + const orderSignatures = marketBuySwapQuote.orders.map(order => order.signature); + expect(signatures).to.deep.equal(orderSignatures); + expect(feePercentage).to.bignumber.equal(new BigNumber(0.05).multipliedBy(ONE_ETH_IN_WEI)); + expect(feeSignatures).to.deep.equal([]); + }); + }); + }); + + describe('getCalldataOrThrow', () => { + describe('validation', () => { + it('should throw if swap quote provided is not a valid forwarder SwapQuote (taker asset is WETH)', async () => { + const invalidSignedOrders = await getSignedOrdersWithNoFeesAsync( + provider, + makerAssetData, + takerAssetData, + makerAddress, + takerAddress, + FILLABLE_AMOUNTS, + ); + const invalidSwapQuote = getFullyFillableSwapQuoteWithNoFees( + makerAssetData, + takerAssetData, + invalidSignedOrders, + MARKET_OPERATION, + ); + expect(swapQuoteConsumer.getCalldataOrThrowAsync(invalidSwapQuote, {})).to.be.rejectedWith( + `Expected quote.orders[0] to have takerAssetData set as ${wethAssetData}, but is ${takerAssetData}`, + ); + }); + }); + + describe('valid swap quote', async () => { + it('provide correct and optimized calldata options with default options for a marketSell SwapQuote (no affiliate fees)', async () => { + let makerBalance = await erc20Token.balanceOf.callAsync(makerAddress); + let takerBalance = await erc20Token.balanceOf.callAsync(takerAddress); + expect(makerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI)); + expect(takerBalance).to.bignumber.equal(constants.ZERO_AMOUNT); + const { calldataHexString, toAddress } = await swapQuoteConsumer.getCalldataOrThrowAsync( + marketSellSwapQuote, + {}, + ); + expect(toAddress).to.deep.equal(contractWrappers.forwarder.address); + await web3Wrapper.sendTransactionAsync({ + from: takerAddress, + to: toAddress, + data: calldataHexString, + value: marketSellSwapQuote.worstCaseQuoteInfo.totalTakerTokenAmount, + gas: 4000000, + }); + makerBalance = await erc20Token.balanceOf.callAsync(makerAddress); + takerBalance = await erc20Token.balanceOf.callAsync(takerAddress); + expect(makerBalance).to.bignumber.equal(new BigNumber(0.5).multipliedBy(ONE_ETH_IN_WEI)); + expect(takerBalance).to.bignumber.equal(new BigNumber(9.5).multipliedBy(ONE_ETH_IN_WEI)); + }); + it('provide correct and optimized calldata options with default options for a marketBuy SwapQuote (no affiliate fees)', async () => { + let makerBalance = await erc20Token.balanceOf.callAsync(makerAddress); + let takerBalance = await erc20Token.balanceOf.callAsync(takerAddress); + expect(makerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI)); + expect(takerBalance).to.bignumber.equal(constants.ZERO_AMOUNT); + const { calldataHexString, toAddress } = await swapQuoteConsumer.getCalldataOrThrowAsync( + marketBuySwapQuote, + {}, + ); + expect(toAddress).to.deep.equal(contractAddresses.forwarder); + await web3Wrapper.sendTransactionAsync({ + from: takerAddress, + to: toAddress, + data: calldataHexString, + value: marketBuySwapQuote.worstCaseQuoteInfo.totalTakerTokenAmount, + gas: 4000000, + }); + makerBalance = await erc20Token.balanceOf.callAsync(makerAddress); + takerBalance = await erc20Token.balanceOf.callAsync(takerAddress); + expect(takerBalance).to.bignumber.equal(new BigNumber(10).multipliedBy(ONE_ETH_IN_WEI)); + expect(makerBalance).to.bignumber.equal(constants.ZERO_AMOUNT); + }); + // TODO(david) finish testing for affiliate fees calldata output + // it('provide correct and optimized calldata options with affiliate fees for a marketSell SwapQuote', async () => { + // }); + // it('provide correct and optimized calldata options with affiliate fees for a marketBuy SwapQuote', async () => { + // }); + }); + }); +}); diff --git a/packages/asset-swapper/test/swap_quote_calculator_test.ts b/packages/asset-swapper/test/swap_quote_calculator_test.ts index c120a2c1b6..eafa176a15 100644 --- a/packages/asset-swapper/test/swap_quote_calculator_test.ts +++ b/packages/asset-swapper/test/swap_quote_calculator_test.ts @@ -5,6 +5,7 @@ import * as chai from 'chai'; import * as _ from 'lodash'; import 'mocha'; +import { constants } from '../src/constants'; import { OrdersAndFillableAmounts, SwapQuoterError } from '../src/types'; import { swapQuoteCalculator } from '../src/utils/swap_quote_calculator'; @@ -70,7 +71,7 @@ describe('swapQuoteCalculator', () => { }); describe('InsufficientLiquidityError', () => { it('should throw if not enough taker asset liquidity (multiple orders)', () => { - // we have 150 takerAsset units available to fill but attempt to calculate a quote for 200 takerAsset units + // we have 150 takerAsset units available to sell but attempt to calculate a quote for 200 takerAsset units const errorFunction = () => { swapQuoteCalculator.calculateMarketSellSwapQuote( ordersAndFillableAmounts, @@ -84,7 +85,7 @@ describe('swapQuoteCalculator', () => { testHelpers.expectInsufficientLiquidityError(expect, errorFunction, new BigNumber(150)); }); it('should throw if not enough taker asset liquidity (multiple orders with 20% slippage)', () => { - // we have 150 takerAsset units available to fill but attempt to calculate a quote for 200 makerAsset units + // we have 150 takerAsset units available to sell but attempt to calculate a quote for 200 takerAsset units const errorFunction = () => { swapQuoteCalculator.calculateMarketSellSwapQuote( ordersAndFillableAmounts, @@ -98,7 +99,7 @@ describe('swapQuoteCalculator', () => { testHelpers.expectInsufficientLiquidityError(expect, errorFunction, new BigNumber(125)); }); it('should throw if not enough taker asset liquidity (multiple orders with 5% slippage)', () => { - // we have 150 takerAsset units available to fill but attempt to calculate a quote for 200 makerAsset units + // we have 150 takerAsset units available to fill but attempt to calculate a quote for 200 takerAsset units const errorFunction = () => { swapQuoteCalculator.calculateMarketSellSwapQuote( ordersAndFillableAmounts, @@ -201,12 +202,12 @@ describe('swapQuoteCalculator', () => { ).to.not.throw(); }); it('should throw if not enough ZRX liquidity', () => { - // we request 300 makerAsset units but the ZRX order is only enough to fill the first order, which only has 200 makerAssetUnits available + // we request 75 takerAsset units but the ZRX order is only enough to fill the first order, which only has 50 takerAsset units available expect(() => swapQuoteCalculator.calculateMarketSellSwapQuote( ordersAndFillableAmounts, smallFeeOrderAndFillableAmount, - new BigNumber(125), + new BigNumber(75), 0, false, false, @@ -214,7 +215,7 @@ describe('swapQuoteCalculator', () => { ).to.throw(SwapQuoterError.InsufficientZrxLiquidity); }); it('calculates a correct swapQuote with no slippage', () => { - // we request 100 takerAsset units which can be filled using the first order + // we request 50 takerAsset units which can be filled using the first order // the first order requires a fee of 100 ZRX from the taker which can be filled by the feeOrder const assetSellAmount = new BigNumber(50); const slippagePercentage = 0; @@ -230,7 +231,7 @@ describe('swapQuoteCalculator', () => { expect(swapQuote.orders).to.deep.equal([ordersAndFillableAmounts.orders[0]]); expect(swapQuote.feeOrders).to.deep.equal([smallFeeOrderAndFillableAmount.orders[0]]); // test if rates are correct - // 50 eth to fill the first order + 100 eth for fees + // 50 takerAsset units to fill the first order + 100 takerAsset units for fees const expectedMakerAssetAmountForTakerAsset = new BigNumber(200); const expectedTakerAssetAmountForZrxFees = new BigNumber(100); const expectedTotalTakerAssetAmount = assetSellAmount.plus(expectedTakerAssetAmountForZrxFees); @@ -258,7 +259,7 @@ describe('swapQuoteCalculator', () => { // we request 50 takerAsset units which can be filled using the first order // however with 50% slippage we are protecting the buy with 25 extra takerAssetUnits // so we need enough orders to fill 75 takerAssetUnits - // 150 takerAssetUnits can only be filled using both orders + // 75 takerAssetUnits can only be filled using both orders // the first order requires a fee of 100 ZRX from the taker which can be filled by the feeOrder const assetSellAmount = new BigNumber(50); const slippagePercentage = 0.5; @@ -274,7 +275,6 @@ describe('swapQuoteCalculator', () => { expect(swapQuote.orders).to.deep.equal(ordersAndFillableAmounts.orders); expect(swapQuote.feeOrders).to.deep.equal(allFeeOrdersAndFillableAmounts.orders); // test if rates are correct - // 50 eth to fill the first order + 100 eth for fees const expectedMakerAssetAmountForTakerAsset = new BigNumber(200); const expectedTakerAssetAmountForZrxFees = new BigNumber(100); const expectedTotalTakerAssetAmount = assetSellAmount.plus(expectedTakerAssetAmountForZrxFees); @@ -286,7 +286,7 @@ describe('swapQuoteCalculator', () => { expectedTakerAssetAmountForZrxFees, ); expect(swapQuote.bestCaseQuoteInfo.totalTakerTokenAmount).to.bignumber.equal(expectedTotalTakerAssetAmount); - // 100 eth to fill the first order + 208 eth for fees + const expectedWorstMakerAssetAmountForTakerAsset = new BigNumber(100); const expectedWorstTakerAssetAmountForZrxFees = new BigNumber(99); const expectedWorstTotalTakerAssetAmount = assetSellAmount.plus(expectedWorstTakerAssetAmountForZrxFees); @@ -301,6 +301,80 @@ describe('swapQuoteCalculator', () => { expectedWorstTotalTakerAssetAmount, ); }); + it('calculates a correct swapQuote (with fee calculations disabled) with no slippage', () => { + // we request 50 takerAsset units which can be filled using the first order + const assetSellAmount = new BigNumber(50); + const slippagePercentage = 0; + const swapQuote = swapQuoteCalculator.calculateMarketSellSwapQuote( + ordersAndFillableAmounts, + smallFeeOrderAndFillableAmount, + assetSellAmount, + slippagePercentage, + false, + true, + ); + // test if orders are correct + expect(swapQuote.orders).to.deep.equal([ordersAndFillableAmounts.orders[0]]); + expect(swapQuote.feeOrders).to.deep.equal([]); + // test if rates are correct + const expectedMakerAssetAmountForTakerAsset = new BigNumber(200); + const expectedTotalTakerAssetAmount = assetSellAmount; + expect(swapQuote.bestCaseQuoteInfo.takerTokenAmount).to.bignumber.equal(assetSellAmount); + expect(swapQuote.bestCaseQuoteInfo.makerTokenAmount).to.bignumber.equal( + expectedMakerAssetAmountForTakerAsset, + ); + expect(swapQuote.bestCaseQuoteInfo.feeTakerTokenAmount).to.bignumber.equal(constants.ZERO_AMOUNT); + expect(swapQuote.bestCaseQuoteInfo.totalTakerTokenAmount).to.bignumber.equal(expectedTotalTakerAssetAmount); + // because we have no slippage protection, minRate is equal to maxRate + expect(swapQuote.worstCaseQuoteInfo.takerTokenAmount).to.bignumber.equal(assetSellAmount); + expect(swapQuote.worstCaseQuoteInfo.makerTokenAmount).to.bignumber.equal( + expectedMakerAssetAmountForTakerAsset, + ); + expect(swapQuote.worstCaseQuoteInfo.feeTakerTokenAmount).to.bignumber.equal(constants.ZERO_AMOUNT); + expect(swapQuote.worstCaseQuoteInfo.totalTakerTokenAmount).to.bignumber.equal( + expectedTotalTakerAssetAmount, + ); + }); + it('calculates a correct swapQuote (with fee calculatations disabled) with slippage', () => { + // we request 50 takerAsset units which can be filled using the first order + // however with 50% slippage we are protecting the buy with 25 extra takerAssetUnits + // so we need enough orders to fill 75 takerAssetUnits + // 50 takerAssetUnits can only be filled using both orders + // the first order requires a fee of 100 ZRX from the taker which can be filled by the feeOrder + const assetSellAmount = new BigNumber(50); + const slippagePercentage = 0.5; + const swapQuote = swapQuoteCalculator.calculateMarketSellSwapQuote( + ordersAndFillableAmounts, + allFeeOrdersAndFillableAmounts, + assetSellAmount, + slippagePercentage, + false, + true, + ); + // test if orders are correct + expect(swapQuote.orders).to.deep.equal(ordersAndFillableAmounts.orders); + expect(swapQuote.feeOrders).to.deep.equal([]); + // test if rates are correct + const expectedMakerAssetAmountForTakerAsset = new BigNumber(200); + const expectedTotalTakerAssetAmount = assetSellAmount; + expect(swapQuote.bestCaseQuoteInfo.takerTokenAmount).to.bignumber.equal(assetSellAmount); + expect(swapQuote.bestCaseQuoteInfo.makerTokenAmount).to.bignumber.equal( + expectedMakerAssetAmountForTakerAsset, + ); + expect(swapQuote.bestCaseQuoteInfo.feeTakerTokenAmount).to.bignumber.equal(constants.ZERO_AMOUNT); + expect(swapQuote.bestCaseQuoteInfo.totalTakerTokenAmount).to.bignumber.equal(expectedTotalTakerAssetAmount); + // 100 eth to fill the first order + 208 eth for fees + const expectedWorstMakerAssetAmountForTakerAsset = new BigNumber(100); + const expectedWorstTotalTakerAssetAmount = assetSellAmount; + expect(swapQuote.worstCaseQuoteInfo.takerTokenAmount).to.bignumber.equal(assetSellAmount); + expect(swapQuote.worstCaseQuoteInfo.makerTokenAmount).to.bignumber.equal( + expectedWorstMakerAssetAmountForTakerAsset, + ); + expect(swapQuote.worstCaseQuoteInfo.feeTakerTokenAmount).to.bignumber.equal(constants.ZERO_AMOUNT); + expect(swapQuote.worstCaseQuoteInfo.totalTakerTokenAmount).to.bignumber.equal( + expectedWorstTotalTakerAssetAmount, + ); + }); }); describe('#calculateMarketBuySwapQuote', () => { let firstOrder: SignedOrder; @@ -588,5 +662,78 @@ describe('swapQuoteCalculator', () => { expectedWorstTotalTakerAssetAmount, ); }); + it('calculates a correct swapQuote (with fee calculations disabled) with no slippage', () => { + // we request 200 makerAsset units which can be filled using the first order + // the first order requires a fee of 100 ZRX from the taker which can be filled by the feeOrder + const assetBuyAmount = new BigNumber(200); + const slippagePercentage = 0; + const swapQuote = swapQuoteCalculator.calculateMarketBuySwapQuote( + ordersAndFillableAmounts, + smallFeeOrderAndFillableAmount, + assetBuyAmount, + slippagePercentage, + false, + true, + ); + // test if orders are correct + expect(swapQuote.orders).to.deep.equal([ordersAndFillableAmounts.orders[0]]); + expect(swapQuote.feeOrders).to.deep.equal([]); + // test if rates are correct + // 50 eth to fill the first order + 100 eth for fees + const expectedTakerAssetAmountForMakerAsset = new BigNumber(50); + const expectedTotalTakerAssetAmount = expectedTakerAssetAmountForMakerAsset; + expect(swapQuote.bestCaseQuoteInfo.takerTokenAmount).to.bignumber.equal( + expectedTakerAssetAmountForMakerAsset, + ); + expect(swapQuote.bestCaseQuoteInfo.feeTakerTokenAmount).to.bignumber.equal(constants.ZERO_AMOUNT); + expect(swapQuote.bestCaseQuoteInfo.totalTakerTokenAmount).to.bignumber.equal(expectedTotalTakerAssetAmount); + // because we have no slippage protection, minRate is equal to maxRate + expect(swapQuote.worstCaseQuoteInfo.takerTokenAmount).to.bignumber.equal( + expectedTakerAssetAmountForMakerAsset, + ); + expect(swapQuote.worstCaseQuoteInfo.feeTakerTokenAmount).to.bignumber.equal(constants.ZERO_AMOUNT); + expect(swapQuote.worstCaseQuoteInfo.totalTakerTokenAmount).to.bignumber.equal( + expectedTotalTakerAssetAmount, + ); + }); + it('calculates a correct swapQuote (with fee calculations disabled) with slippage', () => { + // we request 200 makerAsset units which can be filled using the first order + // however with 50% slippage we are protecting the buy with 100 extra makerAssetUnits + // so we need enough orders to fill 300 makerAssetUnits + // 300 makerAssetUnits can only be filled using both orders + // the first order requires a fee of 100 ZRX from the taker which can be filled by the feeOrder + const assetBuyAmount = new BigNumber(200); + const slippagePercentage = 0.5; + const swapQuote = swapQuoteCalculator.calculateMarketBuySwapQuote( + ordersAndFillableAmounts, + allFeeOrdersAndFillableAmounts, + assetBuyAmount, + slippagePercentage, + false, + true, + ); + // test if orders are correct + expect(swapQuote.orders).to.deep.equal(ordersAndFillableAmounts.orders); + expect(swapQuote.feeOrders).to.deep.equal([]); + // test if rates are correct + // 50 eth to fill the first order + 100 eth for fees + const expectedTakerAssetAmountForMakerAsset = new BigNumber(50); + const expectedTotalTakerAssetAmount = expectedTakerAssetAmountForMakerAsset; + expect(swapQuote.bestCaseQuoteInfo.takerTokenAmount).to.bignumber.equal( + expectedTakerAssetAmountForMakerAsset, + ); + expect(swapQuote.bestCaseQuoteInfo.feeTakerTokenAmount).to.bignumber.equal(constants.ZERO_AMOUNT); + expect(swapQuote.bestCaseQuoteInfo.totalTakerTokenAmount).to.bignumber.equal(expectedTotalTakerAssetAmount); + // 100 eth to fill the first order + 208 eth for fees + const expectedWorstTakerAssetAmountForMakerAsset = new BigNumber(100); + const expectedWorstTotalTakerAssetAmount = expectedWorstTakerAssetAmountForMakerAsset; + expect(swapQuote.worstCaseQuoteInfo.takerTokenAmount).to.bignumber.equal( + expectedWorstTakerAssetAmountForMakerAsset, + ); + expect(swapQuote.worstCaseQuoteInfo.feeTakerTokenAmount).to.bignumber.equal(constants.ZERO_AMOUNT); + expect(swapQuote.worstCaseQuoteInfo.totalTakerTokenAmount).to.bignumber.equal( + expectedWorstTotalTakerAssetAmount, + ); + }); }); }); diff --git a/packages/asset-swapper/test/swap_quote_consumer_utils_test.ts b/packages/asset-swapper/test/swap_quote_consumer_utils_test.ts new file mode 100644 index 0000000000..821e318ba1 --- /dev/null +++ b/packages/asset-swapper/test/swap_quote_consumer_utils_test.ts @@ -0,0 +1,170 @@ +import { ContractAddresses, ContractWrappers } from '@0x/contract-wrappers'; +import { BlockchainLifecycle, tokenUtils } from '@0x/dev-utils'; +import { assetDataUtils } from '@0x/order-utils'; +import { MarketOperation, SignedOrder } from '@0x/types'; +import { BigNumber } from '@0x/utils'; +import * as chai from 'chai'; +import 'mocha'; + +import { SwapQuote } from '../src'; +import { ConsumerType } from '../src/types'; +import { swapQuoteConsumerUtils } from '../src/utils/swap_quote_consumer_utils'; + +import { chaiSetup } from './utils/chai_setup'; +import { migrateOnceAsync } from './utils/migrate'; +import { getFullyFillableSwapQuoteWithNoFees, getSignedOrdersWithNoFeesAsync } from './utils/swap_quote'; +import { provider, web3Wrapper } from './utils/web3_wrapper'; + +chaiSetup.configure(); +const expect = chai.expect; +const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); + +const ONE_ETH_IN_WEI = new BigNumber(1000000000000000000); +const TESTRPC_NETWORK_ID = 50; +const FILLABLE_AMOUNTS = [new BigNumber(2), new BigNumber(3), new BigNumber(5)].map(value => + value.multipliedBy(ONE_ETH_IN_WEI), +); +const LARGE_FILLABLE_AMOUNTS = [new BigNumber(20), new BigNumber(20), new BigNumber(20)].map(value => + value.multipliedBy(ONE_ETH_IN_WEI), +); + +describe('swapQuoteConsumerUtils', () => { + let contractWrappers: ContractWrappers; + let userAddresses: string[]; + let makerAddress: string; + let takerAddress: string; + let makerTokenAddress: string; + let takerTokenAddress: string; + let makerAssetData: string; + let takerAssetData: string; + let wethAssetData: string; + let contractAddresses: ContractAddresses; + + const networkId = TESTRPC_NETWORK_ID; + before(async () => { + contractAddresses = await migrateOnceAsync(); + await blockchainLifecycle.startAsync(); + userAddresses = await web3Wrapper.getAvailableAddressesAsync(); + const config = { + networkId, + contractAddresses, + }; + contractWrappers = new ContractWrappers(provider, config); + [takerAddress, makerAddress] = userAddresses; + [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); + [makerAssetData, takerAssetData, wethAssetData] = [ + assetDataUtils.encodeERC20AssetData(makerTokenAddress), + assetDataUtils.encodeERC20AssetData(takerTokenAddress), + assetDataUtils.encodeERC20AssetData(contractAddresses.etherToken), + ]; + }); + after(async () => { + await blockchainLifecycle.revertAsync(); + }); + beforeEach(async () => { + await blockchainLifecycle.startAsync(); + }); + afterEach(async () => { + await blockchainLifecycle.revertAsync(); + }); + + describe('getConsumerTypeForSwapQuoteAsync', () => { + let forwarderOrders: SignedOrder[]; + let exchangeOrders: SignedOrder[]; + let largeForwarderOrders: SignedOrder[]; + let forwarderSwapQuote: SwapQuote; + let exchangeSwapQuote: SwapQuote; + let largeForwarderSwapQuote: SwapQuote; + + beforeEach(async () => { + exchangeOrders = await getSignedOrdersWithNoFeesAsync( + provider, + makerAssetData, + takerAssetData, + makerAddress, + takerAddress, + FILLABLE_AMOUNTS, + ); + + forwarderOrders = await getSignedOrdersWithNoFeesAsync( + provider, + makerAssetData, + wethAssetData, + makerAddress, + takerAddress, + FILLABLE_AMOUNTS, + ); + + largeForwarderOrders = await getSignedOrdersWithNoFeesAsync( + provider, + makerAssetData, + wethAssetData, + makerAddress, + takerAddress, + LARGE_FILLABLE_AMOUNTS, + ); + + forwarderSwapQuote = getFullyFillableSwapQuoteWithNoFees( + makerAssetData, + wethAssetData, + forwarderOrders, + MarketOperation.Sell, + ); + + largeForwarderSwapQuote = getFullyFillableSwapQuoteWithNoFees( + makerAssetData, + wethAssetData, + largeForwarderOrders, + MarketOperation.Sell, + ); + + exchangeSwapQuote = getFullyFillableSwapQuoteWithNoFees( + makerAssetData, + takerAssetData, + exchangeOrders, + MarketOperation.Sell, + ); + }); + + it('should return exchange consumer if takerAsset is not wEth', async () => { + const consumerType = await swapQuoteConsumerUtils.getConsumerTypeForSwapQuoteAsync( + exchangeSwapQuote, + contractWrappers, + provider, + { takerAddress }, + ); + expect(consumerType).to.equal(ConsumerType.Exchange); + }); + it('should return forwarder consumer if takerAsset is wEth and have enough eth balance', async () => { + const consumerType = await swapQuoteConsumerUtils.getConsumerTypeForSwapQuoteAsync( + forwarderSwapQuote, + contractWrappers, + provider, + { takerAddress }, + ); + expect(consumerType).to.equal(ConsumerType.Forwarder); + }); + it('should return exchange consumer if takerAsset is wEth and taker has enough weth', async () => { + const etherInWei = new BigNumber(20).multipliedBy(ONE_ETH_IN_WEI); + await contractWrappers.weth9.deposit.sendTransactionAsync({ value: etherInWei, from: takerAddress }); + const consumerType = await swapQuoteConsumerUtils.getConsumerTypeForSwapQuoteAsync( + forwarderSwapQuote, + contractWrappers, + provider, + { takerAddress }, + ); + expect(consumerType).to.equal(ConsumerType.Exchange); + }); + it('should return forwarder consumer if takerAsset is wEth and takerAddress has no available balance in either weth or eth (defaulting behavior)', async () => { + const etherInWei = new BigNumber(50).multipliedBy(ONE_ETH_IN_WEI); + await contractWrappers.weth9.deposit.sendTransactionAsync({ value: etherInWei, from: takerAddress }); + const consumerType = await swapQuoteConsumerUtils.getConsumerTypeForSwapQuoteAsync( + largeForwarderSwapQuote, + contractWrappers, + provider, + { takerAddress }, + ); + expect(consumerType).to.equal(ConsumerType.Forwarder); + }); + }); +}); diff --git a/packages/asset-swapper/test/utils/swap_quote.ts b/packages/asset-swapper/test/utils/swap_quote.ts index de9c23bf97..fcf4ca03cc 100644 --- a/packages/asset-swapper/test/utils/swap_quote.ts +++ b/packages/asset-swapper/test/utils/swap_quote.ts @@ -1,13 +1,38 @@ import { orderFactory } from '@0x/order-utils/lib/src/order_factory'; import { MarketOperation, SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; +import { SupportedProvider } from '@0x/web3-wrapper'; import * as _ from 'lodash'; +import { constants } from '../../src/constants'; import { SwapQuote } from '../../src/types'; const ZERO_BIG_NUMBER = new BigNumber(0); -export const getSignedOrdersWithNoFees = ( +export const getSignedOrdersWithNoFeesAsync = async ( + provider: SupportedProvider, + makerAssetData: string, + takerAssetData: string, + makerAddress: string, + takerAddress: string, + fillableAmounts: BigNumber[], + exchangeAddress?: string, +): Promise => { + const promises = _.map(fillableAmounts, async (fillableAmount: BigNumber) => + orderFactory.createSignedOrderAsync( + provider, + makerAddress, + fillableAmount, + makerAssetData, + fillableAmount, + takerAssetData, + exchangeAddress || constants.NULL_ADDRESS, + ), + ); + return Promise.all(promises); +}; + +export const getPartialSignedOrdersWithNoFees = ( makerAssetData: string, takerAssetData: string, makerAddress: string, @@ -25,6 +50,55 @@ export const getSignedOrdersWithNoFees = ( ); }; +export const getPartialSignedOrdersWithFees = ( + makerAssetData: string, + takerAssetData: string, + makerAddress: string, + takerAddress: string, + fillableAmounts: BigNumber[], + takerFees: BigNumber[], +): SignedOrder[] => { + const orders = getPartialSignedOrdersWithNoFees( + makerAssetData, + takerAssetData, + makerAddress, + takerAddress, + fillableAmounts, + ); + return _.map(orders, (order: SignedOrder, index: number) => + orderFactory.createSignedOrderFromPartial({ + ...order, + ...{ takerFee: takerFees[index] }, + }), + ); +}; + +export const getFullyFillableSwapQuoteWithFees = ( + makerAssetData: string, + takerAssetData: string, + orders: SignedOrder[], + feeOrders: SignedOrder[], + operation: MarketOperation, +) => { + const swapQuote = getFullyFillableSwapQuoteWithNoFees(makerAssetData, takerAssetData, orders, operation); + swapQuote.feeOrders = feeOrders; + const totalFeeTakerTokenAmount = _.reduce( + feeOrders, + (a: BigNumber, c: SignedOrder) => a.plus(c.takerAssetAmount), + ZERO_BIG_NUMBER, + ); + // Adds fees to the SwapQuoteInfos assuming all feeOrders will be filled + swapQuote.bestCaseQuoteInfo.feeTakerTokenAmount = totalFeeTakerTokenAmount; + swapQuote.worstCaseQuoteInfo.feeTakerTokenAmount = totalFeeTakerTokenAmount; + swapQuote.bestCaseQuoteInfo.totalTakerTokenAmount = swapQuote.bestCaseQuoteInfo.totalTakerTokenAmount.plus( + totalFeeTakerTokenAmount, + ); + swapQuote.worstCaseQuoteInfo.totalTakerTokenAmount = swapQuote.worstCaseQuoteInfo.totalTakerTokenAmount.plus( + totalFeeTakerTokenAmount, + ); + return swapQuote; +}; + export const getFullyFillableSwapQuoteWithNoFees = ( makerAssetData: string, takerAssetData: string, diff --git a/packages/base-contract/CHANGELOG.json b/packages/base-contract/CHANGELOG.json index 793d3d4c4d..6715014e5a 100644 --- a/packages/base-contract/CHANGELOG.json +++ b/packages/base-contract/CHANGELOG.json @@ -1,6 +1,6 @@ [ { - "version": "5.2.0", + "version": "5.4.0", "changes": [ { "note": "Automatically decode and throw rich reverts in `_throwIfRevertWithReasonCallResult`", @@ -20,6 +20,47 @@ } ] }, + { + "timestamp": 1565296576, + "version": "5.3.1", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "version": "5.3.0", + "changes": [ + { + "note": "Updated interface to `deployFrom0xArtifactAsync` to include log decode dependencies.", + "pr": 1995 + }, + { + "note": "Updated interface to `deployAsync` to include log decode dependencies.", + "pr": 1995 + } + ], + "timestamp": 1564604963 + }, + { + "version": "5.2.0", + "changes": [ + { + "note": "Add SubscriptionManager", + "pr": 1970 + } + ] + }, + { + "timestamp": 1563957393, + "version": "5.1.2", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563006338, "version": "5.1.1", diff --git a/packages/base-contract/CHANGELOG.md b/packages/base-contract/CHANGELOG.md index 35d209ae79..d1b735b108 100644 --- a/packages/base-contract/CHANGELOG.md +++ b/packages/base-contract/CHANGELOG.md @@ -5,6 +5,23 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v5.3.1 - _August 8, 2019_ + + * Dependencies updated + +## v5.3.0 - _July 31, 2019_ + + * Updated interface to `deployFrom0xArtifactAsync` to include log decode dependencies. (#1995) + * Updated interface to `deployAsync` to include log decode dependencies. (#1995) + +## v5.2.0 - _Invalid date_ + + * Add SubscriptionManager (#1970) + +## v5.1.2 - _July 24, 2019_ + + * Dependencies updated + ## v5.1.1 - _July 13, 2019_ * Dependencies updated diff --git a/packages/base-contract/package.json b/packages/base-contract/package.json index 103fc2886c..07af21d2fe 100644 --- a/packages/base-contract/package.json +++ b/packages/base-contract/package.json @@ -1,6 +1,6 @@ { "name": "@0x/base-contract", - "version": "5.1.1", + "version": "5.3.1", "engines": { "node": ">=6.12" }, @@ -32,22 +32,28 @@ "devDependencies": { "@0x/tslint-config": "^3.0.1", "@types/lodash": "4.14.104", + "@types/mocha": "^5.2.7", "chai": "^4.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", "tslint": "5.11.0", "typescript": "3.0.1" }, "dependencies": { - "@0x/assert": "^2.1.0", - "@0x/json-schemas": "^3.0.11", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", - "ethereum-types": "^2.1.3", - "lodash": "^4.17.11" + "@0x/assert": "^2.1.3", + "@0x/json-schemas": "^3.1.13", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", + "ethereum-types": "^2.1.4", + "ethereumjs-blockstream": "6.0.0", + "ethereumjs-util": "^5.1.1", + "ethers": "~4.0.4", + "js-sha3": "^0.7.0", + "lodash": "^4.17.11", + "uuid": "^3.3.2" }, "publishConfig": { "access": "public" diff --git a/packages/base-contract/src/index.ts b/packages/base-contract/src/index.ts index 3665c53556..0866d572fd 100644 --- a/packages/base-contract/src/index.ts +++ b/packages/base-contract/src/index.ts @@ -27,6 +27,10 @@ import * as _ from 'lodash'; import { formatABIDataItem } from './utils'; +export { SubscriptionManager } from './subscription_manager'; + +export * from './types'; + export interface AbiEncoderByFunctionSignature { [key: string]: AbiEncoder.Method; } @@ -201,12 +205,20 @@ export class BaseContract { const abiEncodedArguments = abiEncoder.encode(functionArguments); return abiEncodedArguments; } + /// @dev Constructs a contract wrapper. + /// @param contractName Name of contract. + /// @param abi of the contract. + /// @param address of the deployed contract. + /// @param supportedProvider for communicating with an ethereum node. + /// @param logDecodeDependencies the name and ABI of contracts whose event logs are + /// decoded by this wrapper. constructor( contractName: string, abi: ContractAbi, address: string, supportedProvider: SupportedProvider, callAndTxnDefaults?: Partial, + logDecodeDependencies?: { [contractName: string]: ContractAbi }, ) { assert.isString('contractName', contractName); assert.isETHAddressHex('address', address); @@ -230,6 +242,10 @@ export class BaseContract { const abiEncoder = new AbiEncoder.Method(methodAbi); const functionSignature = abiEncoder.getSignature(); this._abiEncoderByFunctionSignature[functionSignature] = abiEncoder; + this._web3Wrapper.abiDecoder.addABI(abi, contractName); + }); + _.each(logDecodeDependencies, (dependencyAbi, dependencyName) => { + this._web3Wrapper.abiDecoder.addABI(dependencyAbi, dependencyName); }); } } diff --git a/packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts b/packages/base-contract/src/subscription_manager.ts similarity index 82% rename from packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts rename to packages/base-contract/src/subscription_manager.ts index de4112bc41..ad7e6067a0 100644 --- a/packages/contract-wrappers/src/contract_wrappers/contract_wrapper.ts +++ b/packages/base-contract/src/subscription_manager.ts @@ -12,24 +12,16 @@ import { import { Block, BlockAndLogStreamer, Log } from 'ethereumjs-blockstream'; import * as _ from 'lodash'; -import { - BlockRange, - ContractEventArgs, - ContractEvents, - ContractWrappersError, - EventCallback, - IndexedFilterValues, -} from '../types'; -import { constants } from '../utils/constants'; -import { filterUtils } from '../utils/filter_utils'; +import { BlockRange, EventCallback, IndexedFilterValues, SubscriptionErrors } from './types'; +import { filterUtils } from './utils/filter_utils'; -export abstract class ContractWrapper { - public abstract abi: ContractAbi; - protected _networkId: number; - protected _web3Wrapper: Web3Wrapper; +const DEFAULT_BLOCK_POLLING_INTERVAL = 1000; + +export class SubscriptionManager { + public abi: ContractAbi; private _blockAndLogStreamerIfExists: BlockAndLogStreamer | undefined; - private readonly _blockPollingIntervalMs: number; private _blockAndLogStreamIntervalIfExists?: NodeJS.Timer; + private readonly _web3Wrapper: Web3Wrapper; private readonly _filters: { [filterToken: string]: FilterObject }; private readonly _filterCallbacks: { [filterToken: string]: EventCallback; @@ -43,26 +35,24 @@ export abstract class ContractWrapper { logUtils.warn(err); } } - constructor(web3Wrapper: Web3Wrapper, networkId: number, blockPollingIntervalMs?: number) { + constructor(abi: ContractAbi, web3Wrapper: Web3Wrapper) { + this.abi = abi; this._web3Wrapper = web3Wrapper; - this._networkId = networkId; - this._blockPollingIntervalMs = - blockPollingIntervalMs === undefined ? constants.DEFAULT_BLOCK_POLLING_INTERVAL : blockPollingIntervalMs; this._filters = {}; this._filterCallbacks = {}; this._blockAndLogStreamerIfExists = undefined; this._onLogAddedSubscriptionToken = undefined; this._onLogRemovedSubscriptionToken = undefined; } - protected _unsubscribeAll(): void { + public unsubscribeAll(): void { const filterTokens = _.keys(this._filterCallbacks); _.each(filterTokens, filterToken => { - this._unsubscribe(filterToken); + this.unsubscribe(filterToken); }); } - protected _unsubscribe(filterToken: string, err?: Error): void { + public unsubscribe(filterToken: string, err?: Error): void { if (this._filters[filterToken] === undefined) { - throw new Error(ContractWrappersError.SubscriptionNotFound); + throw new Error(SubscriptionErrors.SubscriptionNotFound); } if (err !== undefined) { const callback = this._filterCallbacks[filterToken]; @@ -74,24 +64,25 @@ export abstract class ContractWrapper { this._stopBlockAndLogStream(); } } - protected _subscribe( + public subscribe( address: string, eventName: ContractEvents, indexFilterValues: IndexedFilterValues, abi: ContractAbi, callback: EventCallback, isVerbose: boolean = false, + blockPollingIntervalMs?: number, ): string { const filter = filterUtils.getFilter(address, eventName, indexFilterValues, abi); if (this._blockAndLogStreamerIfExists === undefined) { - this._startBlockAndLogStream(isVerbose); + this._startBlockAndLogStream(isVerbose, blockPollingIntervalMs); } const filterToken = filterUtils.generateUUID(); this._filters[filterToken] = filter; this._filterCallbacks[filterToken] = callback as EventCallback; return filterToken; } - protected async _getLogsAsync( + public async getLogsAsync( address: string, eventName: ContractEvents, blockRange: BlockRange, @@ -123,21 +114,23 @@ export abstract class ContractWrapper { } }); } - private _startBlockAndLogStream(isVerbose: boolean): void { + private _startBlockAndLogStream(isVerbose: boolean, blockPollingIntervalMs?: number): void { if (this._blockAndLogStreamerIfExists !== undefined) { - throw new Error(ContractWrappersError.SubscriptionAlreadyPresent); + throw new Error(SubscriptionErrors.SubscriptionAlreadyPresent); } this._blockAndLogStreamerIfExists = new BlockAndLogStreamer( this._blockstreamGetBlockOrNullAsync.bind(this), this._blockstreamGetLogsAsync.bind(this), - ContractWrapper._onBlockAndLogStreamerError.bind(this, isVerbose), + SubscriptionManager._onBlockAndLogStreamerError.bind(this, isVerbose), ); const catchAllLogFilter = {}; this._blockAndLogStreamerIfExists.addLogFilter(catchAllLogFilter); + const _blockPollingIntervalMs = + blockPollingIntervalMs === undefined ? DEFAULT_BLOCK_POLLING_INTERVAL : blockPollingIntervalMs; this._blockAndLogStreamIntervalIfExists = intervalUtils.setAsyncExcludingInterval( this._reconcileBlockAsync.bind(this), - this._blockPollingIntervalMs, - ContractWrapper._onBlockAndLogStreamerError.bind(this, isVerbose), + _blockPollingIntervalMs, + SubscriptionManager._onBlockAndLogStreamerError.bind(this, isVerbose), ); let isRemoved = false; this._onLogAddedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogAdded( @@ -176,7 +169,7 @@ export abstract class ContractWrapper { } private _stopBlockAndLogStream(): void { if (this._blockAndLogStreamerIfExists === undefined) { - throw new Error(ContractWrappersError.SubscriptionNotFound); + throw new Error(SubscriptionErrors.SubscriptionNotFound); } this._blockAndLogStreamerIfExists.unsubscribeFromOnLogAdded(this._onLogAddedSubscriptionToken as string); this._blockAndLogStreamerIfExists.unsubscribeFromOnLogRemoved(this._onLogRemovedSubscriptionToken as string); diff --git a/packages/base-contract/src/types.ts b/packages/base-contract/src/types.ts new file mode 100644 index 0000000000..e8caac5eef --- /dev/null +++ b/packages/base-contract/src/types.ts @@ -0,0 +1,38 @@ +import { BlockParam, ContractEventArg, DecodedLogArgs, LogEntryEvent, LogWithDecodedArgs } from 'ethereum-types'; + +export type LogEvent = LogEntryEvent; +export interface DecodedLogEvent { + isRemoved: boolean; + log: LogWithDecodedArgs; +} + +export type EventCallback = ( + err: null | Error, + log?: DecodedLogEvent, +) => void; + +export interface ContractEvent { + logIndex: number; + transactionIndex: number; + transactionHash: string; + blockHash: string; + blockNumber: number; + address: string; + type: string; + event: string; + args: ContractEventArgs; +} + +export enum SubscriptionErrors { + SubscriptionNotFound = 'SUBSCRIPTION_NOT_FOUND', + SubscriptionAlreadyPresent = 'SUBSCRIPTION_ALREADY_PRESENT', +} + +export interface IndexedFilterValues { + [index: string]: ContractEventArg; +} + +export interface BlockRange { + fromBlock: BlockParam; + toBlock: BlockParam; +} diff --git a/packages/contract-wrappers/src/utils/filter_utils.ts b/packages/base-contract/src/utils/filter_utils.ts similarity index 96% rename from packages/contract-wrappers/src/utils/filter_utils.ts rename to packages/base-contract/src/utils/filter_utils.ts index f16c1975bc..a10899e9ce 100644 --- a/packages/contract-wrappers/src/utils/filter_utils.ts +++ b/packages/base-contract/src/utils/filter_utils.ts @@ -4,7 +4,7 @@ import * as jsSHA3 from 'js-sha3'; import * as _ from 'lodash'; import * as uuid from 'uuid/v4'; -import { BlockRange, ContractEvents, IndexedFilterValues } from '../types'; +import { BlockRange, IndexedFilterValues } from '../types'; const TOPIC_LENGTH = 32; @@ -12,7 +12,7 @@ export const filterUtils = { generateUUID(): string { return uuid(); }, - getFilter( + getFilter( address: string, eventName: ContractEvents, indexFilterValues: IndexedFilterValues, diff --git a/packages/connect/CHANGELOG.json b/packages/connect/CHANGELOG.json index 3c05a34894..87c07a93ca 100644 --- a/packages/connect/CHANGELOG.json +++ b/packages/connect/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1565296576, + "version": "5.0.16", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1564604963, + "version": "5.0.15", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1563957393, + "version": "5.0.14", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563193019, "version": "5.0.13", diff --git a/packages/connect/CHANGELOG.md b/packages/connect/CHANGELOG.md index 3d8c37dfef..5de49e4a73 100644 --- a/packages/connect/CHANGELOG.md +++ b/packages/connect/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v5.0.16 - _August 8, 2019_ + + * Dependencies updated + +## v5.0.15 - _July 31, 2019_ + + * Dependencies updated + +## v5.0.14 - _July 24, 2019_ + + * Dependencies updated + ## v5.0.13 - _July 15, 2019_ * Dependencies updated diff --git a/packages/connect/package.json b/packages/connect/package.json index 0831bc4efe..bfd9a6a4d7 100644 --- a/packages/connect/package.json +++ b/packages/connect/package.json @@ -1,6 +1,6 @@ { "name": "@0x/connect", - "version": "5.0.13", + "version": "5.0.16", "engines": { "node": ">=6.12" }, @@ -45,12 +45,12 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/connect/README.md", "dependencies": { - "@0x/assert": "^2.1.0", - "@0x/json-schemas": "^3.0.11", - "@0x/order-utils": "^8.2.2", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", + "@0x/assert": "^2.1.3", + "@0x/json-schemas": "^3.1.13", + "@0x/order-utils": "^8.2.5", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", "lodash": "^4.17.11", "query-string": "^6.0.0", "sinon": "^4.0.0", @@ -61,7 +61,7 @@ "@0x/tslint-config": "^3.0.1", "@types/fetch-mock": "^6.0.3", "@types/lodash": "4.14.104", - "@types/mocha": "^2.2.42", + "@types/mocha": "^5.2.7", "@types/query-string": "^5.1.0", "@types/sinon": "^2.2.2", "@types/uuid": "^3.4.3", @@ -73,7 +73,7 @@ "dirty-chai": "^2.0.1", "fetch-mock": "^5.13.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "shx": "^0.2.2", diff --git a/packages/contract-addresses/CHANGELOG.json b/packages/contract-addresses/CHANGELOG.json index 79a44ddddc..ea304f746c 100644 --- a/packages/contract-addresses/CHANGELOG.json +++ b/packages/contract-addresses/CHANGELOG.json @@ -1,4 +1,23 @@ [ + { + "version": "3.1.0", + "changes": [ + { + "note": "Added DevUtils", + "pr": 2060 + } + ] + }, + { + "version": "3.0.3", + "changes": [ + { + "note": "Added StaticCallAssetProxy and ERC1155AssetProxy", + "pr": 2021 + } + ], + "timestamp": 1565296576 + }, { "version": "3.0.2", "changes": [ diff --git a/packages/contract-addresses/CHANGELOG.md b/packages/contract-addresses/CHANGELOG.md index 7ca3fbdb16..1ac4cb458d 100644 --- a/packages/contract-addresses/CHANGELOG.md +++ b/packages/contract-addresses/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.0.3 - _August 8, 2019_ + + * Added StaticCallAssetProxy and ERC1155AssetProxy (#2021) + ## v3.0.2 - _July 15, 2019_ * Update OrderValidator testnet addresses diff --git a/packages/contract-addresses/package.json b/packages/contract-addresses/package.json index f836f79eb8..b58498ad5e 100644 --- a/packages/contract-addresses/package.json +++ b/packages/contract-addresses/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contract-addresses", - "version": "3.0.2", + "version": "3.0.3", "engines": { "node": ">=6.12" }, diff --git a/packages/contract-addresses/src/index.ts b/packages/contract-addresses/src/index.ts index aa3ff7835c..94c7a467b3 100644 --- a/packages/contract-addresses/src/index.ts +++ b/packages/contract-addresses/src/index.ts @@ -12,6 +12,10 @@ export interface ContractAddresses { dutchAuction: string; coordinatorRegistry: string; coordinator: string; + multiAssetProxy: string; + staticCallProxy: string; + erc1155Proxy: string; + devUtils: string; } export enum NetworkId { @@ -37,6 +41,10 @@ const networkToAddresses: { [networkId: number]: ContractAddresses } = { dutchAuction: '0xa3856622276a64fee0f17f67329fac24368d4aae', coordinatorRegistry: '0x45797531b873fd5e519477a070a955764c1a5b07', coordinator: '0xa14857e8930acd9a882d33ec20559beb5479c8a6', + multiAssetProxy: '0xef701d5389ae74503d633396c4d654eabedc9d78', + staticCallProxy: '0x3517b88c19508c08650616019062b898ab65ed29', + erc1155Proxy: '0x7eefbd48fd63d441ec7435d024ec7c5131019add', + devUtils: '0x92d9a4d50190ae04e03914db2ee650124af844e6', }, 3: { erc20Proxy: '0xb1408f4c245a23c31b98d2c626777d4c0d766caa', @@ -50,6 +58,10 @@ const networkToAddresses: { [networkId: number]: ContractAddresses } = { dutchAuction: '0xe5f862f7811af180990025b6259b02feb0a0b8dc', coordinatorRegistry: '0x403cc23e88c17c4652fb904784d1af640a6722d9', coordinator: '0x2ba02e03ee0029311e0f43715307870a3e701b53', + multiAssetProxy: '0xab8fbd189c569ccdee3a4d929bb7f557be4028f6', + staticCallProxy: '0xe1b97e47aa3796276033a5341e884d2ba46b6ac1', + erc1155Proxy: '0x19bb6caa3bc34d39e5a23cedfa3e6c7e7f3c931d', + devUtils: '0x3e0b46bad8e374e4a110c12b832cb120dbe4a479', }, 4: { exchange: '0xbff9493f92a3df4b0429b6d00743b3cfb4c85831', @@ -63,6 +75,10 @@ const networkToAddresses: { [networkId: number]: ContractAddresses } = { dutchAuction: '0xe5f862f7811af180990025b6259b02feb0a0b8dc', coordinatorRegistry: '0x1084b6a398e47907bae43fec3ff4b677db6e4fee', coordinator: '0x2ba02e03ee0029311e0f43715307870a3e701b53', + multiAssetProxy: '0xb34cde0ad3a83d04abebc0b66e75196f22216621', + staticCallProxy: '0xe1b97e47aa3796276033a5341e884d2ba46b6ac1', + erc1155Proxy: '0x19bb6caa3bc34d39e5a23cedfa3e6c7e7f3c931d', + devUtils: '0x2d4a9abda7b8b3605c8dbd34e3550a7467c78287', }, 42: { erc20Proxy: '0xf1ec01d6236d3cd881a0bf0130ea25fe4234003e', @@ -76,20 +92,28 @@ const networkToAddresses: { [networkId: number]: ContractAddresses } = { dutchAuction: '0xe5f862f7811af180990025b6259b02feb0a0b8dc', coordinatorRegistry: '0x09fb99968c016a3ff537bf58fb3d9fe55a7975d5', coordinator: '0x2ba02e03ee0029311e0f43715307870a3e701b53', + multiAssetProxy: '0xf6313a772c222f51c28f2304c0703b8cf5428fd8', + staticCallProxy: '0x48e94bdb9033640d45ea7c721e25f380f8bffa43', + erc1155Proxy: '0x64517fa2b480ba3678a2a3c0cf08ef7fd4fad36f', + devUtils: '0x1e3616bc5144362f95d72de41874395567697e93', }, // NetworkId 50 represents our Ganache snapshot generated from migrations. 50: { erc20Proxy: '0x1dc4c1cefef38a777b15aa20260a54e584b16c48', erc721Proxy: '0x1d7022f5b17d2f8b695918fb48fa1089c9f85401', + erc1155Proxy: '0x6a4a62e5a7ed13c361b176a5f62c2ee620ac0df8', zrxToken: '0x871dd7c2b4b25e1aa18728e9d5f2af4c4e431f5c', etherToken: '0x0b1ba0af832d7c05fd64161e0db78e85978e8082', exchange: '0x48bacb9266a570d521063ef5dd96e61686dbe788', - assetProxyOwner: '0x04b5dadd2c0d6a261bfafbc964e0cac48585def3', - forwarder: '0x6000eca38b8b5bba64986182fe2a69c57f6b5414', - orderValidator: '0x32eecaf51dfea9618e9bc94e9fbfddb1bbdcba15', - dutchAuction: '0x7e3f4e1deb8d3a05d9d2da87d9521268d0ec3239', - coordinatorRegistry: '0xaa86dda78e9434aca114b6676fc742a18d15a1cc', - coordinator: '0x4d3d5c850dd5bd9d6f4adda3dd039a3c8054ca29', + assetProxyOwner: '0x8d42e38980ce74736c21c059b2240df09958d3c8', + forwarder: '0xaa86dda78e9434aca114b6676fc742a18d15a1cc', + orderValidator: '0x4d3d5c850dd5bd9d6f4adda3dd039a3c8054ca29', + dutchAuction: '0xa31e64ea55b9b6bbb9d6a676738e9a5b23149f84', + coordinatorRegistry: '0x1941ff73d1154774d87521d2d0aaad5d19c8df60', + coordinator: '0x0d8b0dd11f5d34ed41d556def5f841900d5b1c6b', + multiAssetProxy: '0xcfc18cec799fbd1793b5c43e773c98d4d61cc2db', + staticCallProxy: '0x6dfff22588be9b3ef8cf0ad6dc9b84796f9fb45f', + devUtils: '0x38ef19fdf8e8415f18c307ed71967e19aac28ba1', }, }; diff --git a/packages/contract-artifacts/CHANGELOG.json b/packages/contract-artifacts/CHANGELOG.json index 4bd5b1d868..71ee909a94 100644 --- a/packages/contract-artifacts/CHANGELOG.json +++ b/packages/contract-artifacts/CHANGELOG.json @@ -1,4 +1,40 @@ [ + { + "version": "2.1.0", + "changes": [ + { + "note": "Added DevUtils", + "pr": 2060 + } + ] + }, + { + "timestamp": 1565296576, + "version": "2.0.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1564604963, + "version": "2.0.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1563957393, + "version": "2.0.2", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563006338, "version": "2.0.1", diff --git a/packages/contract-artifacts/CHANGELOG.md b/packages/contract-artifacts/CHANGELOG.md index 37dc28f21a..0b79cef6bd 100644 --- a/packages/contract-artifacts/CHANGELOG.md +++ b/packages/contract-artifacts/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.4 - _August 8, 2019_ + + * Dependencies updated + +## v2.0.3 - _July 31, 2019_ + + * Dependencies updated + +## v2.0.2 - _July 24, 2019_ + + * Dependencies updated + ## v2.0.1 - _July 13, 2019_ * Dependencies updated diff --git a/packages/contract-artifacts/artifacts/DevUtils.json b/packages/contract-artifacts/artifacts/DevUtils.json new file mode 100644 index 0000000000..58e6484998 --- /dev/null +++ b/packages/contract-artifacts/artifacts/DevUtils.json @@ -0,0 +1,501 @@ +{ + "schemaVersion": "2.0.0", + "contractName": "DevUtils", + "compilerOutput": { + "abi": [ + { + "constant": true, + "inputs": [{ "name": "assetData", "type": "bytes" }], + "name": "decodeERC721AssetData", + "outputs": [ + { "name": "assetProxyId", "type": "bytes4" }, + { "name": "tokenAddress", "type": "address" }, + { "name": "tokenId", "type": "uint256" } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "name": "ownerAddress", "type": "address" }, { "name": "assetData", "type": "bytes" }], + "name": "getBalanceAndAssetProxyAllowance", + "outputs": [{ "name": "balance", "type": "uint256" }, { "name": "allowance", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "ERC1155_PROXY_ID", + "outputs": [{ "name": "", "type": "bytes4" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "name": "ownerAddress", "type": "address" }, { "name": "assetData", "type": "bytes" }], + "name": "getTransferableAssetAmount", + "outputs": [{ "name": "transferableAssetAmount", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "name": "ownerAddress", "type": "address" }, { "name": "assetData", "type": "bytes[]" }], + "name": "getBatchAssetProxyAllowances", + "outputs": [{ "name": "allowances", "type": "uint256[]" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "name": "tokenAddress", "type": "address" }], + "name": "encodeERC20AssetData", + "outputs": [{ "name": "assetData", "type": "bytes" }], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "name": "transactionData", "type": "bytes" }], + "name": "decodeZeroExTransactionData", + "outputs": [ + { "name": "functionName", "type": "string" }, + { + "components": [ + { "name": "makerAddress", "type": "address" }, + { "name": "takerAddress", "type": "address" }, + { "name": "feeRecipientAddress", "type": "address" }, + { "name": "senderAddress", "type": "address" }, + { "name": "makerAssetAmount", "type": "uint256" }, + { "name": "takerAssetAmount", "type": "uint256" }, + { "name": "makerFee", "type": "uint256" }, + { "name": "takerFee", "type": "uint256" }, + { "name": "expirationTimeSeconds", "type": "uint256" }, + { "name": "salt", "type": "uint256" }, + { "name": "makerAssetData", "type": "bytes" }, + { "name": "takerAssetData", "type": "bytes" } + ], + "name": "orders", + "type": "tuple[]" + }, + { "name": "takerAssetFillAmounts", "type": "uint256[]" }, + { "name": "signatures", "type": "bytes[]" } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "name": "ownerAddress", "type": "address" }, { "name": "assetData", "type": "bytes" }], + "name": "getBalance", + "outputs": [{ "name": "balance", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "components": [ + { "name": "makerAddress", "type": "address" }, + { "name": "takerAddress", "type": "address" }, + { "name": "feeRecipientAddress", "type": "address" }, + { "name": "senderAddress", "type": "address" }, + { "name": "makerAssetAmount", "type": "uint256" }, + { "name": "takerAssetAmount", "type": "uint256" }, + { "name": "makerFee", "type": "uint256" }, + { "name": "takerFee", "type": "uint256" }, + { "name": "expirationTimeSeconds", "type": "uint256" }, + { "name": "salt", "type": "uint256" }, + { "name": "makerAssetData", "type": "bytes" }, + { "name": "takerAssetData", "type": "bytes" } + ], + "name": "orders", + "type": "tuple[]" + }, + { "name": "signatures", "type": "bytes[]" } + ], + "name": "getOrderRelevantStates", + "outputs": [ + { + "components": [ + { "name": "orderStatus", "type": "uint8" }, + { "name": "orderHash", "type": "bytes32" }, + { "name": "orderTakerAssetFilledAmount", "type": "uint256" } + ], + "name": "ordersInfo", + "type": "tuple[]" + }, + { "name": "fillableTakerAssetAmounts", "type": "uint256[]" }, + { "name": "isValidSignature", "type": "bool[]" } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "ERC20_PROXY_ID", + "outputs": [{ "name": "", "type": "bytes4" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "name": "assetData", "type": "bytes" }], + "name": "decodeERC20AssetData", + "outputs": [ + { "name": "assetProxyId", "type": "bytes4" }, + { "name": "tokenAddress", "type": "address" } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "components": [ + { "name": "makerAddress", "type": "address" }, + { "name": "takerAddress", "type": "address" }, + { "name": "feeRecipientAddress", "type": "address" }, + { "name": "senderAddress", "type": "address" }, + { "name": "makerAssetAmount", "type": "uint256" }, + { "name": "takerAssetAmount", "type": "uint256" }, + { "name": "makerFee", "type": "uint256" }, + { "name": "takerFee", "type": "uint256" }, + { "name": "expirationTimeSeconds", "type": "uint256" }, + { "name": "salt", "type": "uint256" }, + { "name": "makerAssetData", "type": "bytes" }, + { "name": "takerAssetData", "type": "bytes" } + ], + "name": "order", + "type": "tuple" + }, + { "name": "signature", "type": "bytes" } + ], + "name": "getOrderRelevantState", + "outputs": [ + { + "components": [ + { "name": "orderStatus", "type": "uint8" }, + { "name": "orderHash", "type": "bytes32" }, + { "name": "orderTakerAssetFilledAmount", "type": "uint256" } + ], + "name": "orderInfo", + "type": "tuple" + }, + { "name": "fillableTakerAssetAmount", "type": "uint256" }, + { "name": "isValidSignature", "type": "bool" } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "name": "assetData", "type": "bytes" }], + "name": "decodeERC1155AssetData", + "outputs": [ + { "name": "assetProxyId", "type": "bytes4" }, + { "name": "tokenAddress", "type": "address" }, + { "name": "tokenIds", "type": "uint256[]" }, + { "name": "tokenValues", "type": "uint256[]" }, + { "name": "callbackData", "type": "bytes" } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "name": "addresses", "type": "address[]" }], + "name": "getEthBalances", + "outputs": [{ "name": "", "type": "uint256[]" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "ERC721_PROXY_ID", + "outputs": [{ "name": "", "type": "bytes4" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "name": "tokenAddress", "type": "address" }, { "name": "tokenId", "type": "uint256" }], + "name": "encodeERC721AssetData", + "outputs": [{ "name": "assetData", "type": "bytes" }], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "MULTI_ASSET_PROXY_ID", + "outputs": [{ "name": "", "type": "bytes4" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "name": "tokenAddress", "type": "address" }, + { "name": "tokenIds", "type": "uint256[]" }, + { "name": "tokenValues", "type": "uint256[]" }, + { "name": "callbackData", "type": "bytes" } + ], + "name": "encodeERC1155AssetData", + "outputs": [{ "name": "assetData", "type": "bytes" }], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "name": "tokenAddress", "type": "address" }, { "name": "tokenId", "type": "uint256" }], + "name": "getERC721TokenOwner", + "outputs": [{ "name": "ownerAddress", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "name": "assetData", "type": "bytes" }], + "name": "decodeMultiAssetData", + "outputs": [ + { "name": "assetProxyId", "type": "bytes4" }, + { "name": "amounts", "type": "uint256[]" }, + { "name": "nestedAssetData", "type": "bytes[]" } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "name": "ownerAddress", "type": "address" }, { "name": "assetData", "type": "bytes[]" }], + "name": "getBatchBalances", + "outputs": [{ "name": "balances", "type": "uint256[]" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "name": "ownerAddress", "type": "address" }, { "name": "assetData", "type": "bytes" }], + "name": "getAssetProxyAllowance", + "outputs": [{ "name": "allowance", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "name": "amounts", "type": "uint256[]" }, + { "name": "nestedAssetData", "type": "bytes[]" } + ], + "name": "encodeMultiAssetData", + "outputs": [{ "name": "assetData", "type": "bytes" }], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "STATIC_CALL_PROXY_ID", + "outputs": [{ "name": "", "type": "bytes4" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "name": "ownerAddress", "type": "address" }, { "name": "assetData", "type": "bytes[]" }], + "name": "getBatchBalancesAndAssetProxyAllowances", + "outputs": [{ "name": "balances", "type": "uint256[]" }, { "name": "allowances", "type": "uint256[]" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "name": "_exchange", "type": "address" }, { "name": "_zrxAssetData", "type": "bytes" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + } + ], + "devdoc": { + "methods": { + "decodeERC1155AssetData(bytes)": { + "details": "Decode ERC-1155 asset data from the format described in the AssetProxy contract specification.", + "params": { "assetData": "AssetProxy-compliant asset data describing an ERC-1155 set of assets." }, + "return": "The ERC-1155 AssetProxy identifier, the address of the ERC-1155 contract hosting the assets, an array of the identifiers of the assets to be traded, an array of asset amounts to be traded, and callback data. Each element of the arrays corresponds to the same-indexed element of the other array. Return values specified as `memory` are returned as pointers to locations within the memory of the input parameter `assetData`." + }, + "decodeERC20AssetData(bytes)": { + "details": "Decode ERC-20 asset data from the format described in the AssetProxy contract specification.", + "params": { "assetData": "AssetProxy-compliant asset data describing an ERC-20 asset." }, + "return": "The ERC-20 AssetProxy identifier, and the address of the ERC-20 contract hosting this asset." + }, + "decodeERC721AssetData(bytes)": { + "details": "Decode ERC-721 asset data from the format described in the AssetProxy contract specification.", + "params": { "assetData": "AssetProxy-compliant asset data describing an ERC-721 asset." }, + "return": "The ERC-721 AssetProxy identifier, the address of the ERC-721 contract hosting this asset, and the identifier of the specific asset to be traded." + }, + "decodeMultiAssetData(bytes)": { + "details": "Decode multi-asset data from the format described in the AssetProxy contract specification.", + "params": { "assetData": "AssetProxy-compliant data describing a multi-asset basket." }, + "return": "The Multi-Asset AssetProxy identifier, an array of the amounts of the assets to be traded, and an array of the AssetProxy-compliant data describing each asset to be traded. Each element of the arrays corresponds to the same-indexed element of the other array." + }, + "decodeZeroExTransactionData(bytes)": { + "details": "Decodes the call data for an Exchange contract method call.", + "params": { "transactionData": "ABI-encoded calldata for an Exchange contract method call." }, + "return": "The name of the function called, and the parameters it was given. For single-order fills and cancels, the arrays will have just one element." + }, + "encodeERC1155AssetData(address,uint256[],uint256[],bytes)": { + "details": "Encode ERC-1155 asset data into the format described in the AssetProxy contract specification.", + "params": { + "callbackData": "Data to be passed to receiving contracts when a transfer is performed.", + "tokenAddress": "The address of the ERC-1155 contract hosting the asset(s) to be traded.", + "tokenIds": "The identifiers of the specific assets to be traded.", + "tokenValues": "The amounts of each asset to be traded." + }, + "return": "AssetProxy-compliant asset data describing the set of assets." + }, + "encodeERC20AssetData(address)": { + "details": "Encode ERC-20 asset data into the format described in the AssetProxy contract specification.", + "params": { "tokenAddress": "The address of the ERC-20 contract hosting the asset to be traded." }, + "return": "AssetProxy-compliant data describing the asset." + }, + "encodeERC721AssetData(address,uint256)": { + "details": "Encode ERC-721 asset data into the format described in the AssetProxy specification.", + "params": { + "tokenAddress": "The address of the ERC-721 contract hosting the asset to be traded.", + "tokenId": "The identifier of the specific asset to be traded." + }, + "return": "AssetProxy-compliant asset data describing the asset." + }, + "encodeMultiAssetData(uint256[],bytes[])": { + "details": "Encode data for multiple assets, per the AssetProxy contract specification.", + "params": { + "amounts": "The amounts of each asset to be traded.", + "nestedAssetData": "AssetProxy-compliant data describing each asset to be traded." + }, + "return": "AssetProxy-compliant data describing the set of assets." + }, + "getAssetProxyAllowance(address,bytes)": { + "details": "Returns the number of asset(s) (described by assetData) that the corresponding AssetProxy contract is authorized to spend. When the asset data contains multiple assets (eg for Multi-Asset), the return value indicates how many complete \"baskets\" of those assets may be spent by all of the corresponding AssetProxy contracts.", + "params": { + "assetData": "Details of asset, encoded per the AssetProxy contract specification.", + "ownerAddress": "Owner of the assets specified by assetData." + }, + "return": "Number of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend." + }, + "getBalance(address,bytes)": { + "details": "Returns the owner's balance of the assets(s) specified in assetData. When the asset data contains multiple assets (eg in ERC1155 or Multi-Asset), the return value indicates how many complete \"baskets\" of those assets are owned by owner.", + "params": { + "assetData": "Details of asset, encoded per the AssetProxy contract specification.", + "ownerAddress": "Owner of the assets specified by assetData." + }, + "return": "Number of assets (or asset baskets) held by owner." + }, + "getBalanceAndAssetProxyAllowance(address,bytes)": { + "details": "Calls getBalance() and getAllowance() for assetData.", + "params": { + "assetData": "Details of asset, encoded per the AssetProxy contract specification.", + "ownerAddress": "Owner of the assets specified by assetData." + }, + "return": "Number of assets (or asset baskets) held by owner, and number of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend." + }, + "getBatchAssetProxyAllowances(address,bytes[])": { + "details": "Calls getAssetProxyAllowance() for each element of assetData.", + "params": { + "assetData": "Array of asset details, each encoded per the AssetProxy contract specification.", + "ownerAddress": "Owner of the assets specified by assetData." + }, + "return": "An array of asset allowances from getAllowance(), with each element corresponding to the same-indexed element in the assetData input." + }, + "getBatchBalances(address,bytes[])": { + "details": "Calls getBalance() for each element of assetData.", + "params": { + "assetData": "Array of asset details, each encoded per the AssetProxy contract specification.", + "ownerAddress": "Owner of the assets specified by assetData." + }, + "return": "Array of asset balances from getBalance(), with each element corresponding to the same-indexed element in the assetData input." + }, + "getBatchBalancesAndAssetProxyAllowances(address,bytes[])": { + "details": "Calls getBatchBalances() and getBatchAllowances() for each element of assetData.", + "params": { + "assetData": "Array of asset details, each encoded per the AssetProxy contract specification.", + "ownerAddress": "Owner of the assets specified by assetData." + }, + "return": "An array of asset balances from getBalance(), and an array of asset allowances from getAllowance(), with each element corresponding to the same-indexed element in the assetData input." + }, + "getERC721TokenOwner(address,uint256)": { + "details": "Calls `asset.ownerOf(tokenId)`, but returns a null owner instead of reverting on an unowned asset.", + "params": { + "tokenAddress": "Address of ERC721 asset.", + "tokenId": "The identifier for the specific NFT." + }, + "return": "Owner of tokenId or null address if unowned." + }, + "getEthBalances(address[])": { + "details": "Batch fetches ETH balances", + "params": { "addresses": "Array of addresses." }, + "return": "Array of ETH balances." + }, + "getOrderRelevantState((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes)": { + "details": "Fetches all order-relevant information needed to validate if the supplied order is fillable.", + "params": { + "order": "The order structure.", + "signature": "Signature provided by maker that proves the order's authenticity. `0x01` can always be provided if the signature does not need to be validated." + }, + "return": "The orderInfo (hash, status, and `takerAssetAmount` already filled for the given order), fillableTakerAssetAmount (amount of the order's `takerAssetAmount` that is fillable given all on-chain state), and isValidSignature (validity of the provided signature). NOTE: If the `takerAssetData` encodes data for multiple assets, `fillableTakerAssetAmount` will represent a \"scaled\" amount, meaning it must be multiplied by all the individual asset amounts within the `takerAssetData` to get the final amount of each asset that can be filled." + }, + "getOrderRelevantStates((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],bytes[])": { + "details": "Fetches all order-relevant information needed to validate if the supplied orders are fillable.", + "params": { + "orders": "Array of order structures.", + "signatures": "Array of signatures provided by makers that prove the authenticity of the orders. `0x01` can always be provided if a signature does not need to be validated." + }, + "return": "The ordersInfo (array of the hash, status, and `takerAssetAmount` already filled for each order), fillableTakerAssetAmounts (array of amounts for each order's `takerAssetAmount` that is fillable given all on-chain state), and isValidSignature (array containing the validity of each provided signature). NOTE: If the `takerAssetData` encodes data for multiple assets, each element of `fillableTakerAssetAmounts` will represent a \"scaled\" amount, meaning it must be multiplied by all the individual asset amounts within the `takerAssetData` to get the final amount of each asset that can be filled." + }, + "getTransferableAssetAmount(address,bytes)": { + "details": "Gets the amount of an asset transferable by the owner.", + "params": { + "assetData": "Description of tokens, per the AssetProxy contract specification.", + "ownerAddress": "Address of the owner of the asset." + }, + "return": "The amount of the asset tranferable by the owner. NOTE: If the `assetData` encodes data for multiple assets, the `transferableAssetAmount` will represent the amount of times the entire `assetData` can be transferred. To calculate the total individual transferable amounts, this scaled `transferableAmount` must be multiplied by the individual asset amounts located within the `assetData`." + } + } + }, + "evm": { + "bytecode": { + "object": "0x60806040523480156200001157600080fd5b5060405162004f8938038062004f898339810160408190526200003491620004ae565b600080546001600160a01b0319166001600160a01b0384811691909117918290556040517f60704108000000000000000000000000000000000000000000000000000000008152849284928492911690636070410890620000ba907ff47261b0000000000000000000000000000000000000000000000000000000009060040162000589565b60206040518083038186803b158015620000d357600080fd5b505afa158015620000e8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506200010e919081019062000488565b600180546001600160a01b0319166001600160a01b039283161790556000546040517f607041080000000000000000000000000000000000000000000000000000000081529116906360704108906200018c907f02571792000000000000000000000000000000000000000000000000000000009060040162000589565b60206040518083038186803b158015620001a557600080fd5b505afa158015620001ba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620001e0919081019062000488565b600280546001600160a01b0319166001600160a01b039283161790556000546040517f607041080000000000000000000000000000000000000000000000000000000081529116906360704108906200025e907fa7cb5fb7000000000000000000000000000000000000000000000000000000009060040162000589565b60206040518083038186803b1580156200027757600080fd5b505afa1580156200028c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620002b2919081019062000488565b600380546001600160a01b0319166001600160a01b039283161790556000546040517f6070410800000000000000000000000000000000000000000000000000000000815291169063607041089062000330907fc339d10a000000000000000000000000000000000000000000000000000000009060040162000589565b60206040518083038186803b1580156200034957600080fd5b505afa1580156200035e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525062000384919081019062000488565b600480546001600160a01b0319166001600160a01b0392909216919091179055508051620003ba906005906020840190620003c5565b5050505050620005b6565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200040857805160ff191683800117855562000438565b8280016001018555821562000438579182015b82811115620004385782518255916020019190600101906200041b565b50620004469291506200044a565b5090565b6200046791905b8082111562000446576000815560010162000451565b90565b80516001600160a01b03811681146200048257600080fd5b92915050565b6000602082840312156200049b57600080fd5b620004a783836200046a565b9392505050565b60008060408385031215620004c1578081fd5b620004cd84846200046a565b602084810151919350906001600160401b0380821115620004ec578384fd5b81860187601f820112620004fe578485fd5b80519250818311156200050f578485fd5b604051601f8401601f19168101850183811182821017156200052f578687fd5b604052838152818401850189101562000546578586fd5b8592505b838310156200056957818301850151818401860152918401916200054a565b838311156200057a57858585830101525b80955050505050509250929050565b7fffffffff0000000000000000000000000000000000000000000000000000000091909116815260200190565b6149c380620005c66000396000f3fe608060405234801561001057600080fd5b50600436106101a35760003560e01c80639eadc835116100ee578063b698846311610097578063d186037f11610071578063d186037f146103ce578063d3d862d1146103e1578063d965b998146103f4578063e4e6e7da146103fc576101a3565b8063b698846314610379578063bbb2dcf614610399578063d001c5dc146103bb576101a3565b8063a6627e9f116100c8578063a6627e9f1461034b578063b37fda041461035e578063b43cffe114610366576101a3565b80639eadc8351461030c578063a0901e5114610330578063a28fe02e14610343576101a3565b80636f83188e116101505780638ee1a6421161012a5780638ee1a642146102c15780638f4ce479146102c95780638f5afa52146102ea576101a3565b80636f83188e146102695780637d7275121461028c5780637f46448d1461029f576101a3565b80632322cf76116101815780632322cf76146102095780634dfdac2014610229578063590aa87514610249576101a3565b806304a5618a146101a85780630d7b7d76146101d35780631bd0eb8f146101f4575b600080fd5b6101bb6101b6366004613ccb565b61041d565b6040516101ca939291906143d1565b60405180910390f35b6101e66101e1366004613940565b6104e3565b6040516101ca929190614892565b6101fc610505565b6040516101ca91906142d4565b61021c610217366004613940565b610529565b6040516101ca9190614889565b61023c610237366004613858565b610551565b6040516101ca9190614239565b61025c61025736600461383b565b6105d4565b6040516101ca919061446e565b61027c610277366004613ccb565b610673565b6040516101ca94939291906144cc565b61021c61029a366004613940565b6114f7565b6102b26102ad366004613a83565b611b87565b6040516101ca9392919061419d565b6101fc611cbf565b6102dc6102d7366004613ccb565b611ce3565b6040516101ca929190614301565b6102fd6102f8366004613d8b565b611d8b565b6040516101ca93929190614852565b61031f61031a366004613ccb565b612081565b6040516101ca959493929190614349565b61023c61033e3660046139b2565b612144565b6101fc6121ca565b61025c610359366004613986565b6121ee565b6101fc612290565b61025c6103743660046138a8565b6122b4565b61038c610387366004613986565b61235c565b6040516101ca91906140d0565b6103ac6103a7366004613ccb565b61247a565b6040516101ca93929190614421565b61023c6103c9366004613858565b61253f565b61021c6103dc366004613940565b6125ad565b61025c6103ef366004613c02565b612cb5565b6101fc612cd2565b61040f61040a366004613858565b612cf6565b6040516101ca92919061427a565b60008080610431848263ffffffff612d0f16565b92507fffffffff0000000000000000000000000000000000000000000000000000000083167f0257179200000000000000000000000000000000000000000000000000000000146104b7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104ae9061481b565b60405180910390fd5b6104c884601063ffffffff612d7a16565b91506104db84602463ffffffff612dd916565b929491935050565b6000806104f084846114f7565b91506104fc84846125ad565b90509250929050565b7fa7cb5fb70000000000000000000000000000000000000000000000000000000081565b600080600061053885856104e3565b915091506105468282612dec565b925050505b92915050565b606060008251905080604051908082528060200260200182016040528015610583578160200160208202803883390190505b50915060005b8181146105cc576105ad858583815181106105a057fe5b60200260200101516125ad565b8382815181106105b957fe5b6020908102919091010152600101610589565b505092915050565b606063f47261b060e01b826040516024016105ef91906140d0565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050919050565b6060808080600061068a868263ffffffff612d0f16565b90507fffffffff0000000000000000000000000000000000000000000000000000000081167f4ac14782000000000000000000000000000000000000000000000000000000001415610713576040518060400160405280601181526020017f626174636843616e63656c4f72646572730000000000000000000000000000008152509450610e61565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f297bb70b00000000000000000000000000000000000000000000000000000000141561079a576040518060400160405280600f81526020017f626174636846696c6c4f726465727300000000000000000000000000000000008152509450610e61565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f50dde190000000000000000000000000000000000000000000000000000000001415610821576040518060400160405280601681526020017f626174636846696c6c4f72646572734e6f5468726f77000000000000000000008152509450610e61565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f4d0ae5460000000000000000000000000000000000000000000000000000000014156108a8576040518060400160405280601581526020017f626174636846696c6c4f724b696c6c4f726465727300000000000000000000008152509450610e61565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fd46b02c300000000000000000000000000000000000000000000000000000000141561092f576040518060400160405280600b81526020017f63616e63656c4f726465720000000000000000000000000000000000000000008152509450610e61565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fb4be83d50000000000000000000000000000000000000000000000000000000014156109b6576040518060400160405280600981526020017f66696c6c4f7264657200000000000000000000000000000000000000000000008152509450610e61565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f3e228bae000000000000000000000000000000000000000000000000000000001415610a3d576040518060400160405280601081526020017f66696c6c4f726465724e6f5468726f77000000000000000000000000000000008152509450610e61565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f64a3bc15000000000000000000000000000000000000000000000000000000001415610ac4576040518060400160405280600f81526020017f66696c6c4f724b696c6c4f7264657200000000000000000000000000000000008152509450610e61565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fe5fa431b000000000000000000000000000000000000000000000000000000001415610b4b576040518060400160405280600f81526020017f6d61726b65744275794f726465727300000000000000000000000000000000008152509450610e61565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fa3e20380000000000000000000000000000000000000000000000000000000001415610bd2576040518060400160405280601681526020017f6d61726b65744275794f72646572734e6f5468726f77000000000000000000008152509450610e61565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f7e1d9808000000000000000000000000000000000000000000000000000000001415610c59576040518060400160405280601081526020017f6d61726b657453656c6c4f7264657273000000000000000000000000000000008152509450610e61565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fdd1c7d18000000000000000000000000000000000000000000000000000000001415610ce0576040518060400160405280601781526020017f6d61726b657453656c6c4f72646572734e6f5468726f770000000000000000008152509450610e61565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f3c28d861000000000000000000000000000000000000000000000000000000001415610d67576040518060400160405280600b81526020017f6d617463684f72646572730000000000000000000000000000000000000000008152509450610e61565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f4f9559b1000000000000000000000000000000000000000000000000000000001480610df857507fffffffff0000000000000000000000000000000000000000000000000000000081167fbfc8bfce00000000000000000000000000000000000000000000000000000000145b15610e2f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104ae9061472a565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104ae906146f3565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f4ac14782000000000000000000000000000000000000000000000000000000001415610f1e578551610ec190879060049063ffffffff612e0216565b806020019051610ed49190810190613a4e565b604080516000808252602082019092529195505b5060408051600080825260208201909252919450610f16565b6060815260200190600190039081610f015790505b5091506114ef565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f4d0ae546000000000000000000000000000000000000000000000000000000001480610faf57507fffffffff0000000000000000000000000000000000000000000000000000000081167f50dde19000000000000000000000000000000000000000000000000000000000145b80610ffb57507fffffffff0000000000000000000000000000000000000000000000000000000081167f297bb70b00000000000000000000000000000000000000000000000000000000145b156110155761100986612ec7565b919550935091506114ef565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fd46b02c30000000000000000000000000000000000000000000000000000000014156111155760408051600180825281830190925290816020015b61107c6132e9565b81526020019060019003908161107457505086519094506110a790879060049063ffffffff612e0216565b8060200190516110ba9190810190613d56565b846000815181106110c757fe5b60200260200101819052506000604051908082528060200260200182016040528015610ee8578160200160208202803883390190505060408051600080825260208201909252919450610f16565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f64a3bc150000000000000000000000000000000000000000000000000000000014806111a657507fffffffff0000000000000000000000000000000000000000000000000000000081167fb4be83d500000000000000000000000000000000000000000000000000000000145b806111f257507fffffffff0000000000000000000000000000000000000000000000000000000081167f3e228bae00000000000000000000000000000000000000000000000000000000145b156112005761100986612f03565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fe5fa431b00000000000000000000000000000000000000000000000000000000148061129157507fffffffff0000000000000000000000000000000000000000000000000000000081167fa3e2038000000000000000000000000000000000000000000000000000000000145b806112dd57507fffffffff0000000000000000000000000000000000000000000000000000000081167f7e1d980800000000000000000000000000000000000000000000000000000000145b8061132957507fffffffff0000000000000000000000000000000000000000000000000000000081167fdd1c7d1800000000000000000000000000000000000000000000000000000000145b156113375761100986612ffd565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f3c28d8610000000000000000000000000000000000000000000000000000000014156114ef576113896132e9565b6113916132e9565b6060806113ab60048b518c612e029092919063ffffffff16565b8060200190516113be9190810190613de5565b604080516002808252606082019092529498509296509094509250816020015b6113e66132e9565b8152602001906001900390816113de579050509750838860008151811061140957fe5b6020026020010181905250828860018151811061142257fe5b602090810291909101015260408051600280825260608201909252908160200160208202803883390190505096508360a001518760008151811061146257fe5b6020026020010181815250508260a001518760018151811061148057fe5b60209081029190910101526040805160028082526060820190925290816020015b60608152602001906001900390816114a157905050955081866000815181106114c657fe5b602002602001018190525080866001815181106114df57fe5b6020026020010181905250505050505b509193509193565b60008061150a838263ffffffff612d0f16565b90507fffffffff0000000000000000000000000000000000000000000000000000000081167ff47261b000000000000000000000000000000000000000000000000000000000141561168857600061156984601063ffffffff612d7a16565b905060606370a0823160e01b8660405160240161158691906140d0565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050600060608373ffffffffffffffffffffffffffffffffffffffff168360405161160e91906140b4565b600060405180830381855afa9150503d8060008114611649576040519150601f19603f3d011682016040523d82523d6000602084013e61164e565b606091505b5091509150818015611661575080516020145b61166c57600061167d565b61167d81600063ffffffff612dd916565b955050505050611b80565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f02571792000000000000000000000000000000000000000000000000000000001415611735576000806116de8561041d565b92509250508573ffffffffffffffffffffffffffffffffffffffff16611704838361235c565b73ffffffffffffffffffffffffffffffffffffffff1614611726576000611729565b60015b60ff1693505050611b80565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fa7cb5fb700000000000000000000000000000000000000000000000000000000141561191f57600060608061178d86612081565b5081519296509094509250905060005b81811461191557606062fdd58e60e01b8a8684815181106117ba57fe5b60200260200101516040516024016117d3929190614177565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050600060608773ffffffffffffffffffffffffffffffffffffffff168360405161185b91906140b4565b600060405180830381855afa9150503d8060008114611896576040519150601f19603f3d011682016040523d82523d6000602084013e61189b565b606091505b509150915060008280156118b0575081516020145b6118bb5760006118cc565b6118cc82600063ffffffff612dd916565b905060008786815181106118dc57fe5b602002602001015182816118ec57fe5b0490508b8110806118fb57508b155b1561190457809b505b50506001909301925061179d915050565b5050505050611b80565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fc339d10a000000000000000000000000000000000000000000000000000000001415611ab157606063a85e59e460e01b84600080600060405160240161198c9493929190614481565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252600454915190925060009173ffffffffffffffffffffffffffffffffffffffff1690611a369084906140b4565b600060405180830381855afa9150503d8060008114611a71576040519150601f19603f3d011682016040523d82523d6000602084013e611a76565b606091505b5050905080611a86576000611aa8565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b93505050611b80565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f94cfcdd7000000000000000000000000000000000000000000000000000000001415611b8057606080611b078561247a565b80519194509250905060005b818114611b7b576000611b3989858481518110611b2c57fe5b60200260200101516114f7565b90506000858381518110611b4957fe5b60200260200101518281611b5957fe5b04905087811080611b68575087155b15611b71578097505b5050600101611b13565b505050505b5092915050565b606080606060008551905080604051908082528060200260200182016040528015611bcc57816020015b611bb96133a2565b815260200190600190039081611bb15790505b50935080604051908082528060200260200182016040528015611bf9578160200160208202803883390190505b50925080604051908082528060200260200182016040528015611c26578160200160208202803883390190505b50915060005b818114611cb657611c63878281518110611c4257fe5b6020026020010151878381518110611c5657fe5b6020026020010151611d8b565b8751889085908110611c7157fe5b60200260200101878581518110611c8457fe5b60200260200101878681518110611c9757fe5b9315156020948502919091019093019290925291905252600101611c2c565b50509250925092565b7ff47261b00000000000000000000000000000000000000000000000000000000081565b600080611cf6838263ffffffff612d0f16565b91507fffffffff0000000000000000000000000000000000000000000000000000000082167ff47261b00000000000000000000000000000000000000000000000000000000014611d73576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104ae9061481b565b611d8483601063ffffffff612d7a16565b9050915091565b611d936133a2565b600080546040517fc75e0a81000000000000000000000000000000000000000000000000000000008152829173ffffffffffffffffffffffffffffffffffffffff169063c75e0a8190611dea908890600401614876565b60606040518083038186803b158015611e0257600080fd5b505afa158015611e16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611e3a9190810190613d00565b855160005460208301516040517f93634702000000000000000000000000000000000000000000000000000000008152939650919273ffffffffffffffffffffffffffffffffffffffff90911691639363470291611e9f919085908a9060040161429f565b60206040518083038186803b158015611eb757600080fd5b505afa158015611ecb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611eef9190810190613ca9565b91506000611f0282886101400151610529565b60a088015160c08901516005805460408051602060026001851615610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190941693909304601f8101849004840282018401909252818152959650939492936060939291830182828015611fba5780601f10611f8f57610100808354040283529160200191611fba565b820191906000526020600020905b815481529060010190602001808311611f9d57829003601f168201915b505050505090506000611fdb828c610140015161307190919063ffffffff16565b15611fff57611ff885611ff28d6080015186613096565b866130d5565b905061205b565b600061200b8784610529565b90508361202857612021868d60800151876130d5565b9150612059565b6000612039878e60800151886130d5565b905060006120488387896130d5565b90506120548282612dec565b935050505b505b61207261206c858b6040015161312b565b82612dec565b97505050505050509250925092565b60008060608080612098868563ffffffff612d0f16565b94507fffffffff0000000000000000000000000000000000000000000000000000000085167fa7cb5fb70000000000000000000000000000000000000000000000000000000014612115576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104ae9061481b565b505050506024828101516044840151606485015160848601519496929591820184019490820184019391010190565b6060808251604051908082528060200260200182016040528015612172578160200160208202803883390190505b50905060005b83518114611b805783818151811061218c57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16318282815181106121b757fe5b6020908102919091010152600101612178565b7f025717920000000000000000000000000000000000000000000000000000000081565b6060630257179260e01b838360405160240161220b929190614177565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152905092915050565b7f94cfcdd70000000000000000000000000000000000000000000000000000000081565b606063a7cb5fb760e01b858585856040516024016122d59493929190614118565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529050949350505050565b60006060636352211e60e01b836040516024016123799190614889565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050600060608573ffffffffffffffffffffffffffffffffffffffff168360405161240191906140b4565b600060405180830381855afa9150503d806000811461243c576040519150601f19603f3d011682016040523d82523d6000602084013e612441565b606091505b5091509150818015612454575080516020145b61245f576000612470565b61247081600c63ffffffff612d7a16565b9695505050505050565b600060608061248f848463ffffffff612d0f16565b92507fffffffff0000000000000000000000000000000000000000000000000000000083167f94cfcdd7000000000000000000000000000000000000000000000000000000001461250c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104ae9061481b565b835161252290859060049063ffffffff612e0216565b8060200190516125359190810190613c4f565b9395909450915050565b606060008251905080604051908082528060200260200182016040528015612571578160200160208202803883390190505b50915060005b8181146105cc5761258e85858381518110611b2c57fe5b83828151811061259a57fe5b6020908102919091010152600101612577565b6000806125c0838263ffffffff612d0f16565b90507fffffffff0000000000000000000000000000000000000000000000000000000081167f94cfcdd700000000000000000000000000000000000000000000000000000000141561268a576060806126188561247a565b80519194509250905060005b81811461267f57600061263d898584815181106105a057fe5b9050600085838151811061264d57fe5b6020026020010151828161265d57fe5b0490508781108061266c575087155b15612675578097505b5050600101612624565b5061054b9350505050565b7fffffffff0000000000000000000000000000000000000000000000000000000081167ff47261b000000000000000000000000000000000000000000000000000000000141561273a5760006126e784601063ffffffff612d7a16565b6001546040519192506060917fdd62ed3e000000000000000000000000000000000000000000000000000000009161158691899173ffffffffffffffffffffffffffffffffffffffff16906024016140f1565b7fffffffff0000000000000000000000000000000000000000000000000000000081167f02571792000000000000000000000000000000000000000000000000000000001415612a68576000806127908561041d565b600254604051929550909350606092507fe985e9c500000000000000000000000000000000000000000000000000000000916127e9918a9173ffffffffffffffffffffffffffffffffffffffff909116906024016140f1565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050600060608473ffffffffffffffffffffffffffffffffffffffff168360405161287191906140b4565b600060405180830381855afa9150503d80600081146128ac576040519150601f19603f3d011682016040523d82523d6000602084013e6128b1565b606091505b50915091508115806128c557508051602014155b806128e157506128dc81600063ffffffff612dd916565b600114155b15612a3b57606063081812fc60e01b856040516024016129019190614889565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090508573ffffffffffffffffffffffffffffffffffffffff168160405161298591906140b4565b600060405180830381855afa9150503d80600081146129c0576040519150601f19603f3d011682016040523d82523d6000602084013e6129c5565b606091505b5090935091508280156129d9575081516020145b8015612a22575060025473ffffffffffffffffffffffffffffffffffffffff16612a0a83600c63ffffffff612d7a16565b73ffffffffffffffffffffffffffffffffffffffff16145b612a2d576000612a30565b60015b60ff16975050611915565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff96505050505050611b80565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fa7cb5fb7000000000000000000000000000000000000000000000000000000001415612c42576000612abd84612081565b5050600354604051929450606093507fe985e9c50000000000000000000000000000000000000000000000000000000092612b149250899173ffffffffffffffffffffffffffffffffffffffff16906024016140f1565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050509050600060608373ffffffffffffffffffffffffffffffffffffffff1683604051612b9c91906140b4565b600060405180830381855afa9150503d8060008114612bd7576040519150601f19603f3d011682016040523d82523d6000602084013e612bdc565b606091505b5091509150818015612bef575080516020145b8015612c0b5750612c0781600063ffffffff612dd916565b6001145b612c1657600061167d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff955050505050611b80565b7fffffffff0000000000000000000000000000000000000000000000000000000081167fc339d10a000000000000000000000000000000000000000000000000000000001415611b8057507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9392505050565b60606394cfcdd760e01b838360405160240161220b92919061424c565b7fc339d10a0000000000000000000000000000000000000000000000000000000081565b606080612d03848461253f565b91506104fc8484610551565b60008160040183511015612d4f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104ae906147be565b5001602001517fffffffff000000000000000000000000000000000000000000000000000000001690565b60008160140183511015612dba576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104ae90614761565b50016014015173ffffffffffffffffffffffffffffffffffffffff1690565b6000612de5838361316d565b9392505050565b6000818310612dfb5781612de5565b5090919050565b606081831115612e3e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104ae90614583565b8351821115612e79576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104ae906145ba565b8282036040519080825280601f01601f191660200182016040528015612ea6576020820181803883390190505b509050612de5612eb5826131b6565b84612ebf876131b6565b0183516131bc565b6060806060612ee36004855186612e029092919063ffffffff16565b806020019051612ef69190810190613b2b565b9196909550909350915050565b60408051600180825281830190925260609182918291816020015b612f266132e9565b815260200190600190039081612f1e5750506040805160018082528183019092529194506020808301908038833901905050604080516001808252818301909252919350816020015b6060815260200190600190039081612f6f5750508451909150612f9c90859060049063ffffffff612e0216565b806020019051612faf9190810190613e82565b85600081518110612fbc57fe5b6020026020010185600081518110612fd057fe5b6020026020010185600081518110612fe457fe5b6020908102919091010192909252919052529193909250565b6040805160018082528183019092526060918291829160208083019080388339505085519193506130399186915060049063ffffffff612e0216565b80602001905161304c9190810190613baf565b8451859060009061305957fe5b60209081029190910101919091529095929450925050565b600081518351148015612de55750508051602091820120825192909101919091201490565b600082820183811015612de5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104ae906146bc565b6000808311613110576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104ae90614685565b61312361311d8584613280565b846132d4565b949350505050565b600082821115613167576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104ae906145f1565b50900390565b600081602001835110156131ad576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104ae90614628565b50016020015190565b60200190565b60208110156131e6576001816020036101000a03801983511681855116808217865250505061327b565b828214156131f35761327b565b8282111561322d5760208103905080820181840181515b8285101561322557845186526020958601959094019361320a565b90525061327b565b60208103905080820181840183515b8186121561327657825182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0928301929091019061323c565b855250505b505050565b60008261328f5750600061054b565b8282028284828161329c57fe5b0414612de5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104ae906146bc565b6000808284816132e057fe5b04949350505050565b604051806101800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160608152602001606081525090565b604080516060810182526000808252602082018190529181019190915290565b803561054b8161495b565b805161054b8161495b565b600082601f8301126133e8578081fd5b81516133fb6133f6826148c7565b6148a0565b8181529150602080830190840160005b83811015613438576134238760208451890101613602565b8352602092830192919091019060010161340b565b5050505092915050565b600082601f830112613452578081fd5b81356134606133f6826148c7565b8181529150602080830190840160005b838110156134385761348887602084358901016135b4565b83526020928301929190910190600101613470565b600082601f8301126134ad578081fd5b81516134bb6133f6826148c7565b8181529150602080830190840160005b83811015613438576134e38760208451890101613748565b835260209283019291909101906001016134cb565b600082601f830112613508578081fd5b81516135166133f6826148c7565b81815291506020808301908481018184028601820187101561353757600080fd5b60005b84811015611b7b5781518452928201929082019060010161353a565b600082601f830112613566578081fd5b81356135746133f6826148c7565b81815291506020808301908481018184028601820187101561359557600080fd5b60005b84811015611b7b57813584529282019290820190600101613598565b600082601f8301126135c4578081fd5b81356135d26133f6826148e8565b91508082528360208285010111156135e957600080fd5b8060208401602084013760009082016020015292915050565b600082601f83011261361357600080fd5b81516136216133f6826148e8565b915080825283602082850101111561363857600080fd5b611b8081602084016020860161492b565b600061018080838503121561365c578182fd5b613665816148a0565b91505061367283836133c2565b815261368183602084016133c2565b602082015261369383604084016133c2565b60408201526136a583606084016133c2565b60608201526080820135608082015260a082013560a082015260c082013560c082015260e082013560e08201526101008083013581830152506101208083013581830152506101408083013567ffffffffffffffff8082111561370757600080fd5b613713868387016135b4565b8385015261016092508285013591508082111561372f57600080fd5b5061373c858286016135b4565b82840152505092915050565b600061018080838503121561375b578182fd5b613764816148a0565b91505061377183836133cd565b815261378083602084016133cd565b602082015261379283604084016133cd565b60408201526137a483606084016133cd565b60608201526080820151608082015260a082015160a082015260c082015160c082015260e082015160e08201526101008083015181830152506101208083015181830152506101408083015167ffffffffffffffff8082111561380657600080fd5b61381286838701613602565b8385015261016092508285015191508082111561382e57600080fd5b5061373c85828601613602565b60006020828403121561384d57600080fd5b8135612de58161495b565b6000806040838503121561386b57600080fd5b82356138768161495b565b9150602083013567ffffffffffffffff81111561389257600080fd5b61389e85828601613442565b9150509250929050565b600080600080608085870312156138bd578182fd5b84356138c88161495b565b9350602085013567ffffffffffffffff808211156138e4578384fd5b6138f088838901613556565b94506040870135915080821115613905578384fd5b61391188838901613556565b9350606087013591508082111561392757600080fd5b50613934878288016135b4565b91505092959194509250565b6000806040838503121561395357600080fd5b823561395e8161495b565b9150602083013567ffffffffffffffff81111561397a57600080fd5b61389e858286016135b4565b6000806040838503121561399957600080fd5b82356139a48161495b565b946020939093013593505050565b600060208083850312156139c4578182fd5b823567ffffffffffffffff8111156139da578283fd5b80840185601f8201126139eb578384fd5b803591506139fb6133f6836148c7565b8281528381019082850185850284018601891015613a17578687fd5b8693505b84841015613a42578035613a2e8161495b565b835260019390930192918501918501613a1b565b50979650505050505050565b600060208284031215613a6057600080fd5b815167ffffffffffffffff811115613a7757600080fd5b6131238482850161349d565b60008060408385031215613a95578182fd5b823567ffffffffffffffff80821115613aac578384fd5b81850186601f820112613abd578485fd5b80359250613acd6133f6846148c7565b83815260208082019190838101885b87811015613b0557613af38c848435890101613649565b85529382019390820190600101613adc565b50919750880135945050505080821115613b1e57600080fd5b5061389e85828601613442565b600080600060608486031215613b3f578081fd5b835167ffffffffffffffff80821115613b56578283fd5b613b628783880161349d565b94506020860151915080821115613b77578283fd5b613b83878388016134f8565b93506040860151915080821115613b98578283fd5b50613ba5868287016133d8565b9150509250925092565b600080600060608486031215613bc3578081fd5b835167ffffffffffffffff80821115613bda578283fd5b613be68783880161349d565b9450602086015193506040860151915080821115613b98578283fd5b60008060408385031215613c1557600080fd5b823567ffffffffffffffff80821115613c2d57600080fd5b613c3986838701613556565b93506020850135915080821115613b1e57600080fd5b60008060408385031215613c6257600080fd5b825167ffffffffffffffff80821115613c7a57600080fd5b613c86868387016134f8565b93506020850151915080821115613c9c57600080fd5b5061389e858286016133d8565b600060208284031215613cbb57600080fd5b81518015158114612de557600080fd5b600060208284031215613cdd57600080fd5b813567ffffffffffffffff811115613cf457600080fd5b613123848285016135b4565b60006060828403128015613d12578182fd5b8015613d1c578182fd5b50613d2760606148a0565b825160ff81168114613d37578283fd5b8152602083810151908201526040928301519281019290925250919050565b600060208284031215613d6857600080fd5b815167ffffffffffffffff811115613d7f57600080fd5b61312384828501613748565b60008060408385031215613d9e57600080fd5b823567ffffffffffffffff80821115613db657600080fd5b613dc286838701613649565b93506020850135915080821115613dd857600080fd5b5061389e858286016135b4565b60008060008060808587031215613dfa578182fd5b845167ffffffffffffffff80821115613e11578384fd5b613e1d88838901613748565b95506020870151915080821115613e32578384fd5b613e3e88838901613748565b94506040870151915080821115613e53578384fd5b613e5f88838901613602565b93506060870151915080821115613e7557600080fd5b5061393487828801613602565b600080600060608486031215613e96578081fd5b835167ffffffffffffffff80821115613ead578283fd5b613eb987838801613748565b9450602086015193506040860151915080821115613ed5578283fd5b50613ba586828701613602565b73ffffffffffffffffffffffffffffffffffffffff169052565b60008151808452602084018081955060208302810191506020850160005b84811015613f48578284038852613f32848351613f90565b6020988901989094509190910190600101613f1a565b50919695505050505050565b600081518084526020840193506020830160005b82811015613f86578151865260209586019590910190600101613f68565b5093949350505050565b60008151808452613fa881602086016020860161492b565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b805160ff16825260208082015190830152604090810151910152565b6000610180614006848451613ee2565b60208301516140186020860182613ee2565b50604083015161402b6040860182613ee2565b50606083015161403e6060860182613ee2565b506080830151608085015260a083015160a085015260c083015160c085015260e083015160e085015261010080840151818601525061012080840151818601525061014080840151828287015261409783870182613f90565b915050610160915081840151858203838701526124708282613f90565b600082516140c681846020870161492b565b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b73ffffffffffffffffffffffffffffffffffffffff92831681529116602082015260400190565b600073ffffffffffffffffffffffffffffffffffffffff86168252608060208301526141476080830186613f54565b82810360408401526141598186613f54565b838103606085015261416b8186613f90565b98975050505050505050565b73ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b606080825284519082018190526000906020906080840190828801845b828110156141e0576141cd848351613fda565b60609390930192908401906001016141ba565b505050838103828501526141f48187613f54565b8481036040860152855180825290830191508286019060005b8181101561422b57825115158452928401929184019160010161420d565b509198975050505050505050565b600060208252612de56020830184613f54565b60006040825261425f6040830185613f54565b82810360208401526142718185613efc565b95945050505050565b60006040825261428d6040830185613f54565b82810360208401526142718185613f54565b600084825273ffffffffffffffffffffffffffffffffffffffff84166020830152606060408301526142716060830184613f90565b7fffffffff0000000000000000000000000000000000000000000000000000000091909116815260200190565b7fffffffff0000000000000000000000000000000000000000000000000000000092909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60007fffffffff000000000000000000000000000000000000000000000000000000008716825273ffffffffffffffffffffffffffffffffffffffff8616602083015260a060408301526143a060a0830186613f54565b82810360608401526143b28186613f54565b83810360808501526143c48186613f90565b9998505050505050505050565b7fffffffff0000000000000000000000000000000000000000000000000000000093909316835273ffffffffffffffffffffffffffffffffffffffff919091166020830152604082015260600190565b60007fffffffff00000000000000000000000000000000000000000000000000000000851682526060602083015261445c6060830185613f54565b82810360408401526124708185613efc565b600060208252612de56020830184613f90565b6000608082526144946080830187613f90565b73ffffffffffffffffffffffffffffffffffffffff958616602084015293909416604082015260ff9190911660609091015292915050565b6000608082526144df6080830187613f90565b602083820381850152818751808452828401915082838202850101838a0160005b8381101561454c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe087840301855261453a838351613ff6565b94860194925090850190600101614500565b50508681036040880152614560818a613f54565b94505050505082810360608401526145788185613efc565b979650505050505050565b6020808252601a908201527f46524f4d5f4c4553535f5448414e5f544f5f5245515549524544000000000000604082015260600190565b6020808252601c908201527f544f5f4c4553535f5448414e5f4c454e4754485f524551554952454400000000604082015260600190565b60208082526011908201527f55494e543235365f554e444552464c4f57000000000000000000000000000000604082015260600190565b60208082526026908201527f475245415445525f4f525f455155414c5f544f5f33325f4c454e4754485f524560408201527f5155495245440000000000000000000000000000000000000000000000000000606082015260800190565b60208082526010908201527f4449564953494f4e5f42595f5a45524f00000000000000000000000000000000604082015260600190565b60208082526010908201527f55494e543235365f4f564552464c4f5700000000000000000000000000000000604082015260600190565b60208082526019908201527f554e4b4e4f574e5f46554e4354494f4e5f53454c4543544f5200000000000000604082015260600190565b6020808252600d908201527f554e494d504c454d454e54454400000000000000000000000000000000000000604082015260600190565b60208082526026908201527f475245415445525f4f525f455155414c5f544f5f32305f4c454e4754485f524560408201527f5155495245440000000000000000000000000000000000000000000000000000606082015260800190565b60208082526025908201527f475245415445525f4f525f455155414c5f544f5f345f4c454e4754485f52455160408201527f5549524544000000000000000000000000000000000000000000000000000000606082015260800190565b6020808252600e908201527f57524f4e475f50524f58595f4944000000000000000000000000000000000000604082015260600190565b60a081016148608286613fda565b8360608301528215156080830152949350505050565b600060208252612de56020830184613ff6565b90815260200190565b918252602082015260400190565b60405181810167ffffffffffffffff811182821017156148bf57600080fd5b604052919050565b600067ffffffffffffffff8211156148de57600080fd5b5060209081020190565b600067ffffffffffffffff8211156148ff57600080fd5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b8381101561494657818101518382015260200161492e565b83811115614955576000848401525b50505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461497d57600080fd5b5056fea365627a7a72305820b0089191876aedb7c9ca73a599fe9f1af81f739a05048f17544cc85e5cb803f86c6578706572696d656e74616cf564736f6c634300050a0040" + } + } + }, + "networks": {} +} diff --git a/packages/contract-artifacts/artifacts/ERC1155Proxy.json b/packages/contract-artifacts/artifacts/ERC1155Proxy.json new file mode 100644 index 0000000000..daab773e67 --- /dev/null +++ b/packages/contract-artifacts/artifacts/ERC1155Proxy.json @@ -0,0 +1,254 @@ +{ + "schemaVersion": "2.0.0", + "contractName": "ERC1155Proxy", + "compilerOutput": { + "abi": [ + { + "constant": false, + "inputs": [ + { + "name": "target", + "type": "address" + } + ], + "name": "addAuthorizedAddress", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "uint256" + } + ], + "name": "authorities", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "target", + "type": "address" + } + ], + "name": "removeAuthorizedAddress", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "target", + "type": "address" + }, + { + "name": "index", + "type": "uint256" + } + ], + "name": "removeAuthorizedAddressAtIndex", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "assetData", + "type": "bytes" + }, + { + "name": "from", + "type": "address" + }, + { + "name": "to", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getProxyId", + "outputs": [ + { + "name": "", + "type": "bytes4" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "name": "", + "type": "address" + } + ], + "name": "authorized", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getAuthorizedAddresses", + "outputs": [ + { + "name": "", + "type": "address[]" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "target", + "type": "address" + }, + { + "indexed": true, + "name": "caller", + "type": "address" + } + ], + "name": "AuthorizedAddressAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "name": "target", + "type": "address" + }, + { + "indexed": true, + "name": "caller", + "type": "address" + } + ], + "name": "AuthorizedAddressRemoved", + "type": "event" + } + ], + "devdoc": { + "methods": { + "addAuthorizedAddress(address)": { + "details": "Authorizes an address.", + "params": { + "target": "Address to authorize." + } + }, + "getAuthorizedAddresses()": { + "details": "Gets all authorized addresses.", + "return": "Array of authorized addresses." + }, + "getProxyId()": { + "details": "Gets the proxy id associated with the proxy address.", + "return": "Proxy id." + }, + "removeAuthorizedAddress(address)": { + "details": "Removes authorizion of an address.", + "params": { + "target": "Address to remove authorization from." + } + }, + "removeAuthorizedAddressAtIndex(address,uint256)": { + "details": "Removes authorizion of an address.", + "params": { + "index": "Index of target in authorities array.", + "target": "Address to remove authorization from." + } + }, + "transferFrom(bytes,address,address,uint256)": { + "details": "Transfers batch of ERC1155 assets. Either succeeds or throws.", + "params": { + "amount": "Amount that will be multiplied with each element of `assetData.values` to scale the values that will be transferred.", + "assetData": "Byte array encoded with ERC1155 token address, array of ids, array of values, and callback data.", + "from": "Address to transfer assets from.", + "to": "Address to transfer assets to." + } + } + } + }, + "evm": { + "bytecode": { + "object": "0x6080604052600080546001600160a01b03191633179055611415806100256000396000f3fe608060405234801561001057600080fd5b50600436106100be5760003560e01c8063a85e59e411610076578063b91816111161005b578063b918161114610285578063d39de6e9146102cc578063f2fde38b14610324576100be565b8063a85e59e4146101b2578063ae25532e14610248576100be565b806370712939116100a7578063707129391461013e5780638da5cb5b146101715780639ad2674414610179576100be565b806342f1181e146100c3578063494503d4146100f8575b600080fd5b6100f6600480360360208110156100d957600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610357565b005b6101156004803603602081101561010e57600080fd5b5035610543565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6100f66004803603602081101561015457600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610577565b61011561086a565b6100f66004803603604081101561018f57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610886565b6100f6600480360360808110156101c857600080fd5b8101906020810181356401000000008111156101e357600080fd5b8201836020820111156101f557600080fd5b8035906020019184600183028401116401000000008311171561021757600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610c37565b61025061105f565b604080517fffffffff000000000000000000000000000000000000000000000000000000009092168252519081900360200190f35b6102b86004803603602081101561029b57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611080565b604080519115158252519081900360200190f35b6102d4611095565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156103105781810151838201526020016102f8565b505050509050019250505060405180910390f35b6100f66004803603602081101561033a57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611104565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103dd57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4f4e4c595f434f4e54524143545f4f574e455200000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff811660009081526001602052604090205460ff161561047257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f5441524745545f414c52454144595f415554484f52495a454400000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8116600081815260016020819052604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168317905560028054928301815583527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace90910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001684179055513392917f3147867c59d17e8fa9d522465651d44aae0a9e38f902f3475b97e58072f0ed4c91a350565b6002818154811061055057fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b60005473ffffffffffffffffffffffffffffffffffffffff1633146105fd57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4f4e4c595f434f4e54524143545f4f574e455200000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff811660009081526001602052604090205460ff1661069157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f5441524745545f4e4f545f415554484f52495a45440000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8116600090815260016020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b600254811015610823578173ffffffffffffffffffffffffffffffffffffffff166002828154811061070b57fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16141561081b57600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810190811061076357fe5b6000918252602090912001546002805473ffffffffffffffffffffffffffffffffffffffff909216918390811061079657fe5b600091825260209091200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01906108159082611369565b50610823565b6001016106dd565b50604051339073ffffffffffffffffffffffffffffffffffffffff8316907f1f32c1b084e2de0713b8fb16bd46bb9df710a3dbeae2f3ca93af46e016dcc6b090600090a350565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b60005473ffffffffffffffffffffffffffffffffffffffff16331461090c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4f4e4c595f434f4e54524143545f4f574e455200000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081526001602052604090205460ff166109a057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f5441524745545f4e4f545f415554484f52495a45440000000000000000000000604482015290519081900360640190fd5b6002548110610a1057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f494e4445585f4f55545f4f465f424f554e445300000000000000000000000000604482015290519081900360640190fd5b8173ffffffffffffffffffffffffffffffffffffffff1660028281548110610a3457fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1614610ac257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f415554484f52495a45445f414444524553535f4d49534d415443480000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8216600090815260016020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908110610b3d57fe5b6000918252602090912001546002805473ffffffffffffffffffffffffffffffffffffffff9092169183908110610b7057fe5b600091825260209091200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190610bef9082611369565b50604051339073ffffffffffffffffffffffffffffffffffffffff8416907f1f32c1b084e2de0713b8fb16bd46bb9df710a3dbeae2f3ca93af46e016dcc6b090600090a35050565b3360009081526001602052604090205460ff16610cb557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f53454e4445525f4e4f545f415554484f52495a45440000000000000000000000604482015290519081900360640190fd5b60006060806060610d0b60048a8a90508b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092949392505063ffffffff6111ea169050565b8060200190516080811015610d1f57600080fd5b815160208301805191939283019291640100000000811115610d4057600080fd5b82016020810184811115610d5357600080fd5b8151856020820283011164010000000082111715610d7057600080fd5b50509291906020018051640100000000811115610d8c57600080fd5b82016020810184811115610d9f57600080fd5b8151856020820283011164010000000082111715610dbc57600080fd5b50509291906020018051640100000000811115610dd857600080fd5b82016020810184811115610deb57600080fd5b8151640100000000811182820187101715610e0557600080fd5b50509291905050509350935093509350600082519050606081604051908082528060200260200182016040528015610e47578160200160208202803883390190505b50905060005b828114610e9057610e71858281518110610e6357fe5b6020026020010151896112d7565b828281518110610e7d57fe5b6020908102919091010152600101610e4d565b508573ffffffffffffffffffffffffffffffffffffffff16632eb2c2d68a8a8885886040518663ffffffff1660e01b8152600401808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001806020018060200180602001848103845287818151815260200191508051906020019060200280838360005b83811015610f6d578181015183820152602001610f55565b50505050905001848103835286818151815260200191508051906020019060200280838360005b83811015610fac578181015183820152602001610f94565b50505050905001848103825285818151815260200191508051906020019080838360005b83811015610fe8578181015183820152602001610fd0565b50505050905090810190601f1680156110155780820380516001836020036101000a031916815260200191505b5098505050505050505050600060405180830381600087803b15801561103a57600080fd5b505af115801561104e573d6000803e3d6000fd5b505050505050505050505050505050565b600060405180806113b1603091396030019050604051809103902090505b90565b60016020526000908152604090205460ff1681565b606060028054806020026020016040519081016040528092919081815260200182805480156110fa57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116110cf575b5050505050905090565b60005473ffffffffffffffffffffffffffffffffffffffff16331461118a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4f4e4c595f434f4e54524143545f4f574e455200000000000000000000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff8116156111e757600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83161790555b50565b60608183111561125b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f46524f4d5f4c4553535f5448414e5f544f5f5245515549524544000000000000604482015290519081900360640190fd5b83518211156112cb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f544f5f4c4553535f5448414e5f4c454e4754485f524551554952454400000000604482015290519081900360640190fd5b50819003910190815290565b6000826112e657506000611363565b828202828482816112f357fe5b041461136057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f55494e543235365f4f564552464c4f5700000000000000000000000000000000604482015290519081900360640190fd5b90505b92915050565b81548183558181111561138d5760008381526020902061138d918101908301611392565b505050565b61107d91905b808211156113ac5760008155600101611398565b509056fe4552433131353541737365747328616464726573732c75696e743235365b5d2c75696e743235365b5d2c627974657329a265627a7a72305820830991568a081d2cfe3ad4a799bd1c9607c221a03df4b84012916e981b3503e564736f6c634300050a0032" + } + } + }, + "networks": {} +} diff --git a/packages/contract-artifacts/artifacts/StaticCallProxy.json b/packages/contract-artifacts/artifacts/StaticCallProxy.json new file mode 100644 index 0000000000..60c01bc043 --- /dev/null +++ b/packages/contract-artifacts/artifacts/StaticCallProxy.json @@ -0,0 +1,71 @@ +{ + "schemaVersion": "2.0.0", + "contractName": "StaticCallProxy", + "compilerOutput": { + "abi": [ + { + "constant": true, + "inputs": [ + { + "name": "assetData", + "type": "bytes" + }, + { + "name": "from", + "type": "address" + }, + { + "name": "to", + "type": "address" + }, + { + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getProxyId", + "outputs": [ + { + "name": "", + "type": "bytes4" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + } + ], + "devdoc": { + "methods": { + "getProxyId()": { + "details": "Gets the proxy id associated with the proxy address.", + "return": "Proxy id." + }, + "transferFrom(bytes,address,address,uint256)": { + "details": "Makes a staticcall to a target address and verifies that the data returned matches the expected return data.", + "params": { + "amount": "This value is ignored.", + "assetData": "Byte array encoded with staticCallTarget, staticCallData, and expectedCallResultHash", + "from": "This value is ignored.", + "to": "This value is ignored." + } + } + } + }, + "evm": { + "bytecode": { + "object": "0x608060405234801561001057600080fd5b506104a1806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063a85e59e41461003b578063ae25532e146100d3575b600080fd5b6100d16004803603608081101561005157600080fd5b81019060208101813564010000000081111561006c57600080fd5b82018360208201111561007e57600080fd5b803590602001918460018302840111640100000000831117156100a057600080fd5b919350915073ffffffffffffffffffffffffffffffffffffffff813581169160208101359091169060400135610110565b005b6100db61033e565b604080517fffffffff000000000000000000000000000000000000000000000000000000009092168252519081900360200190f35b6000606060006101656004898990508a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092949392505063ffffffff61035e169050565b806020019051606081101561017957600080fd5b81516020830180519193928301929164010000000081111561019a57600080fd5b820160208101848111156101ad57600080fd5b81516401000000008111828201871017156101c757600080fd5b5050602091820151604051825196995091975095506000946060945073ffffffffffffffffffffffffffffffffffffffff8916935087928291908401908083835b6020831061024557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610208565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146102a5576040519150601f19603f3d011682016040523d82523d6000602084013e6102aa565b606091505b5091509150816102bc57805160208201fd5b8051602082012083811461033157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f554e45585045435445445f5354415449435f43414c4c5f524553554c54000000604482015290519081900360640190fd5b5050505050505050505050565b6000604051808061044c6021913960210190506040518091039020905090565b6060818311156103cf57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f46524f4d5f4c4553535f5448414e5f544f5f5245515549524544000000000000604482015290519081900360640190fd5b835182111561043f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f544f5f4c4553535f5448414e5f4c454e4754485f524551554952454400000000604482015290519081900360640190fd5b5081900391019081529056fe53746174696343616c6c28616464726573732c62797465732c6279746573333229a265627a7a723058202a9eb09d75997d78128bcdbbcc5078907fc01fd97b218cd94a4e7600375d488664736f6c634300050a0032" + } + } + }, + "networks": {} +} diff --git a/packages/contract-artifacts/package.json b/packages/contract-artifacts/package.json index d6d286aa8c..c621e63f5a 100644 --- a/packages/contract-artifacts/package.json +++ b/packages/contract-artifacts/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contract-artifacts", - "version": "2.0.1", + "version": "2.0.4", "engines": { "node": ">=6.12" }, @@ -30,10 +30,11 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/contract-artifacts/README.md", "devDependencies": { - "@0x/utils": "^4.4.0", + "@0x/utils": "^4.5.0", + "@types/mocha": "^5.2.7", "chai": "^4.0.1", "lodash": "^4.17.11", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "shx": "^0.2.2", "typescript": "3.0.1" }, diff --git a/packages/contract-artifacts/src/copy.ts b/packages/contract-artifacts/src/copy.ts index 06a4474432..c67b3741f8 100644 --- a/packages/contract-artifacts/src/copy.ts +++ b/packages/contract-artifacts/src/copy.ts @@ -48,13 +48,7 @@ if (allArtifactPaths.length < pkgNames.length) { for (const _path of allArtifactPaths) { const fileName = _path.split('/').slice(-1)[0]; const targetPath = path.join(__dirname, '../../artifacts', fileName); - const targetPathPython = path.join( - MONOREPO_ROOT, - 'python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts', - fileName, - ); fs.copyFileSync(_path, targetPath); - fs.copyFileSync(_path, targetPathPython); logUtils.log(`Copied ${_path}`); } logUtils.log(`Finished copying contract-artifacts. Remember to transform artifacts before publishing or using abi-gen`); diff --git a/packages/contract-artifacts/src/index.ts b/packages/contract-artifacts/src/index.ts index 431bf64f6a..a1a5db3b8d 100644 --- a/packages/contract-artifacts/src/index.ts +++ b/packages/contract-artifacts/src/index.ts @@ -1,9 +1,11 @@ import * as AssetProxyOwner from '../artifacts/AssetProxyOwner.json'; import * as Coordinator from '../artifacts/Coordinator.json'; import * as CoordinatorRegistry from '../artifacts/CoordinatorRegistry.json'; +import * as DevUtils from '../artifacts/DevUtils.json'; import * as DummyERC20Token from '../artifacts/DummyERC20Token.json'; import * as DummyERC721Token from '../artifacts/DummyERC721Token.json'; import * as DutchAuction from '../artifacts/DutchAuction.json'; +import * as ERC1155Proxy from '../artifacts/ERC1155Proxy.json'; import * as ERC20Proxy from '../artifacts/ERC20Proxy.json'; import * as ERC20Token from '../artifacts/ERC20Token.json'; import * as ERC721Proxy from '../artifacts/ERC721Proxy.json'; @@ -16,14 +18,17 @@ import * as IValidator from '../artifacts/IValidator.json'; import * as IWallet from '../artifacts/IWallet.json'; import * as MultiAssetProxy from '../artifacts/MultiAssetProxy.json'; import * as OrderValidator from '../artifacts/OrderValidator.json'; +import * as StaticCallProxy from '../artifacts/StaticCallProxy.json'; import * as WETH9 from '../artifacts/WETH9.json'; import * as ZRXToken from '../artifacts/ZRXToken.json'; export { AssetProxyOwner, DutchAuction, + DevUtils, DummyERC20Token, DummyERC721Token, + ERC1155Proxy, ERC20Proxy, ERC20Token, ERC721Proxy, @@ -35,6 +40,7 @@ export { IWallet, MultiAssetProxy, OrderValidator, + StaticCallProxy, WETH9, ZRXToken, Coordinator, diff --git a/packages/contract-artifacts/tsconfig.json b/packages/contract-artifacts/tsconfig.json index 9360e137ed..7d339682c3 100644 --- a/packages/contract-artifacts/tsconfig.json +++ b/packages/contract-artifacts/tsconfig.json @@ -8,6 +8,7 @@ "include": ["./src/**/*", "./test/**/*"], "files": [ "./artifacts/AssetProxyOwner.json", + "./artifacts/DevUtils.json", "./artifacts/DutchAuction.json", "./artifacts/DummyERC20Token.json", "./artifacts/DummyERC721Token.json", @@ -26,6 +27,8 @@ "./artifacts/ZRXToken.json", "./artifacts/CoordinatorRegistry.json", "./artifacts/Coordinator.json", - "./artifacts/EthBalanceChecker.json" + "./artifacts/EthBalanceChecker.json", + "./artifacts/ERC1155Proxy.json", + "./artifacts/StaticCallProxy.json" ] } diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index fec1fc4b31..597ea7ed1f 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -1,6 +1,6 @@ [ { - "version": "9.2.0", + "version": "11.2.0", "changes": [ { "note": "Use new `Order` and `ZeroExTransaction` structures with `domain` field", @@ -12,6 +12,48 @@ } ] }, + { + "version": "11.1.0", + "changes": [ + { + "note": "Add `contractAddresses` to `ContractWrappers` class. Add `validateAndSendTransactionAsync` to all methods. Add interfaces ForwarderError, ContractError, TraderInfo, OrderAndTraderInfo.", + "pr": 2068 + } + ] + }, + { + "version": "11.0.0", + "changes": [ + { + "note": "Use @0x/abi-gen to generate wrappers. For a full list of changes, see https://github.com/0xProject/0x-monorepo/issues/2040", + "pr": 2037 + } + ], + "timestamp": 1565296576 + }, + { + "version": "10.1.0", + "changes": [ + { + "note": "Updated interface to `deployFrom0xArtifactAsync` to include log decode dependencies.", + "pr": 1995 + }, + { + "note": "Updated interface to `deployAsync` to include log decode dependencies.", + "pr": 1995 + } + ], + "timestamp": 1564604963 + }, + { + "version": "10.0.0", + "changes": [ + { + "note": "Constructors for `ERC20TokenWrapper`, `ERC721TokenWrapper`, and `EtherTokenWrapper` no longer accept networkId", + "pr": 1970 + } + ] + }, { "version": "9.1.8", "changes": [ @@ -19,7 +61,8 @@ "note": "re-export new ethereum-types type, TupleDataItem", "pr": 1919 } - ] + ], + "timestamp": 1563957393 }, { "timestamp": 1563193019, diff --git a/packages/contract-wrappers/CHANGELOG.md b/packages/contract-wrappers/CHANGELOG.md index 9be4e360b6..3d5d4ac8fd 100644 --- a/packages/contract-wrappers/CHANGELOG.md +++ b/packages/contract-wrappers/CHANGELOG.md @@ -5,6 +5,23 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v11.0.0 - _August 8, 2019_ + + * Use @0x/abi-gen to generate wrappers. For a full list of changes, see https://github.com/0xProject/0x-monorepo/issues/2040 (#2037) + +## v10.1.0 - _July 31, 2019_ + + * Updated interface to `deployFrom0xArtifactAsync` to include log decode dependencies. (#1995) + * Updated interface to `deployAsync` to include log decode dependencies. (#1995) + +## v10.0.0 - _Invalid date_ + + * Constructors for `ERC20TokenWrapper`, `ERC721TokenWrapper`, and `EtherTokenWrapper` no longer accept networkId (#1970) + +## v9.1.8 - _July 24, 2019_ + + * re-export new ethereum-types type, TupleDataItem (#1919) + ## v9.1.7 - _July 15, 2019_ * Dependencies updated diff --git a/packages/contract-wrappers/README.md b/packages/contract-wrappers/README.md index 36f2f48fb4..0ab599a249 100644 --- a/packages/contract-wrappers/README.md +++ b/packages/contract-wrappers/README.md @@ -1,8 +1,6 @@ ## @0x/contract-wrappers -Smart TS wrappers for 0x smart contracts. The wrappers have simplified interfaces, perform client-side validation on transactions and throw helpful error messages. - -### Read the [Documentation](https://0xproject.com/docs/0x.js). +Wrappers for 0x smart contracts, generated using @0x/abi-gen. ## Installation @@ -14,7 +12,7 @@ npm install @0x/contract-wrappers --save **Import** -```javascript +```typescript import { ContractWrappers } from '@0x/contract-wrappers'; ``` @@ -28,7 +26,7 @@ If your project is in [TypeScript](https://www.typescriptlang.org/), add the fol ## Contributing -We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. +We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository. Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. @@ -54,22 +52,6 @@ To build this package and all other monorepo packages that it depends on, run th PKG=@0x/contract-wrappers yarn build ``` -Or continuously rebuild on change: - -```bash -PKG=@0x/contract-wrappers yarn watch -``` - -```bash -yarn build -``` - -or continuously rebuild on change: - -```bash -yarn watch -``` - ### Clean ```bash @@ -87,3 +69,9 @@ yarn lint ```bash yarn test ``` + +### Documentation + +Documentation for this package is generated by TypeDoc, using the Solidity source code for 0x contracts. Each contract corresponds to one global-level module, which contains relevant enums and interfaces for its events and structs. Most significantly, each module exports a class, `Contract`, e.g. `ExchangeContract`, which implements helper methods for all the functions defined in the corresponding contract. + +A convention to note is that these contract-specific helper methods are defined as _object literals_, which are separated from methods in the generated documentation. Each contract method has a number of sub-methods, e.g. `sendTransactionAsync`, or `estimateGasAsync`, which are documented separately. This is an example of an expected method call signature: `exchangeContractInstance.fillOrder.sendTransactionAsync(...arguments)`. diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json index 5a5d741f87..7cb94410b2 100644 --- a/packages/contract-wrappers/package.json +++ b/packages/contract-wrappers/package.json @@ -1,7 +1,10 @@ { "name": "@0x/contract-wrappers", - "version": "9.1.7", - "description": "Smart TS wrappers for 0x smart contracts", + "version": "11.0.0", + "engines": { + "node": ">=6.12" + }, + "description": "Wrappers for 0x smart contract wrappers generated using @0x/abi-gen", "keywords": [ "0xproject", "ethereum", @@ -10,86 +13,71 @@ ], "main": "lib/src/index.js", "types": "lib/src/index.d.ts", + "directories": { + "test": "test" + }, "scripts": { - "build": "tsc -b", + "build": "yarn pre_build && tsc -b", "build:ci": "yarn build", "lint": "tslint --format stylish --project . --exclude **/lib/**/*", - "fix": "tslint --fix --format stylish --project . --exclude **/lib/**/*", + "fix": "tslint --fix --format stylish --project .--exclude **/lib/**/*", "test:circleci": "run-s test:coverage", "test": "yarn run_mocha", - "rebuild_and_test": "run-s build test", + "run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js lib/test/global_hooks.js --timeout 10000 --bail --exit", "test:coverage": "nyc npm run test --all && yarn coverage:report:lcov", "coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info", - "clean": "shx rm -rf _bundles lib test_temp generated_docs", - "run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js lib/test/global_hooks.js --timeout 10000 --bail --exit", - "docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" + "pre_build": "yarn generate_contract_wrappers && yarn prettier_contract_wrappers", + "prettier": "prettier --write **/* --config ../../.prettierrc", + "prettier_contract_wrappers": "prettier --write src/generated-wrappers/* --config ../../.prettierrc", + "clean": "shx rm -rf lib src/generated-wrappers", + "generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../node_modules/@0x/abi-gen-templates/contract.handlebars --partials '../../node_modules/@0x/abi-gen-templates/partials/**/*.handlebars' --output src/generated-wrappers --backend ethers", + "docs_test": "typedoc --excludePrivate --excludeExternals --target ES5 --tsconfig typedoc-tsconfig.json --out generated_docs ./src/generated-wrappers/*" }, "config": { - "postpublish": { - "assets": [] - } + "abis": "../contract-artifacts/artifacts/@(AssetProxyOwner|DevUtils|DutchAuction|DummyERC20Token|DummyERC721Token|ERC20Proxy|ERC20Token|ERC721Proxy|ERC721Token|Exchange|Forwarder|IAssetProxy|IValidator|IWallet|MultiAssetProxy|OrderValidator|WETH9|ZRXToken|Coordinator|CoordinatorRegistry|EthBalanceChecker).json" }, "repository": { "type": "git", - "url": "https://github.com/0xProject/0x-monorepo" + "url": "https://github.com/0xProject/0x-monorepo.git" }, "license": "Apache-2.0", - "engines": { - "node": ">=6.0.0" + "bugs": { + "url": "https://github.com/0xProject/0x-monorepo/issues" }, + "homepage": "https://github.com/0xProject/0x-monorepo/packages/contract-wrappers/README.md", "devDependencies": { - "@0x/contracts-test-utils": "^3.1.10", - "@0x/coordinator-server": "0.1.1", - "@0x/dev-utils": "^2.2.4", - "@0x/fill-scenarios": "^3.0.13", - "@0x/migrations": "^4.1.9", - "@0x/subproviders": "^4.1.1", + "@0x/abi-gen": "^4.1.0", + "@0x/abi-gen-templates": "^2.4.1", + "@0x/assert": "^2.1.3", + "@0x/contracts-test-utils": "^3.1.12", + "@0x/coordinator-server": "^0.1.3", + "@0x/json-schemas": "^3.1.13", "@0x/tslint-config": "^3.0.1", - "@types/lodash": "4.14.104", - "@types/mocha": "^2.2.42", - "@types/nock": "^10.0.1", - "@types/node": "*", - "@types/sinon": "^2.2.2", - "@types/uuid": "^3.4.3", - "@types/web3-provider-engine": "^14.0.0", + "@0x/types": "^2.4.1", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", + "@types/nock": "^10.0.3", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^3.0.0", "dirty-chai": "^2.0.1", - "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "ethereum-types": "^2.1.4", + "ethers": "~4.0.4", + "lodash": "^4.17.11", + "mocha": "^6.2.0", "nock": "^10.0.6", - "npm-run-all": "^4.1.2", - "nyc": "^11.0.1", - "opn-cli": "^3.1.0", - "shx": "^0.2.2", - "sinon": "^4.0.0", - "source-map-support": "^0.5.0", - "tslint": "5.11.0", - "typedoc": "0.13.0", - "typescript": "3.0.1", - "web3-provider-engine": "14.0.6" + "shx": "^0.2.2" }, "dependencies": { - "@0x/abi-gen-wrappers": "^5.0.2", - "@0x/assert": "^2.1.0", - "@0x/contract-addresses": "^3.0.2", - "@0x/contract-artifacts": "^2.0.1", - "@0x/json-schemas": "^3.0.11", - "@0x/order-utils": "^8.2.2", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", - "ethereum-types": "^2.1.3", - "ethereumjs-abi": "0.6.5", - "ethereumjs-blockstream": "6.0.0", - "ethereumjs-util": "^5.1.1", - "ethers": "~4.0.4", - "http-status-codes": "^1.3.2", - "js-sha3": "^0.7.0", - "lodash": "^4.17.11", - "uuid": "^3.3.2" + "@0x/base-contract": "^5.3.1", + "@0x/contract-addresses": "^3.0.3", + "@0x/contract-artifacts": "^2.0.4", + "@0x/dev-utils": "^2.3.0", + "@0x/fill-scenarios": "^3.0.16", + "@0x/migrations": "^4.2.0", + "@0x/order-utils": "^8.2.5", + "@0x/subproviders": "^5.0.1", + "http-status-codes": "^1.3.2" }, "publishConfig": { "access": "public" diff --git a/packages/contract-wrappers/src/abstract/abstract_balance_and_proxy_allowance_lazy_store.ts b/packages/contract-wrappers/src/abstract/abstract_balance_and_proxy_allowance_lazy_store.ts deleted file mode 100644 index b095c8e79f..0000000000 --- a/packages/contract-wrappers/src/abstract/abstract_balance_and_proxy_allowance_lazy_store.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { BigNumber } from '@0x/utils'; - -export abstract class AbstractBalanceAndProxyAllowanceLazyStore { - public abstract async getBalanceAsync(tokenAddress: string, userAddress: string): Promise; - public abstract async getProxyAllowanceAsync(tokenAddress: string, userAddress: string): Promise; - public abstract setBalance(tokenAddress: string, userAddress: string, balance: BigNumber): void; - public abstract deleteBalance(tokenAddress: string, userAddress: string): void; - public abstract setProxyAllowance(tokenAddress: string, userAddress: string, proxyAllowance: BigNumber): void; - public abstract deleteProxyAllowance(tokenAddress: string, userAddress: string): void; - public abstract deleteAll(): void; -} diff --git a/packages/contract-wrappers/src/contract_wrappers.ts b/packages/contract-wrappers/src/contract_wrappers.ts index 370a191d43..f216b773eb 100644 --- a/packages/contract-wrappers/src/contract_wrappers.ts +++ b/packages/contract-wrappers/src/contract_wrappers.ts @@ -1,3 +1,4 @@ +import { ContractAddresses } from '@0x/contract-addresses'; import { Coordinator, DutchAuction, @@ -15,20 +16,17 @@ import { Web3Wrapper } from '@0x/web3-wrapper'; import { SupportedProvider } from 'ethereum-types'; import * as _ from 'lodash'; -import { CoordinatorWrapper } from './contract_wrappers/coordinator_wrapper'; -import { DutchAuctionWrapper } from './contract_wrappers/dutch_auction_wrapper'; -import { ERC20ProxyWrapper } from './contract_wrappers/erc20_proxy_wrapper'; -import { ERC20TokenWrapper } from './contract_wrappers/erc20_token_wrapper'; -import { ERC721ProxyWrapper } from './contract_wrappers/erc721_proxy_wrapper'; -import { ERC721TokenWrapper } from './contract_wrappers/erc721_token_wrapper'; -import { EtherTokenWrapper } from './contract_wrappers/ether_token_wrapper'; -import { ExchangeWrapper } from './contract_wrappers/exchange_wrapper'; -import { ForwarderWrapper } from './contract_wrappers/forwarder_wrapper'; -import { OrderValidatorWrapper } from './contract_wrappers/order_validator_wrapper'; +import { CoordinatorWrapper } from './coordinator_wrapper'; +import { DutchAuctionContract } from './generated-wrappers/dutch_auction'; +import { ERC20ProxyContract } from './generated-wrappers/erc20_proxy'; +import { ERC721ProxyContract } from './generated-wrappers/erc721_proxy'; +import { ExchangeContract } from './generated-wrappers/exchange'; +import { ForwarderContract } from './generated-wrappers/forwarder'; +import { OrderValidatorContract } from './generated-wrappers/order_validator'; +import { WETH9Contract } from './generated-wrappers/weth9'; import { ContractWrappersConfigSchema } from './schemas/contract_wrappers_config_schema'; import { ContractWrappersConfig } from './types'; import { assert } from './utils/assert'; -import { constants } from './utils/constants'; import { _getDefaultContractAddresses } from './utils/contract_addresses'; /** @@ -36,45 +34,40 @@ import { _getDefaultContractAddresses } from './utils/contract_addresses'; */ export class ContractWrappers { /** - * An instance of the ExchangeWrapper class containing methods for interacting with the 0x Exchange smart contract. + * An index of the default contract addresses for this network. */ - public exchange: ExchangeWrapper; + public contractAddresses: ContractAddresses; /** - * An instance of the ERC20TokenWrapper class containing methods for interacting with any ERC20 token smart contract. + * An instance of the ExchangeContract class containing methods for interacting with the 0x Exchange smart contract. */ - public erc20Token: ERC20TokenWrapper; + public exchange: ExchangeContract; /** - * An instance of the ERC721TokenWrapper class containing methods for interacting with any ERC721 token smart contract. - */ - public erc721Token: ERC721TokenWrapper; - /** - * An instance of the EtherTokenWrapper class containing methods for interacting with the - * wrapped ETH ERC20 token smart contract. - */ - public etherToken: EtherTokenWrapper; - /** - * An instance of the ERC20ProxyWrapper class containing methods for interacting with the + * An instance of the ERC20ProxyContract class containing methods for interacting with the * erc20Proxy smart contract. */ - public erc20Proxy: ERC20ProxyWrapper; + public erc20Proxy: ERC20ProxyContract; /** - * An instance of the ERC721ProxyWrapper class containing methods for interacting with the + * An instance of the ERC721ProxyContract class containing methods for interacting with the * erc721Proxy smart contract. */ - public erc721Proxy: ERC721ProxyWrapper; + public erc721Proxy: ERC721ProxyContract; /** - * An instance of the ForwarderWrapper class containing methods for interacting with any Forwarder smart contract. + * An instance of the WETH9Contract class containing methods for interacting with the + * WETH9 smart contract. */ - public forwarder: ForwarderWrapper; + public weth9: WETH9Contract; /** - * An instance of the OrderValidatorWrapper class containing methods for interacting with any OrderValidator smart contract. + * An instance of the ForwarderContract class containing methods for interacting with any Forwarder smart contract. */ - public orderValidator: OrderValidatorWrapper; + public forwarder: ForwarderContract; /** - * An instance of the DutchAuctionWrapper class containing methods for interacting with any DutchAuction smart contract. + * An instance of the OrderValidatorContract class containing methods for interacting with any OrderValidator smart contract. */ - public dutchAuction: DutchAuctionWrapper; - + public orderValidator: OrderValidatorContract; + /** + * An instance of the DutchAuctionContract class containing methods for interacting with any DutchAuction smart contract. + */ + public dutchAuction: DutchAuctionContract; /** * An instance of the CoordinatorWrapper class containing methods for interacting with the Coordinator extension contract. */ @@ -109,60 +102,17 @@ export class ContractWrappers { _.forEach(artifactsArray, artifact => { this._web3Wrapper.abiDecoder.addABI(artifact.compilerOutput.abi, artifact.contractName); }); - const blockPollingIntervalMs = - config.blockPollingIntervalMs === undefined - ? constants.DEFAULT_BLOCK_POLLING_INTERVAL - : config.blockPollingIntervalMs; const contractAddresses = config.contractAddresses === undefined ? _getDefaultContractAddresses(config.networkId) : config.contractAddresses; - this.erc20Proxy = new ERC20ProxyWrapper(this._web3Wrapper, config.networkId, contractAddresses.erc20Proxy); - this.erc721Proxy = new ERC721ProxyWrapper(this._web3Wrapper, config.networkId, contractAddresses.erc721Proxy); - this.erc20Token = new ERC20TokenWrapper( - this._web3Wrapper, - config.networkId, - this.erc20Proxy, - blockPollingIntervalMs, - ); - this.erc721Token = new ERC721TokenWrapper( - this._web3Wrapper, - config.networkId, - this.erc721Proxy, - blockPollingIntervalMs, - ); - this.etherToken = new EtherTokenWrapper( - this._web3Wrapper, - config.networkId, - this.erc20Token, - blockPollingIntervalMs, - ); - this.exchange = new ExchangeWrapper( - this._web3Wrapper, - config.networkId, - this.erc20Token, - this.erc721Token, - contractAddresses.exchange, - contractAddresses.zrxToken, - blockPollingIntervalMs, - ); - this.forwarder = new ForwarderWrapper( - this._web3Wrapper, - config.networkId, - contractAddresses.forwarder, - contractAddresses.zrxToken, - contractAddresses.etherToken, - ); - this.orderValidator = new OrderValidatorWrapper( - this._web3Wrapper, - config.networkId, - contractAddresses.orderValidator, - ); - this.dutchAuction = new DutchAuctionWrapper( - this._web3Wrapper, - config.networkId, - contractAddresses.dutchAuction, - ); + this.erc20Proxy = new ERC20ProxyContract(contractAddresses.erc20Proxy, this.getProvider()); + this.erc721Proxy = new ERC721ProxyContract(contractAddresses.erc721Proxy, this.getProvider()); + this.weth9 = new WETH9Contract(contractAddresses.etherToken, this.getProvider()); + this.exchange = new ExchangeContract(contractAddresses.exchange, this.getProvider()); + this.forwarder = new ForwarderContract(contractAddresses.forwarder, this.getProvider()); + this.orderValidator = new OrderValidatorContract(contractAddresses.orderValidator, this.getProvider()); + this.dutchAuction = new DutchAuctionContract(contractAddresses.dutchAuction, this.getProvider()); this.coordinator = new CoordinatorWrapper( this._web3Wrapper, config.networkId, @@ -170,15 +120,16 @@ export class ContractWrappers { contractAddresses.exchange, contractAddresses.coordinatorRegistry, ); + this.contractAddresses = contractAddresses; } /** * Unsubscribes from all subscriptions for all contracts. */ public unsubscribeAll(): void { this.exchange.unsubscribeAll(); - this.erc20Token.unsubscribeAll(); - this.erc721Token.unsubscribeAll(); - this.etherToken.unsubscribeAll(); + this.erc20Proxy.unsubscribeAll(); + this.erc721Proxy.unsubscribeAll(); + this.weth9.unsubscribeAll(); } /** * Get the provider instance currently used by contract-wrappers diff --git a/packages/contract-wrappers/src/contract_wrappers/dutch_auction_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/dutch_auction_wrapper.ts deleted file mode 100644 index 774ec1d16d..0000000000 --- a/packages/contract-wrappers/src/contract_wrappers/dutch_auction_wrapper.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { DutchAuctionContract } from '@0x/abi-gen-wrappers'; -import { DutchAuction } from '@0x/contract-artifacts'; -import { schemas } from '@0x/json-schemas'; -import { assetDataUtils } from '@0x/order-utils'; -import { DutchAuctionData, DutchAuctionDetails, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { ContractAbi } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema'; -import { txOptsSchema } from '../schemas/tx_opts_schema'; -import { DutchAuctionWrapperError, OrderTransactionOpts } from '../types'; -import { assert } from '../utils/assert'; -import { _getDefaultContractAddresses } from '../utils/contract_addresses'; - -import { ContractWrapper } from './contract_wrapper'; - -export class DutchAuctionWrapper extends ContractWrapper { - public abi: ContractAbi = DutchAuction.compilerOutput.abi; - public address: string; - private _dutchAuctionContractIfExists?: DutchAuctionContract; - /** - * Dutch auction details are encoded with the asset data for a 0x order. This function produces a hex - * encoded assetData string, containing information both about the asset being traded and the - * dutch auction; which is usable in the makerAssetData or takerAssetData fields in a 0x order. - * @param assetData Hex encoded assetData string for the asset being auctioned. - * @param beginTimeSeconds Begin time of the dutch auction. - * @param beginAmount Starting amount being sold in the dutch auction. - * @return The hex encoded assetData string. - */ - public static encodeDutchAuctionAssetData( - assetData: string, - beginTimeSeconds: BigNumber, - beginAmount: BigNumber, - ): string { - const dutchAuctionData = assetDataUtils.encodeDutchAuctionAssetData(assetData, beginTimeSeconds, beginAmount); - return dutchAuctionData; - } - /** - * Dutch auction details are encoded with the asset data for a 0x order. This function decodes a hex - * encoded assetData string, containing information both about the asset being traded and the - * dutch auction. - * @param dutchAuctionData Hex encoded assetData string for the asset being auctioned. - * @return An object containing the auction asset, auction begin time and auction begin amount. - */ - public static decodeDutchAuctionData(dutchAuctionData: string): DutchAuctionData { - const decoded = assetDataUtils.decodeDutchAuctionData(dutchAuctionData); - return decoded; - } - /** - * Instantiate DutchAuctionWrapper - * @param web3Wrapper Web3Wrapper instance to use. - * @param networkId Desired networkId. - * @param address The address of the Dutch Auction contract. If undefined, will - * default to the known address corresponding to the networkId. - */ - public constructor(web3Wrapper: Web3Wrapper, networkId: number, address?: string) { - super(web3Wrapper, networkId); - this.address = address === undefined ? _getDefaultContractAddresses(networkId).dutchAuction : address; - } - /** - * Matches the buy and sell orders at an amount given the following: the current block time, the auction - * start time and the auction begin amount. The sell order is a an order at the lowest amount - * at the end of the auction. Excess from the match is transferred to the seller. - * Over time the price moves from beginAmount to endAmount given the current block.timestamp. - * @param buyOrder The Buyer's order. This order is for the current expected price of the auction. - * @param sellOrder The Seller's order. This order is for the lowest amount (at the end of the auction). - * @param takerAddress The user Ethereum address who would like to fill this order. Must be available via the supplied - * Provider provided at instantiation. - * @return Transaction hash. - */ - public async matchOrdersAsync( - buyOrder: SignedOrder, - sellOrder: SignedOrder, - takerAddress: string, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - // type assertions - assert.doesConformToSchema('buyOrder', buyOrder, schemas.signedOrderSchema); - assert.doesConformToSchema('sellOrder', sellOrder, schemas.signedOrderSchema); - await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - const normalizedTakerAddress = takerAddress.toLowerCase(); - // other assertions - if ( - sellOrder.makerAssetData !== buyOrder.takerAssetData || - sellOrder.takerAssetData !== buyOrder.makerAssetData - ) { - throw new Error(DutchAuctionWrapperError.AssetDataMismatch); - } - // get contract - const dutchAuctionInstance = await this._getDutchAuctionContractAsync(); - // validate transaction - if (orderTransactionOpts.shouldValidate) { - await dutchAuctionInstance.matchOrders.callAsync( - buyOrder, - sellOrder, - buyOrder.signature, - sellOrder.signature, - { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - } - // send transaction - const txHash = await dutchAuctionInstance.matchOrders.sendTransactionAsync( - buyOrder, - sellOrder, - buyOrder.signature, - sellOrder.signature, - { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - return txHash; - } - /** - * Fetches the Auction Details for the given order - * @param sellOrder The Seller's order. This order is for the lowest amount (at the end of the auction). - * @return The dutch auction details. - */ - public async getAuctionDetailsAsync(sellOrder: SignedOrder): Promise { - // type assertions - assert.doesConformToSchema('sellOrder', sellOrder, schemas.signedOrderSchema); - // get contract - const dutchAuctionInstance = await this._getDutchAuctionContractAsync(); - // call contract - const auctionDetails = await dutchAuctionInstance.getAuctionDetails.callAsync(sellOrder); - return auctionDetails; - } - private async _getDutchAuctionContractAsync(): Promise { - if (this._dutchAuctionContractIfExists !== undefined) { - return this._dutchAuctionContractIfExists; - } - const contractInstance = new DutchAuctionContract( - this.address, - this._web3Wrapper.getProvider(), - this._web3Wrapper.getContractDefaults(), - ); - this._dutchAuctionContractIfExists = contractInstance; - return this._dutchAuctionContractIfExists; - } -} diff --git a/packages/contract-wrappers/src/contract_wrappers/erc20_proxy_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/erc20_proxy_wrapper.ts deleted file mode 100644 index 5574df315c..0000000000 --- a/packages/contract-wrappers/src/contract_wrappers/erc20_proxy_wrapper.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { ERC20ProxyContract } from '@0x/abi-gen-wrappers'; -import { ERC20Proxy } from '@0x/contract-artifacts'; -import { AssetProxyId } from '@0x/types'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { ContractAbi } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { assert } from '../utils/assert'; -import { _getDefaultContractAddresses } from '../utils/contract_addresses'; - -import { ContractWrapper } from './contract_wrapper'; - -/** - * This class includes the functionality related to interacting with the ERC20Proxy contract. - */ -export class ERC20ProxyWrapper extends ContractWrapper { - public abi: ContractAbi = ERC20Proxy.compilerOutput.abi; - public address: string; - private _erc20ProxyContractIfExists?: ERC20ProxyContract; - /** - * Instantiate ERC20ProxyWrapper - * @param web3Wrapper Web3Wrapper instance to use - * @param networkId Desired networkId - * @param address The address of the ERC20Proxy contract. If undefined, will - * default to the known address corresponding to the networkId. - */ - constructor(web3Wrapper: Web3Wrapper, networkId: number, address?: string) { - super(web3Wrapper, networkId); - this.address = address === undefined ? _getDefaultContractAddresses(networkId).erc20Proxy : address; - } - /** - * Get the 4 bytes ID of this asset proxy - * @return Proxy id - */ - public async getProxyIdAsync(): Promise { - const ERC20ProxyContractInstance = this._getERC20ProxyContract(); - // Note(albrow): Below is a TSLint false positive. Code won't compile if - // you remove the type assertion. - /* tslint:disable-next-line:no-unnecessary-type-assertion */ - const proxyId = (await ERC20ProxyContractInstance.getProxyId.callAsync()) as AssetProxyId; - return proxyId; - } - /** - * Check if the Exchange contract address is authorized by the ERC20Proxy contract. - * @param exchangeContractAddress The hex encoded address of the Exchange contract to call. - * @return Whether the exchangeContractAddress is authorized. - */ - public async isAuthorizedAsync(exchangeContractAddress: string): Promise { - assert.isETHAddressHex('exchangeContractAddress', exchangeContractAddress); - const normalizedExchangeContractAddress = exchangeContractAddress.toLowerCase(); - const ERC20ProxyContractInstance = this._getERC20ProxyContract(); - const isAuthorized = await ERC20ProxyContractInstance.authorized.callAsync(normalizedExchangeContractAddress); - return isAuthorized; - } - /** - * Get the list of all Exchange contract addresses authorized by the ERC20Proxy contract. - * @return The list of authorized addresses. - */ - public async getAuthorizedAddressesAsync(): Promise { - const ERC20ProxyContractInstance = this._getERC20ProxyContract(); - const authorizedAddresses = await ERC20ProxyContractInstance.getAuthorizedAddresses.callAsync(); - return authorizedAddresses; - } - private _getERC20ProxyContract(): ERC20ProxyContract { - if (this._erc20ProxyContractIfExists !== undefined) { - return this._erc20ProxyContractIfExists; - } - const contractInstance = new ERC20ProxyContract( - this.address, - this._web3Wrapper.getProvider(), - this._web3Wrapper.getContractDefaults(), - ); - this._erc20ProxyContractIfExists = contractInstance; - return this._erc20ProxyContractIfExists; - } -} diff --git a/packages/contract-wrappers/src/contract_wrappers/erc20_token_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/erc20_token_wrapper.ts deleted file mode 100644 index 989cf95193..0000000000 --- a/packages/contract-wrappers/src/contract_wrappers/erc20_token_wrapper.ts +++ /dev/null @@ -1,442 +0,0 @@ -import { ERC20TokenContract, ERC20TokenEventArgs, ERC20TokenEvents } from '@0x/abi-gen-wrappers'; -import { ERC20Token } from '@0x/contract-artifacts'; -import { schemas } from '@0x/json-schemas'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { ContractAbi, LogWithDecodedArgs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { methodOptsSchema } from '../schemas/method_opts_schema'; -import { txOptsSchema } from '../schemas/tx_opts_schema'; -import { - BlockRange, - ContractWrappersError, - EventCallback, - IndexedFilterValues, - MethodOpts, - TransactionOpts, -} from '../types'; -import { assert } from '../utils/assert'; -import { constants } from '../utils/constants'; -import { utils } from '../utils/utils'; - -import { ContractWrapper } from './contract_wrapper'; -import { ERC20ProxyWrapper } from './erc20_proxy_wrapper'; - -/** - * This class includes all the functionality related to interacting with ERC20 token contracts. - * All ERC20 method calls are supported, along with some convenience methods for getting/setting allowances - * to the 0x ERC20 Proxy smart contract. - */ -export class ERC20TokenWrapper extends ContractWrapper { - public abi: ContractAbi = ERC20Token.compilerOutput.abi; - public UNLIMITED_ALLOWANCE_IN_BASE_UNITS = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS; - private readonly _tokenContractsByAddress: { [address: string]: ERC20TokenContract }; - private readonly _erc20ProxyWrapper: ERC20ProxyWrapper; - /** - * Instantiate ERC20TokenWrapper - * @param web3Wrapper Web3Wrapper instance to use - * @param networkId Desired networkId - * @param erc20ProxyWrapper The ERC20ProxyWrapper instance to use - * @param blockPollingIntervalMs The block polling interval to use for active subscriptions - */ - constructor( - web3Wrapper: Web3Wrapper, - networkId: number, - erc20ProxyWrapper: ERC20ProxyWrapper, - blockPollingIntervalMs?: number, - ) { - super(web3Wrapper, networkId, blockPollingIntervalMs); - this._tokenContractsByAddress = {}; - this._erc20ProxyWrapper = erc20ProxyWrapper; - } - /** - * Retrieves an owner's ERC20 token balance. - * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed. - * @param ownerAddress The hex encoded user Ethereum address whose balance you would like to check. - * @param methodOpts Optional arguments this method accepts. - * @return The owner's ERC20 token balance in base units. - */ - public async getBalanceAsync( - tokenAddress: string, - ownerAddress: string, - methodOpts: MethodOpts = {}, - ): Promise { - assert.isETHAddressHex('ownerAddress', ownerAddress); - assert.isETHAddressHex('tokenAddress', tokenAddress); - assert.doesConformToSchema('methodOpts', methodOpts, methodOptsSchema); - const normalizedTokenAddress = tokenAddress.toLowerCase(); - const normalizedOwnerAddress = ownerAddress.toLowerCase(); - - const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); - - const txData = {}; - let balance = await tokenContract.balanceOf.callAsync(normalizedOwnerAddress, txData, methodOpts.defaultBlock); - // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber - balance = new BigNumber(balance); - return balance; - } - /** - * Sets the spender's allowance to a specified number of baseUnits on behalf of the owner address. - * Equivalent to the ERC20 spec method `approve`. - * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed. - * @param ownerAddress The hex encoded user Ethereum address who would like to set an allowance - * for spenderAddress. - * @param spenderAddress The hex encoded user Ethereum address who will be able to spend the set allowance. - * @param amountInBaseUnits The allowance amount you would like to set. - * @param txOpts Transaction parameters. - * @return Transaction hash. - */ - public async setAllowanceAsync( - tokenAddress: string, - ownerAddress: string, - spenderAddress: string, - amountInBaseUnits: BigNumber, - txOpts: TransactionOpts = {}, - ): Promise { - assert.isETHAddressHex('tokenAddress', tokenAddress); - await assert.isSenderAddressAsync('ownerAddress', ownerAddress, this._web3Wrapper); - assert.isETHAddressHex('spenderAddress', spenderAddress); - assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits); - assert.doesConformToSchema('txOpts', txOpts, txOptsSchema); - const normalizedTokenAddress = tokenAddress.toLowerCase(); - const normalizedOwnerAddress = ownerAddress.toLowerCase(); - const normalizedSpenderAddress = spenderAddress.toLowerCase(); - - const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); - const txHash = await tokenContract.approve.sendTransactionAsync( - normalizedSpenderAddress, - amountInBaseUnits, - utils.removeUndefinedProperties({ - from: normalizedOwnerAddress, - gas: txOpts.gasLimit, - gasPrice: txOpts.gasPrice, - nonce: txOpts.nonce, - }), - ); - return txHash; - } - /** - * Sets the spender's allowance to an unlimited number of baseUnits on behalf of the owner address. - * Equivalent to the ERC20 spec method `approve`. - * Setting an unlimited allowance will lower the gas cost for filling orders involving tokens that forego updating - * allowances set to the max amount (e.g ZRX, WETH) - * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed. - * @param ownerAddress The hex encoded user Ethereum address who would like to set an allowance - * for spenderAddress. - * @param spenderAddress The hex encoded user Ethereum address who will be able to spend the set allowance. - * @param txOpts Transaction parameters. - * @return Transaction hash. - */ - public async setUnlimitedAllowanceAsync( - tokenAddress: string, - ownerAddress: string, - spenderAddress: string, - txOpts: TransactionOpts = {}, - ): Promise { - const txHash = await this.setAllowanceAsync( - tokenAddress, - ownerAddress, - spenderAddress, - this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, - txOpts, - ); - return txHash; - } - /** - * Retrieves the owners allowance in baseUnits set to the spender's address. - * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed. - * @param ownerAddress The hex encoded user Ethereum address whose allowance to spenderAddress - * you would like to retrieve. - * @param spenderAddress The hex encoded user Ethereum address who can spend the allowance you are fetching. - * @param methodOpts Optional arguments this method accepts. - */ - public async getAllowanceAsync( - tokenAddress: string, - ownerAddress: string, - spenderAddress: string, - methodOpts: MethodOpts = {}, - ): Promise { - assert.isETHAddressHex('tokenAddress', tokenAddress); - assert.isETHAddressHex('ownerAddress', ownerAddress); - assert.isETHAddressHex('spenderAddress', spenderAddress); - assert.doesConformToSchema('methodOpts', methodOpts, methodOptsSchema); - const normalizedTokenAddress = tokenAddress.toLowerCase(); - const normalizedOwnerAddress = ownerAddress.toLowerCase(); - const normalizedSpenderAddress = spenderAddress.toLowerCase(); - - const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); - - const txData = {}; - let allowanceInBaseUnits = await tokenContract.allowance.callAsync( - normalizedOwnerAddress, - normalizedSpenderAddress, - txData, - methodOpts.defaultBlock, - ); - // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber - allowanceInBaseUnits = new BigNumber(allowanceInBaseUnits); - return allowanceInBaseUnits; - } - /** - * Retrieves the owner's allowance in baseUnits set to the 0x proxy contract. - * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed. - * @param ownerAddress The hex encoded user Ethereum address whose proxy contract allowance we are retrieving. - * @param methodOpts Optional arguments this method accepts. - */ - public async getProxyAllowanceAsync( - tokenAddress: string, - ownerAddress: string, - methodOpts: MethodOpts = {}, - ): Promise { - const proxyAddress = this._erc20ProxyWrapper.address; - const allowanceInBaseUnits = await this.getAllowanceAsync(tokenAddress, ownerAddress, proxyAddress, methodOpts); - return allowanceInBaseUnits; - } - /** - * Sets the 0x proxy contract's allowance to a specified number of a tokens' baseUnits on behalf - * of an owner address. - * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed. - * @param ownerAddress The hex encoded user Ethereum address who is setting an allowance - * for the Proxy contract. - * @param amountInBaseUnits The allowance amount specified in baseUnits. - * @param txOpts Transaction parameters. - * @return Transaction hash. - */ - public async setProxyAllowanceAsync( - tokenAddress: string, - ownerAddress: string, - amountInBaseUnits: BigNumber, - txOpts: TransactionOpts = {}, - ): Promise { - const proxyAddress = this._erc20ProxyWrapper.address; - const txHash = await this.setAllowanceAsync( - tokenAddress, - ownerAddress, - proxyAddress, - amountInBaseUnits, - txOpts, - ); - return txHash; - } - /** - * Sets the 0x proxy contract's allowance to a unlimited number of a tokens' baseUnits on behalf - * of an owner address. - * Setting an unlimited allowance will lower the gas cost for filling orders involving tokens that forego updating - * allowances set to the max amount (e.g ZRX, WETH) - * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed. - * @param ownerAddress The hex encoded user Ethereum address who is setting an allowance - * for the Proxy contract. - * @param txOpts Transaction parameters. - * @return Transaction hash. - */ - public async setUnlimitedProxyAllowanceAsync( - tokenAddress: string, - ownerAddress: string, - txOpts: TransactionOpts = {}, - ): Promise { - const txHash = await this.setProxyAllowanceAsync( - tokenAddress, - ownerAddress, - this.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, - txOpts, - ); - return txHash; - } - /** - * Transfers `amountInBaseUnits` ERC20 tokens from `fromAddress` to `toAddress`. - * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed. - * @param fromAddress The hex encoded user Ethereum address that will send the funds. - * @param toAddress The hex encoded user Ethereum address that will receive the funds. - * @param amountInBaseUnits The amount (specified in baseUnits) of the token to transfer. - * @param txOpts Transaction parameters. - * @return Transaction hash. - */ - public async transferAsync( - tokenAddress: string, - fromAddress: string, - toAddress: string, - amountInBaseUnits: BigNumber, - txOpts: TransactionOpts = {}, - ): Promise { - assert.isETHAddressHex('tokenAddress', tokenAddress); - await assert.isSenderAddressAsync('fromAddress', fromAddress, this._web3Wrapper); - assert.isETHAddressHex('toAddress', toAddress); - assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits); - assert.doesConformToSchema('txOpts', txOpts, txOptsSchema); - const normalizedTokenAddress = tokenAddress.toLowerCase(); - const normalizedFromAddress = fromAddress.toLowerCase(); - const normalizedToAddress = toAddress.toLowerCase(); - - const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); - - const fromAddressBalance = await this.getBalanceAsync(normalizedTokenAddress, normalizedFromAddress); - if (fromAddressBalance.isLessThan(amountInBaseUnits)) { - throw new Error(ContractWrappersError.InsufficientBalanceForTransfer); - } - - const txHash = await tokenContract.transfer.sendTransactionAsync( - normalizedToAddress, - amountInBaseUnits, - utils.removeUndefinedProperties({ - from: normalizedFromAddress, - gas: txOpts.gasLimit, - gasPrice: txOpts.gasPrice, - nonce: txOpts.nonce, - }), - ); - return txHash; - } - /** - * Transfers `amountInBaseUnits` ERC20 tokens from `fromAddress` to `toAddress`. - * Requires the fromAddress to have sufficient funds and to have approved an allowance of - * `amountInBaseUnits` to `senderAddress`. - * @param tokenAddress The hex encoded contract Ethereum address where the ERC20 token is deployed. - * @param fromAddress The hex encoded user Ethereum address whose funds are being sent. - * @param toAddress The hex encoded user Ethereum address that will receive the funds. - * @param senderAddress The hex encoded user Ethereum address whose initiates the fund transfer. The - * `fromAddress` must have set an allowance to the `senderAddress` - * before this call. - * @param amountInBaseUnits The amount (specified in baseUnits) of the token to transfer. - * @param txOpts Transaction parameters. - * @return Transaction hash. - */ - public async transferFromAsync( - tokenAddress: string, - fromAddress: string, - toAddress: string, - senderAddress: string, - amountInBaseUnits: BigNumber, - txOpts: TransactionOpts = {}, - ): Promise { - assert.isETHAddressHex('tokenAddress', tokenAddress); - assert.isETHAddressHex('fromAddress', fromAddress); - assert.isETHAddressHex('toAddress', toAddress); - await assert.isSenderAddressAsync('senderAddress', senderAddress, this._web3Wrapper); - assert.isValidBaseUnitAmount('amountInBaseUnits', amountInBaseUnits); - assert.doesConformToSchema('txOpts', txOpts, txOptsSchema); - const normalizedToAddress = toAddress.toLowerCase(); - const normalizedFromAddress = fromAddress.toLowerCase(); - const normalizedTokenAddress = tokenAddress.toLowerCase(); - const normalizedSenderAddress = senderAddress.toLowerCase(); - - const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); - - const fromAddressAllowance = await this.getAllowanceAsync( - normalizedTokenAddress, - normalizedFromAddress, - normalizedSenderAddress, - ); - if (fromAddressAllowance.isLessThan(amountInBaseUnits)) { - throw new Error(ContractWrappersError.InsufficientAllowanceForTransfer); - } - - const fromAddressBalance = await this.getBalanceAsync(normalizedTokenAddress, normalizedFromAddress); - if (fromAddressBalance.isLessThan(amountInBaseUnits)) { - throw new Error(ContractWrappersError.InsufficientBalanceForTransfer); - } - - const txHash = await tokenContract.transferFrom.sendTransactionAsync( - normalizedFromAddress, - normalizedToAddress, - amountInBaseUnits, - utils.removeUndefinedProperties({ - from: normalizedSenderAddress, - gas: txOpts.gasLimit, - gasPrice: txOpts.gasPrice, - nonce: txOpts.nonce, - }), - ); - return txHash; - } - /** - * Subscribe to an event type emitted by the Token contract. - * @param tokenAddress The hex encoded address where the ERC20 token is deployed. - * @param eventName The token contract event you would like to subscribe to. - * @param indexFilterValues An object where the keys are indexed args returned by the event and - * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` - * @param callback Callback that gets called when a log is added/removed - * @param isVerbose Enable verbose subscription warnings (e.g recoverable network issues encountered) - * @return Subscription token used later to unsubscribe - */ - public subscribe( - tokenAddress: string, - eventName: ERC20TokenEvents, - indexFilterValues: IndexedFilterValues, - callback: EventCallback, - isVerbose: boolean = false, - ): string { - assert.isETHAddressHex('tokenAddress', tokenAddress); - assert.doesBelongToStringEnum('eventName', eventName, ERC20TokenEvents); - assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); - assert.isFunction('callback', callback); - const normalizedTokenAddress = tokenAddress.toLowerCase(); - const subscriptionToken = this._subscribe( - normalizedTokenAddress, - eventName, - indexFilterValues, - ERC20Token.compilerOutput.abi, - callback, - isVerbose, - ); - return subscriptionToken; - } - /** - * Cancel a subscription - * @param subscriptionToken Subscription token returned by `subscribe()` - */ - public unsubscribe(subscriptionToken: string): void { - assert.isValidSubscriptionToken('subscriptionToken', subscriptionToken); - this._unsubscribe(subscriptionToken); - } - /** - * Cancels all existing subscriptions - */ - public unsubscribeAll(): void { - super._unsubscribeAll(); - } - /** - * Gets historical logs without creating a subscription - * @param tokenAddress An address of the token that emitted the logs. - * @param eventName The token contract event you would like to subscribe to. - * @param blockRange Block range to get logs from. - * @param indexFilterValues An object where the keys are indexed args returned by the event and - * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` - * @return Array of logs that match the parameters - */ - public async getLogsAsync( - tokenAddress: string, - eventName: ERC20TokenEvents, - blockRange: BlockRange, - indexFilterValues: IndexedFilterValues, - ): Promise>> { - assert.isETHAddressHex('tokenAddress', tokenAddress); - assert.doesBelongToStringEnum('eventName', eventName, ERC20TokenEvents); - assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); - assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); - const normalizedTokenAddress = tokenAddress.toLowerCase(); - const logs = await this._getLogsAsync( - normalizedTokenAddress, - eventName, - blockRange, - indexFilterValues, - ERC20Token.compilerOutput.abi, - ); - return logs; - } - private async _getTokenContractAsync(tokenAddress: string): Promise { - const normalizedTokenAddress = tokenAddress.toLowerCase(); - let tokenContract = this._tokenContractsByAddress[normalizedTokenAddress]; - if (tokenContract !== undefined) { - return tokenContract; - } - const contractInstance = new ERC20TokenContract( - normalizedTokenAddress, - this._web3Wrapper.getProvider(), - this._web3Wrapper.getContractDefaults(), - ); - tokenContract = contractInstance; - this._tokenContractsByAddress[normalizedTokenAddress] = tokenContract; - return tokenContract; - } -} diff --git a/packages/contract-wrappers/src/contract_wrappers/erc721_proxy_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/erc721_proxy_wrapper.ts deleted file mode 100644 index 801e393a3f..0000000000 --- a/packages/contract-wrappers/src/contract_wrappers/erc721_proxy_wrapper.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { ERC721ProxyContract } from '@0x/abi-gen-wrappers'; -import { ERC721Proxy } from '@0x/contract-artifacts'; -import { AssetProxyId } from '@0x/types'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { ContractAbi } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { assert } from '../utils/assert'; -import { _getDefaultContractAddresses } from '../utils/contract_addresses'; - -import { ContractWrapper } from './contract_wrapper'; - -/** - * This class includes the functionality related to interacting with the ERC721Proxy contract. - */ -export class ERC721ProxyWrapper extends ContractWrapper { - public abi: ContractAbi = ERC721Proxy.compilerOutput.abi; - public address: string; - private _erc721ProxyContractIfExists?: ERC721ProxyContract; - /** - * Instantiate ERC721ProxyWrapper - * @param web3Wrapper Web3Wrapper instance to use - * @param networkId Desired networkId - * @param address The address of the ERC721Proxy contract. If undefined, - * will default to the known address corresponding to the networkId. - */ - constructor(web3Wrapper: Web3Wrapper, networkId: number, address?: string) { - super(web3Wrapper, networkId); - this.address = address === undefined ? _getDefaultContractAddresses(networkId).erc721Proxy : address; - } - /** - * Get the 4 bytes ID of this asset proxy - * @return Proxy id - */ - public async getProxyIdAsync(): Promise { - const ERC721ProxyContractInstance = await this._getERC721ProxyContract(); - // Note(albrow): Below is a TSLint false positive. Code won't compile if - // you remove the type assertion. - /* tslint:disable-next-line:no-unnecessary-type-assertion */ - const proxyId = (await ERC721ProxyContractInstance.getProxyId.callAsync()) as AssetProxyId; - return proxyId; - } - /** - * Check if the Exchange contract address is authorized by the ERC721Proxy contract. - * @param exchangeContractAddress The hex encoded address of the Exchange contract to call. - * @return Whether the exchangeContractAddress is authorized. - */ - public async isAuthorizedAsync(exchangeContractAddress: string): Promise { - assert.isETHAddressHex('exchangeContractAddress', exchangeContractAddress); - const normalizedExchangeContractAddress = exchangeContractAddress.toLowerCase(); - const ERC721ProxyContractInstance = await this._getERC721ProxyContract(); - const isAuthorized = await ERC721ProxyContractInstance.authorized.callAsync(normalizedExchangeContractAddress); - return isAuthorized; - } - /** - * Get the list of all Exchange contract addresses authorized by the ERC721Proxy contract. - * @return The list of authorized addresses. - */ - public async getAuthorizedAddressesAsync(): Promise { - const ERC721ProxyContractInstance = await this._getERC721ProxyContract(); - const authorizedAddresses = await ERC721ProxyContractInstance.getAuthorizedAddresses.callAsync(); - return authorizedAddresses; - } - private _getERC721ProxyContract(): ERC721ProxyContract { - if (this._erc721ProxyContractIfExists !== undefined) { - return this._erc721ProxyContractIfExists; - } - const contractInstance = new ERC721ProxyContract( - this.address, - this._web3Wrapper.getProvider(), - this._web3Wrapper.getContractDefaults(), - ); - this._erc721ProxyContractIfExists = contractInstance; - return this._erc721ProxyContractIfExists; - } -} diff --git a/packages/contract-wrappers/src/contract_wrappers/erc721_token_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/erc721_token_wrapper.ts deleted file mode 100644 index 12c899cf4f..0000000000 --- a/packages/contract-wrappers/src/contract_wrappers/erc721_token_wrapper.ts +++ /dev/null @@ -1,469 +0,0 @@ -import { ERC721TokenContract, ERC721TokenEventArgs, ERC721TokenEvents } from '@0x/abi-gen-wrappers'; -import { ERC721Token } from '@0x/contract-artifacts'; -import { schemas } from '@0x/json-schemas'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { ContractAbi, LogWithDecodedArgs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { methodOptsSchema } from '../schemas/method_opts_schema'; -import { txOptsSchema } from '../schemas/tx_opts_schema'; -import { - BlockRange, - ContractWrappersError, - EventCallback, - IndexedFilterValues, - MethodOpts, - TransactionOpts, -} from '../types'; -import { assert } from '../utils/assert'; -import { constants } from '../utils/constants'; -import { utils } from '../utils/utils'; - -import { ContractWrapper } from './contract_wrapper'; -import { ERC721ProxyWrapper } from './erc721_proxy_wrapper'; - -/** - * This class includes all the functionality related to interacting with ERC721 token contracts. - * All ERC721 method calls are supported, along with some convenience methods for getting/setting allowances - * to the 0x ERC721 Proxy smart contract. - */ -export class ERC721TokenWrapper extends ContractWrapper { - public abi: ContractAbi = ERC721Token.compilerOutput.abi; - private readonly _tokenContractsByAddress: { [address: string]: ERC721TokenContract }; - private readonly _erc721ProxyWrapper: ERC721ProxyWrapper; - /** - * Instantiate ERC721TokenWrapper - * @param web3Wrapper Web3Wrapper instance to use - * @param networkId Desired networkId - * @param erc721ProxyWrapper The ERC721ProxyWrapper instance to use - * @param blockPollingIntervalMs The block polling interval to use for active subscriptions - */ - constructor( - web3Wrapper: Web3Wrapper, - networkId: number, - erc721ProxyWrapper: ERC721ProxyWrapper, - blockPollingIntervalMs?: number, - ) { - super(web3Wrapper, networkId, blockPollingIntervalMs); - this._tokenContractsByAddress = {}; - this._erc721ProxyWrapper = erc721ProxyWrapper; - } - /** - * Count all NFTs assigned to an owner - * NFTs assigned to the zero address are considered invalid, and this function throws for queries about the zero address. - * @param tokenAddress The hex encoded contract Ethereum address where the ERC721 token is deployed. - * @param ownerAddress The hex encoded user Ethereum address whose balance you would like to check. - * @param methodOpts Optional arguments this method accepts. - * @return The number of NFTs owned by `ownerAddress`, possibly zero - */ - public async getTokenCountAsync( - tokenAddress: string, - ownerAddress: string, - methodOpts: MethodOpts = {}, - ): Promise { - assert.isETHAddressHex('tokenAddress', tokenAddress); - assert.isETHAddressHex('ownerAddress', ownerAddress); - assert.doesConformToSchema('methodOpts', methodOpts, methodOptsSchema); - const normalizedTokenAddress = tokenAddress.toLowerCase(); - const normalizedOwnerAddress = ownerAddress.toLowerCase(); - - const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); - - const txData = {}; - let balance = await tokenContract.balanceOf.callAsync(normalizedOwnerAddress, txData, methodOpts.defaultBlock); - // Wrap BigNumbers returned from web3 with our own (later) version of BigNumber - balance = new BigNumber(balance); - return balance; - } - /** - * Find the owner of an NFT - * NFTs assigned to zero address are considered invalid, and queries about them do throw. - * @param tokenAddress The hex encoded contract Ethereum address where the ERC721 token is deployed. - * @param tokenId The identifier for an NFT - * @param methodOpts Optional arguments this method accepts. - * @return The address of the owner of the NFT - */ - public async getOwnerOfAsync( - tokenAddress: string, - tokenId: BigNumber, - methodOpts: MethodOpts = {}, - ): Promise { - assert.isETHAddressHex('tokenAddress', tokenAddress); - assert.isBigNumber('tokenId', tokenId); - assert.doesConformToSchema('methodOpts', methodOpts, methodOptsSchema); - const normalizedTokenAddress = tokenAddress.toLowerCase(); - - const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); - - const txData = {}; - try { - const tokenOwner = await tokenContract.ownerOf.callAsync(tokenId, txData, methodOpts.defaultBlock); - return tokenOwner; - } catch (err) { - throw new Error(ContractWrappersError.ERC721OwnerNotFound); - } - } - /** - * Query if an address is an authorized operator for all NFT's of `ownerAddress` - * @param tokenAddress The hex encoded contract Ethereum address where the ERC721 token is deployed. - * @param ownerAddress The hex encoded user Ethereum address of the token owner. - * @param operatorAddress The hex encoded user Ethereum address of the operator you'd like to check if approved. - * @param methodOpts Optional arguments this method accepts. - * @return True if `operatorAddress` is an approved operator for `ownerAddress`, false otherwise - */ - public async isApprovedForAllAsync( - tokenAddress: string, - ownerAddress: string, - operatorAddress: string, - methodOpts: MethodOpts = {}, - ): Promise { - assert.isETHAddressHex('tokenAddress', tokenAddress); - assert.isETHAddressHex('ownerAddress', ownerAddress); - assert.isETHAddressHex('operatorAddress', operatorAddress); - assert.doesConformToSchema('methodOpts', methodOpts, methodOptsSchema); - const normalizedTokenAddress = tokenAddress.toLowerCase(); - const normalizedOwnerAddress = ownerAddress.toLowerCase(); - const normalizedOperatorAddress = operatorAddress.toLowerCase(); - - const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); - - const txData = {}; - const isApprovedForAll = await tokenContract.isApprovedForAll.callAsync( - normalizedOwnerAddress, - normalizedOperatorAddress, - txData, - methodOpts.defaultBlock, - ); - return isApprovedForAll; - } - /** - * Query if 0x proxy is an authorized operator for all NFT's of `ownerAddress` - * @param tokenAddress The hex encoded contract Ethereum address where the ERC721 token is deployed. - * @param ownerAddress The hex encoded user Ethereum address of the token owner. - * @param methodOpts Optional arguments this method accepts. - * @return True if `operatorAddress` is an approved operator for `ownerAddress`, false otherwise - */ - public async isProxyApprovedForAllAsync( - tokenAddress: string, - ownerAddress: string, - methodOpts: MethodOpts = {}, - ): Promise { - const proxyAddress = this._erc721ProxyWrapper.address; - const isProxyApprovedForAll = await this.isApprovedForAllAsync( - tokenAddress, - ownerAddress, - proxyAddress, - methodOpts, - ); - return isProxyApprovedForAll; - } - /** - * Get the approved address for a single NFT. Returns undefined if no approval was set - * Throws if `_tokenId` is not a valid NFT - * @param tokenAddress The hex encoded contract Ethereum address where the ERC721 token is deployed. - * @param tokenId The identifier for an NFT - * @param methodOpts Optional arguments this method accepts. - * @return The approved address for this NFT, or the undefined if there is none - */ - public async getApprovedIfExistsAsync( - tokenAddress: string, - tokenId: BigNumber, - methodOpts: MethodOpts = {}, - ): Promise { - assert.isETHAddressHex('tokenAddress', tokenAddress); - assert.isBigNumber('tokenId', tokenId); - assert.doesConformToSchema('methodOpts', methodOpts, methodOptsSchema); - const normalizedTokenAddress = tokenAddress.toLowerCase(); - - const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); - - const txData = {}; - const approvedAddress = await tokenContract.getApproved.callAsync(tokenId, txData, methodOpts.defaultBlock); - if (approvedAddress === constants.NULL_ADDRESS) { - return undefined; - } - return approvedAddress; - } - /** - * Checks if 0x proxy is approved for a single NFT - * Throws if `_tokenId` is not a valid NFT - * @param tokenAddress The hex encoded contract Ethereum address where the ERC721 token is deployed. - * @param tokenId The identifier for an NFT - * @param methodOpts Optional arguments this method accepts. - * @return True if 0x proxy is approved - */ - public async isProxyApprovedAsync( - tokenAddress: string, - tokenId: BigNumber, - methodOpts: MethodOpts = {}, - ): Promise { - const proxyAddress = this._erc721ProxyWrapper.address; - const approvedAddress = await this.getApprovedIfExistsAsync(tokenAddress, tokenId, methodOpts); - const isProxyApproved = approvedAddress === proxyAddress; - return isProxyApproved; - } - /** - * Enable or disable approval for a third party ("operator") to manage all of `ownerAddress`'s assets. - * Throws if `_tokenId` is not a valid NFT - * Emits the ApprovalForAll event. - * @param tokenAddress The hex encoded contract Ethereum address where the ERC721 token is deployed. - * @param ownerAddress The hex encoded user Ethereum address of the token owner. - * @param operatorAddress The hex encoded user Ethereum address of the operator you'd like to set approval for. - * @param isApproved The boolean variable to set the approval to. - * @param txOpts Transaction parameters. - * @return Transaction hash. - */ - public async setApprovalForAllAsync( - tokenAddress: string, - ownerAddress: string, - operatorAddress: string, - isApproved: boolean, - txOpts: TransactionOpts = {}, - ): Promise { - assert.isETHAddressHex('tokenAddress', tokenAddress); - await assert.isSenderAddressAsync('ownerAddress', ownerAddress, this._web3Wrapper); - assert.isETHAddressHex('operatorAddress', operatorAddress); - assert.isBoolean('isApproved', isApproved); - assert.doesConformToSchema('txOpts', txOpts, txOptsSchema); - const normalizedTokenAddress = tokenAddress.toLowerCase(); - const normalizedOwnerAddress = ownerAddress.toLowerCase(); - const normalizedOperatorAddress = operatorAddress.toLowerCase(); - - const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); - const txHash = await tokenContract.setApprovalForAll.sendTransactionAsync( - normalizedOperatorAddress, - isApproved, - utils.removeUndefinedProperties({ - gas: txOpts.gasLimit, - gasPrice: txOpts.gasPrice, - from: normalizedOwnerAddress, - nonce: txOpts.nonce, - }), - ); - return txHash; - } - /** - * Enable or disable approval for a third party ("operator") to manage all of `ownerAddress`'s assets. - * Throws if `_tokenId` is not a valid NFT - * Emits the ApprovalForAll event. - * @param tokenAddress The hex encoded contract Ethereum address where the ERC721 token is deployed. - * @param ownerAddress The hex encoded user Ethereum address of the token owner. - * @param operatorAddress The hex encoded user Ethereum address of the operator you'd like to set approval for. - * @param isApproved The boolean variable to set the approval to. - * @param txOpts Transaction parameters. - * @return Transaction hash. - */ - public async setProxyApprovalForAllAsync( - tokenAddress: string, - ownerAddress: string, - isApproved: boolean, - txOpts: TransactionOpts = {}, - ): Promise { - const proxyAddress = this._erc721ProxyWrapper.address; - const txHash = await this.setApprovalForAllAsync(tokenAddress, ownerAddress, proxyAddress, isApproved, txOpts); - return txHash; - } - /** - * Set or reaffirm the approved address for an NFT - * The zero address indicates there is no approved address. Throws unless `msg.sender` is the current NFT owner, - * or an authorized operator of the current owner. - * Throws if `_tokenId` is not a valid NFT - * Emits the Approval event. - * @param tokenAddress The hex encoded contract Ethereum address where the ERC721 token is deployed. - * @param approvedAddress The hex encoded user Ethereum address you'd like to set approval for. - * @param tokenId The identifier for an NFT - * @param txOpts Transaction parameters. - * @return Transaction hash. - */ - public async setApprovalAsync( - tokenAddress: string, - approvedAddress: string, - tokenId: BigNumber, - txOpts: TransactionOpts = {}, - ): Promise { - assert.isETHAddressHex('tokenAddress', tokenAddress); - assert.isETHAddressHex('approvedAddress', approvedAddress); - assert.isBigNumber('tokenId', tokenId); - assert.doesConformToSchema('txOpts', txOpts, txOptsSchema); - const normalizedTokenAddress = tokenAddress.toLowerCase(); - const normalizedApprovedAddress = approvedAddress.toLowerCase(); - - const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); - const tokenOwnerAddress = await tokenContract.ownerOf.callAsync(tokenId); - await assert.isSenderAddressAsync('tokenOwnerAddress', tokenOwnerAddress, this._web3Wrapper); - const txHash = await tokenContract.approve.sendTransactionAsync( - normalizedApprovedAddress, - tokenId, - utils.removeUndefinedProperties({ - gas: txOpts.gasLimit, - gasPrice: txOpts.gasPrice, - from: tokenOwnerAddress, - nonce: txOpts.nonce, - }), - ); - return txHash; - } - /** - * Set or reaffirm 0x proxy as an approved address for an NFT - * Throws unless `msg.sender` is the current NFT owner, or an authorized operator of the current owner. - * Throws if `_tokenId` is not a valid NFT - * Emits the Approval event. - * @param tokenAddress The hex encoded contract Ethereum address where the ERC721 token is deployed. - * @param tokenId The identifier for an NFT - * @param txOpts Transaction parameters. - * @return Transaction hash. - */ - public async setProxyApprovalAsync( - tokenAddress: string, - tokenId: BigNumber, - txOpts: TransactionOpts = {}, - ): Promise { - const proxyAddress = this._erc721ProxyWrapper.address; - const txHash = await this.setApprovalAsync(tokenAddress, proxyAddress, tokenId, txOpts); - return txHash; - } - /** - * Enable or disable approval for a third party ("operator") to manage all of `ownerAddress`'s assets. - * Throws if `_tokenId` is not a valid NFT - * Emits the ApprovalForAll event. - * @param tokenAddress The hex encoded contract Ethereum address where the ERC721 token is deployed. - * @param receiverAddress The hex encoded Ethereum address of the user to send the NFT to. - * @param senderAddress The hex encoded Ethereum address of the user to send the NFT to. - * @param tokenId The identifier for an NFT - * @param txOpts Transaction parameters. - * @return Transaction hash. - */ - public async transferFromAsync( - tokenAddress: string, - receiverAddress: string, - senderAddress: string, - tokenId: BigNumber, - txOpts: TransactionOpts = {}, - ): Promise { - assert.isETHAddressHex('tokenAddress', tokenAddress); - assert.isETHAddressHex('receiverAddress', receiverAddress); - await assert.isSenderAddressAsync('senderAddress', senderAddress, this._web3Wrapper); - assert.doesConformToSchema('txOpts', txOpts, txOptsSchema); - const normalizedTokenAddress = tokenAddress.toLowerCase(); - const normalizedReceiverAddress = receiverAddress.toLowerCase(); - const normalizedSenderAddress = senderAddress.toLowerCase(); - const tokenContract = await this._getTokenContractAsync(normalizedTokenAddress); - const ownerAddress = await this.getOwnerOfAsync(tokenAddress, tokenId); - if (normalizedSenderAddress !== ownerAddress) { - const isApprovedForAll = await this.isApprovedForAllAsync( - normalizedTokenAddress, - ownerAddress, - normalizedSenderAddress, - ); - if (!isApprovedForAll) { - const approvedAddress = await this.getApprovedIfExistsAsync(normalizedTokenAddress, tokenId); - if (approvedAddress !== normalizedSenderAddress) { - throw new Error(ContractWrappersError.ERC721NoApproval); - } - } - } - const txHash = await tokenContract.transferFrom.sendTransactionAsync( - ownerAddress, - normalizedReceiverAddress, - tokenId, - utils.removeUndefinedProperties({ - gas: txOpts.gasLimit, - gasPrice: txOpts.gasPrice, - from: normalizedSenderAddress, - nonce: txOpts.nonce, - }), - ); - return txHash; - } - /** - * Subscribe to an event type emitted by the Token contract. - * @param tokenAddress The hex encoded address where the ERC721 token is deployed. - * @param eventName The token contract event you would like to subscribe to. - * @param indexFilterValues An object where the keys are indexed args returned by the event and - * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` - * @param callback Callback that gets called when a log is added/removed - * @param isVerbose Enable verbose subscription warnings (e.g recoverable network issues encountered) - * @return Subscription token used later to unsubscribe - */ - public subscribe( - tokenAddress: string, - eventName: ERC721TokenEvents, - indexFilterValues: IndexedFilterValues, - callback: EventCallback, - isVerbose: boolean = false, - ): string { - assert.isETHAddressHex('tokenAddress', tokenAddress); - assert.doesBelongToStringEnum('eventName', eventName, ERC721TokenEvents); - assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); - assert.isFunction('callback', callback); - const normalizedTokenAddress = tokenAddress.toLowerCase(); - const subscriptionToken = this._subscribe( - normalizedTokenAddress, - eventName, - indexFilterValues, - ERC721Token.compilerOutput.abi, - callback, - isVerbose, - ); - return subscriptionToken; - } - /** - * Cancel a subscription - * @param subscriptionToken Subscription token returned by `subscribe()` - */ - public unsubscribe(subscriptionToken: string): void { - assert.isValidSubscriptionToken('subscriptionToken', subscriptionToken); - this._unsubscribe(subscriptionToken); - } - /** - * Cancels all existing subscriptions - */ - public unsubscribeAll(): void { - super._unsubscribeAll(); - } - /** - * Gets historical logs without creating a subscription - * @param tokenAddress An address of the token that emitted the logs. - * @param eventName The token contract event you would like to subscribe to. - * @param blockRange Block range to get logs from. - * @param indexFilterValues An object where the keys are indexed args returned by the event and - * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` - * @return Array of logs that match the parameters - */ - public async getLogsAsync( - tokenAddress: string, - eventName: ERC721TokenEvents, - blockRange: BlockRange, - indexFilterValues: IndexedFilterValues, - ): Promise>> { - assert.isETHAddressHex('tokenAddress', tokenAddress); - assert.doesBelongToStringEnum('eventName', eventName, ERC721TokenEvents); - assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); - assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); - const normalizedTokenAddress = tokenAddress.toLowerCase(); - const logs = await this._getLogsAsync( - normalizedTokenAddress, - eventName, - blockRange, - indexFilterValues, - ERC721Token.compilerOutput.abi, - ); - return logs; - } - private async _getTokenContractAsync(tokenAddress: string): Promise { - const normalizedTokenAddress = tokenAddress.toLowerCase(); - let tokenContract = this._tokenContractsByAddress[normalizedTokenAddress]; - if (tokenContract !== undefined) { - return tokenContract; - } - const contractInstance = new ERC721TokenContract( - normalizedTokenAddress, - this._web3Wrapper.getProvider(), - this._web3Wrapper.getContractDefaults(), - ); - tokenContract = contractInstance; - this._tokenContractsByAddress[normalizedTokenAddress] = tokenContract; - return tokenContract; - } -} diff --git a/packages/contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts deleted file mode 100644 index b1805ecc87..0000000000 --- a/packages/contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts +++ /dev/null @@ -1,210 +0,0 @@ -import { WETH9Contract, WETH9EventArgs, WETH9Events } from '@0x/abi-gen-wrappers'; -import { WETH9 } from '@0x/contract-artifacts'; -import { schemas } from '@0x/json-schemas'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { ContractAbi, LogWithDecodedArgs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { BlockRange, ContractWrappersError, EventCallback, IndexedFilterValues, TransactionOpts } from '../types'; -import { assert } from '../utils/assert'; -import { utils } from '../utils/utils'; - -import { ContractWrapper } from './contract_wrapper'; -import { ERC20TokenWrapper } from './erc20_token_wrapper'; - -/** - * This class includes all the functionality related to interacting with a wrapped Ether ERC20 token contract. - * The caller can convert ETH into the equivalent number of wrapped ETH ERC20 tokens and back. - */ -export class EtherTokenWrapper extends ContractWrapper { - public abi: ContractAbi = WETH9.compilerOutput.abi; - private readonly _etherTokenContractsByAddress: { - [address: string]: WETH9Contract; - } = {}; - private readonly _erc20TokenWrapper: ERC20TokenWrapper; - /** - * Instantiate EtherTokenWrapper. - * @param web3Wrapper Web3Wrapper instance to use - * @param networkId Desired networkId - * @param erc20TokenWrapper The ERC20TokenWrapper instance to use - * @param blockPollingIntervalMs The block polling interval to use for active subscriptions - */ - constructor( - web3Wrapper: Web3Wrapper, - networkId: number, - erc20TokenWrapper: ERC20TokenWrapper, - blockPollingIntervalMs?: number, - ) { - super(web3Wrapper, networkId, blockPollingIntervalMs); - this._erc20TokenWrapper = erc20TokenWrapper; - } - /** - * Deposit ETH into the Wrapped ETH smart contract and issues the equivalent number of wrapped ETH tokens - * to the depositor address. These wrapped ETH tokens can be used in 0x trades and are redeemable for 1-to-1 - * for ETH. - * @param etherTokenAddress EtherToken address you wish to deposit into. - * @param amountInWei Amount of ETH in Wei the caller wishes to deposit. - * @param depositor The hex encoded user Ethereum address that would like to make the deposit. - * @param txOpts Transaction parameters. - * @return Transaction hash. - */ - public async depositAsync( - etherTokenAddress: string, - amountInWei: BigNumber, - depositor: string, - txOpts: TransactionOpts = {}, - ): Promise { - assert.isETHAddressHex('etherTokenAddress', etherTokenAddress); - assert.isValidBaseUnitAmount('amountInWei', amountInWei); - await assert.isSenderAddressAsync('depositor', depositor, this._web3Wrapper); - const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase(); - const normalizedDepositorAddress = depositor.toLowerCase(); - - const ethBalanceInWei = await this._web3Wrapper.getBalanceInWeiAsync(normalizedDepositorAddress); - assert.assert(ethBalanceInWei.gte(amountInWei), ContractWrappersError.InsufficientEthBalanceForDeposit); - - const wethContract = await this._getEtherTokenContractAsync(normalizedEtherTokenAddress); - const txHash = await wethContract.deposit.sendTransactionAsync( - utils.removeUndefinedProperties({ - from: normalizedDepositorAddress, - value: amountInWei, - gas: txOpts.gasLimit, - gasPrice: txOpts.gasPrice, - nonce: txOpts.nonce, - }), - ); - return txHash; - } - /** - * Withdraw ETH to the withdrawer's address from the wrapped ETH smart contract in exchange for the - * equivalent number of wrapped ETH tokens. - * @param etherTokenAddress EtherToken address you wish to withdraw from. - * @param amountInWei Amount of ETH in Wei the caller wishes to withdraw. - * @param withdrawer The hex encoded user Ethereum address that would like to make the withdrawal. - * @param txOpts Transaction parameters. - * @return Transaction hash. - */ - public async withdrawAsync( - etherTokenAddress: string, - amountInWei: BigNumber, - withdrawer: string, - txOpts: TransactionOpts = {}, - ): Promise { - assert.isValidBaseUnitAmount('amountInWei', amountInWei); - assert.isETHAddressHex('etherTokenAddress', etherTokenAddress); - await assert.isSenderAddressAsync('withdrawer', withdrawer, this._web3Wrapper); - const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase(); - const normalizedWithdrawerAddress = withdrawer.toLowerCase(); - - const WETHBalanceInBaseUnits = await this._erc20TokenWrapper.getBalanceAsync( - normalizedEtherTokenAddress, - normalizedWithdrawerAddress, - ); - assert.assert( - WETHBalanceInBaseUnits.gte(amountInWei), - ContractWrappersError.InsufficientWEthBalanceForWithdrawal, - ); - - const wethContract = await this._getEtherTokenContractAsync(normalizedEtherTokenAddress); - const txHash = await wethContract.withdraw.sendTransactionAsync( - amountInWei, - utils.removeUndefinedProperties({ - from: normalizedWithdrawerAddress, - gas: txOpts.gasLimit, - gasPrice: txOpts.gasPrice, - nonce: txOpts.nonce, - }), - ); - return txHash; - } - /** - * Gets historical logs without creating a subscription - * @param etherTokenAddress An address of the ether token that emitted the logs. - * @param eventName The ether token contract event you would like to subscribe to. - * @param blockRange Block range to get logs from. - * @param indexFilterValues An object where the keys are indexed args returned by the event and - * the value is the value you are interested in. E.g `{_owner: aUserAddressHex}` - * @return Array of logs that match the parameters - */ - public async getLogsAsync( - etherTokenAddress: string, - eventName: WETH9Events, - blockRange: BlockRange, - indexFilterValues: IndexedFilterValues, - ): Promise>> { - assert.isETHAddressHex('etherTokenAddress', etherTokenAddress); - const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase(); - assert.doesBelongToStringEnum('eventName', eventName, WETH9Events); - assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); - assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); - const logs = await this._getLogsAsync( - normalizedEtherTokenAddress, - eventName, - blockRange, - indexFilterValues, - WETH9.compilerOutput.abi, - ); - return logs; - } - /** - * Subscribe to an event type emitted by the Token contract. - * @param etherTokenAddress The hex encoded address where the ether token is deployed. - * @param eventName The ether token contract event you would like to subscribe to. - * @param indexFilterValues An object where the keys are indexed args returned by the event and - * the value is the value you are interested in. E.g `{_owner: aUserAddressHex}` - * @param callback Callback that gets called when a log is added/removed - * @param isVerbose Enable verbose subscription warnings (e.g recoverable network issues encountered) - * @return Subscription token used later to unsubscribe - */ - public subscribe( - etherTokenAddress: string, - eventName: WETH9Events, - indexFilterValues: IndexedFilterValues, - callback: EventCallback, - isVerbose: boolean = false, - ): string { - assert.isETHAddressHex('etherTokenAddress', etherTokenAddress); - const normalizedEtherTokenAddress = etherTokenAddress.toLowerCase(); - assert.doesBelongToStringEnum('eventName', eventName, WETH9Events); - assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); - assert.isFunction('callback', callback); - const subscriptionToken = this._subscribe( - normalizedEtherTokenAddress, - eventName, - indexFilterValues, - WETH9.compilerOutput.abi, - callback, - isVerbose, - ); - return subscriptionToken; - } - /** - * Cancel a subscription - * @param subscriptionToken Subscription token returned by `subscribe()` - */ - public unsubscribe(subscriptionToken: string): void { - assert.isValidSubscriptionToken('subscriptionToken', subscriptionToken); - this._unsubscribe(subscriptionToken); - } - /** - * Cancels all existing subscriptions - */ - public unsubscribeAll(): void { - super._unsubscribeAll(); - } - private async _getEtherTokenContractAsync(etherTokenAddress: string): Promise { - let etherTokenContract = this._etherTokenContractsByAddress[etherTokenAddress]; - if (etherTokenContract !== undefined) { - return etherTokenContract; - } - const contractInstance = new WETH9Contract( - etherTokenAddress, - this._web3Wrapper.getProvider(), - this._web3Wrapper.getContractDefaults(), - ); - etherTokenContract = contractInstance; - this._etherTokenContractsByAddress[etherTokenAddress] = etherTokenContract; - return etherTokenContract; - } -} diff --git a/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts deleted file mode 100644 index 6c647b9cf2..0000000000 --- a/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts +++ /dev/null @@ -1,1280 +0,0 @@ -import { ExchangeContract, ExchangeEventArgs, ExchangeEvents } from '@0x/abi-gen-wrappers'; -import { Exchange } from '@0x/contract-artifacts'; -import { schemas } from '@0x/json-schemas'; -import { - assetDataUtils, - BalanceAndProxyAllowanceLazyStore, - ExchangeTransferSimulator, - orderCalculationUtils, - orderHashUtils, - OrderStateUtils, - OrderValidationUtils, -} from '@0x/order-utils'; -import { AssetProxyId, Order, SignedOrder } from '@0x/types'; -import { BigNumber, providerUtils } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { BlockParamLiteral, ContractAbi, LogWithDecodedArgs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { AssetBalanceAndProxyAllowanceFetcher } from '../fetchers/asset_balance_and_proxy_allowance_fetcher'; -import { OrderFilledCancelledFetcher } from '../fetchers/order_filled_cancelled_fetcher'; -import { methodOptsSchema } from '../schemas/method_opts_schema'; -import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema'; -import { txOptsSchema } from '../schemas/tx_opts_schema'; -import { validateOrderFillableOptsSchema } from '../schemas/validate_order_fillable_opts_schema'; -import { - BlockRange, - EventCallback, - ExchangeWrapperError, - IndexedFilterValues, - MethodOpts, - OrderInfo, - OrderTransactionOpts, - ValidateOrderFillableOpts, -} from '../types'; -import { assert } from '../utils/assert'; -import { _getDefaultContractAddresses } from '../utils/contract_addresses'; -import { decorators } from '../utils/decorators'; -import { TransactionEncoder } from '../utils/transaction_encoder'; - -import { ContractWrapper } from './contract_wrapper'; -import { ERC20TokenWrapper } from './erc20_token_wrapper'; -import { ERC721TokenWrapper } from './erc721_token_wrapper'; - -/** - * This class includes all the functionality related to calling methods, sending transactions and subscribing to - * events of the 0x V2 Exchange smart contract. - */ -export class ExchangeWrapper extends ContractWrapper { - public abi: ContractAbi = Exchange.compilerOutput.abi; - public address: string; - public zrxTokenAddress: string; - private _exchangeContractIfExists?: ExchangeContract; - private readonly _erc721TokenWrapper: ERC721TokenWrapper; - private readonly _erc20TokenWrapper: ERC20TokenWrapper; - /** - * Instantiate ExchangeWrapper - * @param web3Wrapper Web3Wrapper instance to use. - * @param networkId Desired networkId. - * @param erc20TokenWrapper ERC20TokenWrapper instance to use. - * @param erc721TokenWrapper ERC721TokenWrapper instance to use. - * @param address The address of the Exchange contract. If undefined, will - * default to the known address corresponding to the networkId. - * @param zrxTokenAddress The address of the ZRXToken contract. If - * undefined, will default to the known address corresponding to the - * networkId. - * @param blockPollingIntervalMs The block polling interval to use for active subscriptions. - */ - constructor( - web3Wrapper: Web3Wrapper, - networkId: number, - erc20TokenWrapper: ERC20TokenWrapper, - erc721TokenWrapper: ERC721TokenWrapper, - address?: string, - zrxTokenAddress?: string, - blockPollingIntervalMs?: number, - ) { - super(web3Wrapper, networkId, blockPollingIntervalMs); - this._erc20TokenWrapper = erc20TokenWrapper; - this._erc721TokenWrapper = erc721TokenWrapper; - this.address = address === undefined ? _getDefaultContractAddresses(networkId).exchange : address; - this.zrxTokenAddress = - zrxTokenAddress === undefined ? _getDefaultContractAddresses(networkId).zrxToken : zrxTokenAddress; - } - /** - * Retrieve the address of an asset proxy by signature. - * @param proxyId The 4 bytes signature of an asset proxy - * @param methodOpts Optional arguments this method accepts. - * @return The address of an asset proxy for a given signature - */ - public async getAssetProxyBySignatureAsync(proxyId: AssetProxyId, methodOpts: MethodOpts = {}): Promise { - assert.doesBelongToStringEnum('proxyId', proxyId, AssetProxyId); - assert.doesConformToSchema('methodOpts', methodOpts, methodOptsSchema); - const exchangeContract = await this._getExchangeContractAsync(); - - const callData = {}; - const assetProxy = await exchangeContract.getAssetProxy.callAsync(proxyId, callData, methodOpts.defaultBlock); - return assetProxy; - } - /** - * Retrieve the takerAssetAmount of an order that has already been filled. - * @param orderHash The hex encoded orderHash for which you would like to retrieve the filled takerAssetAmount. - * @param methodOpts Optional arguments this method accepts. - * @return The amount of the order (in taker asset base units) that has already been filled. - */ - public async getFilledTakerAssetAmountAsync(orderHash: string, methodOpts: MethodOpts = {}): Promise { - assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema); - assert.doesConformToSchema('methodOpts', methodOpts, methodOptsSchema); - const exchangeContract = await this._getExchangeContractAsync(); - - const callData = {}; - const filledTakerAssetAmountInBaseUnits = await exchangeContract.filled.callAsync( - orderHash, - callData, - methodOpts.defaultBlock, - ); - return filledTakerAssetAmountInBaseUnits; - } - /** - * Retrieve the exchange contract version - * @param methodOpts Optional arguments this method accepts. - * @return Version - */ - public async getVersionAsync(methodOpts: MethodOpts = {}): Promise { - assert.doesConformToSchema('methodOpts', methodOpts, methodOptsSchema); - const exchangeContract = await this._getExchangeContractAsync(); - - const callData = {}; - const version = await exchangeContract.VERSION.callAsync(callData, methodOpts.defaultBlock); - return version; - } - /** - * Retrieve the set order epoch for a given makerAddress & senderAddress pair. - * Orders can be bulk cancelled by setting the order epoch to a value lower then the salt value of orders one wishes to cancel. - * @param makerAddress Maker address - * @param senderAddress Sender address - * @param methodOpts Optional arguments this method accepts. - * @return Order epoch. Defaults to 0. - */ - public async getOrderEpochAsync( - makerAddress: string, - senderAddress: string, - methodOpts: MethodOpts = {}, - ): Promise { - assert.isETHAddressHex('makerAddress', makerAddress); - assert.isETHAddressHex('senderAddress', senderAddress); - assert.doesConformToSchema('methodOpts', methodOpts, methodOptsSchema); - const exchangeContract = await this._getExchangeContractAsync(); - - const callData = {}; - const orderEpoch = await exchangeContract.orderEpoch.callAsync( - makerAddress, - senderAddress, - callData, - methodOpts.defaultBlock, - ); - return orderEpoch; - } - /** - * Check if an order has been cancelled. Order cancellations are binary - * @param orderHash The hex encoded orderHash for which you would like to retrieve the cancelled takerAmount. - * @param methodOpts Optional arguments this method accepts. - * @return Whether the order has been cancelled. - */ - public async isCancelledAsync(orderHash: string, methodOpts: MethodOpts = {}): Promise { - assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema); - assert.doesConformToSchema('methodOpts', methodOpts, methodOptsSchema); - const exchangeContract = await this._getExchangeContractAsync(); - - const callData = {}; - const isCancelled = await exchangeContract.cancelled.callAsync(orderHash, callData, methodOpts.defaultBlock); - return isCancelled; - } - /** - * Fills a signed order with an amount denominated in baseUnits of the taker asset. - * @param signedOrder An object that conforms to the SignedOrder interface. - * @param takerAssetFillAmount The amount of the order (in taker asset baseUnits) that you wish to fill. - * @param takerAddress The user Ethereum address who would like to fill this order. Must be available via the supplied - * Provider provided at instantiation. - * @param orderTransactionOpts Optional arguments this method accepts. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async fillOrderAsync( - signedOrder: SignedOrder, - takerAssetFillAmount: BigNumber, - takerAddress: string, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); - assert.isValidBaseUnitAmount('takerAssetFillAmount', takerAssetFillAmount); - await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - const normalizedTakerAddress = takerAddress.toLowerCase(); - - const exchangeInstance = await this._getExchangeContractAsync(); - if (orderTransactionOpts.shouldValidate) { - await exchangeInstance.fillOrder.callAsync(signedOrder, takerAssetFillAmount, signedOrder.signature, { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }); - } - - const txHash = await exchangeInstance.fillOrder.sendTransactionAsync( - signedOrder, - takerAssetFillAmount, - signedOrder.signature, - { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - return txHash; - } - /** - * No-throw version of fillOrderAsync. This version will not throw if the fill fails. This allows the caller to save gas at the expense of not knowing the reason the fill failed. - * @param signedOrder An object that conforms to the SignedOrder interface. - * @param takerAssetFillAmount The amount of the order (in taker asset baseUnits) that you wish to fill. - * @param takerAddress The user Ethereum address who would like to fill this order. - * Must be available via the supplied Provider provided at instantiation. - * @param orderTransactionOpts Optional arguments this method accepts. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async fillOrderNoThrowAsync( - signedOrder: SignedOrder, - takerAssetFillAmount: BigNumber, - takerAddress: string, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); - assert.isValidBaseUnitAmount('takerAssetFillAmount', takerAssetFillAmount); - await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - const normalizedTakerAddress = takerAddress.toLowerCase(); - - const exchangeInstance = await this._getExchangeContractAsync(); - if (orderTransactionOpts.shouldValidate) { - await exchangeInstance.fillOrderNoThrow.callAsync( - signedOrder, - takerAssetFillAmount, - signedOrder.signature, - { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - } - const txHash = await exchangeInstance.fillOrderNoThrow.sendTransactionAsync( - signedOrder, - takerAssetFillAmount, - signedOrder.signature, - { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - return txHash; - } - /** - * Attempts to fill a specific amount of an order. If the entire amount specified cannot be filled, - * the fill order is abandoned. - * @param signedOrder An object that conforms to the SignedOrder interface. - * @param takerAssetFillAmount The amount of the order (in taker asset baseUnits) that you wish to fill. - * @param takerAddress The user Ethereum address who would like to fill this order. Must be available via the supplied - * Provider provided at instantiation. - * @param orderTransactionOpts Optional arguments this method accepts. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async fillOrKillOrderAsync( - signedOrder: SignedOrder, - takerAssetFillAmount: BigNumber, - takerAddress: string, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); - assert.isValidBaseUnitAmount('takerAssetFillAmount', takerAssetFillAmount); - await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - const normalizedTakerAddress = takerAddress.toLowerCase(); - - const exchangeInstance = await this._getExchangeContractAsync(); - if (orderTransactionOpts.shouldValidate) { - await exchangeInstance.fillOrKillOrder.callAsync(signedOrder, takerAssetFillAmount, signedOrder.signature, { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }); - } - const txHash = await exchangeInstance.fillOrKillOrder.sendTransactionAsync( - signedOrder, - takerAssetFillAmount, - signedOrder.signature, - { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - return txHash; - } - /** - * Executes a 0x transaction. Transaction messages exist for the purpose of calling methods on the Exchange contract - * in the context of another address (see [ZEIP18](https://github.com/0xProject/ZEIPs/issues/18)). - * This is especially useful for implementing filter contracts. - * @param salt Salt - * @param signerAddress Signer address - * @param data Transaction data - * @param signature Signature - * @param senderAddress Sender address - * @param orderTransactionOpts Optional arguments this method accepts. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async executeTransactionAsync( - salt: BigNumber, - signerAddress: string, - data: string, - signature: string, - senderAddress: string, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.isBigNumber('salt', salt); - assert.isETHAddressHex('signerAddress', signerAddress); - assert.isHexString('data', data); - assert.isHexString('signature', signature); - await assert.isSenderAddressAsync('senderAddress', senderAddress, this._web3Wrapper); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - const normalizedSenderAddress = senderAddress.toLowerCase(); - - const exchangeInstance = await this._getExchangeContractAsync(); - if (orderTransactionOpts.shouldValidate) { - await exchangeInstance.executeTransaction.callAsync(salt, signerAddress, data, signature, { - from: normalizedSenderAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }); - } - const txHash = await exchangeInstance.executeTransaction.sendTransactionAsync( - salt, - signerAddress, - data, - signature, - { - from: normalizedSenderAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - return txHash; - } - /** - * Batch version of fillOrderAsync. Executes multiple fills atomically in a single transaction. - * @param signedOrders An array of signed orders to fill. - * @param takerAssetFillAmounts The amounts of the orders (in taker asset baseUnits) that you wish to fill. - * @param takerAddress The user Ethereum address who would like to fill these orders. Must be available via the supplied - * Provider provided at instantiation. - * @param orderTransactionOpts Optional arguments this method accepts. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async batchFillOrdersAsync( - signedOrders: SignedOrder[], - takerAssetFillAmounts: BigNumber[], - takerAddress: string, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); - _.forEach(takerAssetFillAmounts, takerAssetFillAmount => - assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount), - ); - await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - const normalizedTakerAddress = takerAddress.toLowerCase(); - - const exchangeInstance = await this._getExchangeContractAsync(); - const signatures = _.map(signedOrders, signedOrder => signedOrder.signature); - if (orderTransactionOpts.shouldValidate) { - await exchangeInstance.batchFillOrders.callAsync(signedOrders, takerAssetFillAmounts, signatures, { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }); - } - const txHash = await exchangeInstance.batchFillOrders.sendTransactionAsync( - signedOrders, - takerAssetFillAmounts, - signatures, - { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - return txHash; - } - /** - * Synchronously executes multiple calls to fillOrder until total amount of makerAsset is bought by taker. - * @param signedOrders An array of signed orders to fill. - * @param makerAssetFillAmount Maker asset fill amount. - * @param takerAddress The user Ethereum address who would like to fill these orders. Must be available via the supplied - * Provider provided at instantiation. - * @param orderTransactionOpts Optional arguments this method accepts. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async marketBuyOrdersAsync( - signedOrders: SignedOrder[], - makerAssetFillAmount: BigNumber, - takerAddress: string, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); - assert.isBigNumber('makerAssetFillAmount', makerAssetFillAmount); - await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - const normalizedTakerAddress = takerAddress.toLowerCase(); - - const exchangeInstance = await this._getExchangeContractAsync(); - const signatures = _.map(signedOrders, signedOrder => signedOrder.signature); - if (orderTransactionOpts.shouldValidate) { - await exchangeInstance.marketBuyOrders.callAsync(signedOrders, makerAssetFillAmount, signatures, { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }); - } - const txHash = await exchangeInstance.marketBuyOrders.sendTransactionAsync( - signedOrders, - makerAssetFillAmount, - signatures, - { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - return txHash; - } - /** - * Synchronously executes multiple calls to fillOrder until total amount of makerAsset is bought by taker. - * @param signedOrders An array of signed orders to fill. - * @param takerAssetFillAmount Taker asset fill amount. - * @param takerAddress The user Ethereum address who would like to fill these orders. Must be available via the supplied - * Provider provided at instantiation. - * @param orderTransactionOpts Optional arguments this method accepts. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async marketSellOrdersAsync( - signedOrders: SignedOrder[], - takerAssetFillAmount: BigNumber, - takerAddress: string, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); - assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount); - await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - const normalizedTakerAddress = takerAddress.toLowerCase(); - - const exchangeInstance = await this._getExchangeContractAsync(); - const signatures = _.map(signedOrders, signedOrder => signedOrder.signature); - if (orderTransactionOpts.shouldValidate) { - await exchangeInstance.marketSellOrders.callAsync(signedOrders, takerAssetFillAmount, signatures, { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }); - } - const txHash = await exchangeInstance.marketSellOrders.sendTransactionAsync( - signedOrders, - takerAssetFillAmount, - signatures, - { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - return txHash; - } - /** - * No throw version of marketBuyOrdersAsync - * @param signedOrders An array of signed orders to fill. - * @param makerAssetFillAmount Maker asset fill amount. - * @param takerAddress The user Ethereum address who would like to fill these orders. Must be available via the supplied - * Provider provided at instantiation. - * @param orderTransactionOpts Optional arguments this method accepts. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async marketBuyOrdersNoThrowAsync( - signedOrders: SignedOrder[], - makerAssetFillAmount: BigNumber, - takerAddress: string, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); - assert.isBigNumber('makerAssetFillAmount', makerAssetFillAmount); - await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - const normalizedTakerAddress = takerAddress.toLowerCase(); - - const exchangeInstance = await this._getExchangeContractAsync(); - const signatures = _.map(signedOrders, signedOrder => signedOrder.signature); - if (orderTransactionOpts.shouldValidate) { - await exchangeInstance.marketBuyOrdersNoThrow.callAsync(signedOrders, makerAssetFillAmount, signatures, { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }); - } - const txHash = await exchangeInstance.marketBuyOrdersNoThrow.sendTransactionAsync( - signedOrders, - makerAssetFillAmount, - signatures, - { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - return txHash; - } - /** - * No throw version of marketSellOrdersAsync - * @param signedOrders An array of signed orders to fill. - * @param takerAssetFillAmount Taker asset fill amount. - * @param takerAddress The user Ethereum address who would like to fill these orders. Must be available via the supplied - * Provider provided at instantiation. - * @param orderTransactionOpts Optional arguments this method accepts. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async marketSellOrdersNoThrowAsync( - signedOrders: SignedOrder[], - takerAssetFillAmount: BigNumber, - takerAddress: string, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); - assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount); - await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - const normalizedTakerAddress = takerAddress.toLowerCase(); - - const exchangeInstance = await this._getExchangeContractAsync(); - const signatures = _.map(signedOrders, signedOrder => signedOrder.signature); - if (orderTransactionOpts.shouldValidate) { - await exchangeInstance.marketSellOrdersNoThrow.callAsync(signedOrders, takerAssetFillAmount, signatures, { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }); - } - const txHash = await exchangeInstance.marketSellOrdersNoThrow.sendTransactionAsync( - signedOrders, - takerAssetFillAmount, - signatures, - { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - return txHash; - } - /** - * No throw version of batchFillOrdersAsync - * @param signedOrders An array of signed orders to fill. - * @param takerAssetFillAmounts The amounts of the orders (in taker asset baseUnits) that you wish to fill. - * @param takerAddress The user Ethereum address who would like to fill these orders. Must be available via the supplied - * Provider provided at instantiation. - * @param orderTransactionOpts Optional arguments this method accepts. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async batchFillOrdersNoThrowAsync( - signedOrders: SignedOrder[], - takerAssetFillAmounts: BigNumber[], - takerAddress: string, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); - _.forEach(takerAssetFillAmounts, takerAssetFillAmount => - assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount), - ); - await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - const normalizedTakerAddress = takerAddress.toLowerCase(); - - const exchangeInstance = await this._getExchangeContractAsync(); - const signatures = _.map(signedOrders, signedOrder => signedOrder.signature); - if (orderTransactionOpts.shouldValidate) { - await exchangeInstance.batchFillOrdersNoThrow.callAsync(signedOrders, takerAssetFillAmounts, signatures, { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }); - } - const txHash = await exchangeInstance.batchFillOrdersNoThrow.sendTransactionAsync( - signedOrders, - takerAssetFillAmounts, - signatures, - { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - return txHash; - } - /** - * Batch version of fillOrKillOrderAsync. Executes multiple fills atomically in a single transaction. - * @param signedOrders An array of signed orders to fill. - * @param takerAssetFillAmounts The amounts of the orders (in taker asset baseUnits) that you wish to fill. - * @param takerAddress The user Ethereum address who would like to fill these orders. Must be available via the supplied - * Provider provided at instantiation. - * @param orderTransactionOpts Optional arguments this method accepts. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async batchFillOrKillOrdersAsync( - signedOrders: SignedOrder[], - takerAssetFillAmounts: BigNumber[], - takerAddress: string, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); - _.forEach(takerAssetFillAmounts, takerAssetFillAmount => - assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount), - ); - await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - const normalizedTakerAddress = takerAddress.toLowerCase(); - - const exchangeInstance = await this._getExchangeContractAsync(); - const signatures = _.map(signedOrders, signedOrder => signedOrder.signature); - if (orderTransactionOpts.shouldValidate) { - await exchangeInstance.batchFillOrKillOrders.callAsync(signedOrders, takerAssetFillAmounts, signatures, { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }); - } - const txHash = await exchangeInstance.batchFillOrKillOrders.sendTransactionAsync( - signedOrders, - takerAssetFillAmounts, - signatures, - { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - return txHash; - } - /** - * Batch version of cancelOrderAsync. Executes multiple cancels atomically in a single transaction. - * @param orders An array of orders to cancel. - * @param orderTransactionOpts Optional arguments this method accepts. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async batchCancelOrdersAsync( - orders: Array, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.doesConformToSchema('orders', orders, schemas.ordersSchema); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - const makerAddresses = _.map(orders, order => order.makerAddress); - const makerAddress = makerAddresses[0]; - await assert.isSenderAddressAsync('makerAddress', makerAddress, this._web3Wrapper); - const normalizedMakerAddress = makerAddress.toLowerCase(); - - const exchangeInstance = await this._getExchangeContractAsync(); - if (orderTransactionOpts.shouldValidate) { - await exchangeInstance.batchCancelOrders.callAsync(orders, { - from: normalizedMakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }); - } - const txHash = await exchangeInstance.batchCancelOrders.sendTransactionAsync(orders, { - from: normalizedMakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }); - return txHash; - } - /** - * Match two complementary orders that have a profitable spread. - * Each order is filled at their respective price point. However, the calculations are carried out as though - * the orders are both being filled at the right order's price point. - * The profit made by the left order goes to the taker (whoever matched the two orders). - * @param leftSignedOrder First order to match. - * @param rightSignedOrder Second order to match. - * @param takerAddress The address that sends the transaction and gets the spread. - * @param orderTransactionOpts Optional arguments this method accepts. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async matchOrdersAsync( - leftSignedOrder: SignedOrder, - rightSignedOrder: SignedOrder, - takerAddress: string, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.doesConformToSchema('leftSignedOrder', leftSignedOrder, schemas.signedOrderSchema); - assert.doesConformToSchema('rightSignedOrder', rightSignedOrder, schemas.signedOrderSchema); - await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - const normalizedTakerAddress = takerAddress.toLowerCase(); - if ( - rightSignedOrder.makerAssetData !== leftSignedOrder.takerAssetData || - rightSignedOrder.takerAssetData !== leftSignedOrder.makerAssetData - ) { - throw new Error(ExchangeWrapperError.AssetDataMismatch); - } - const exchangeInstance = await this._getExchangeContractAsync(); - if (orderTransactionOpts.shouldValidate) { - await exchangeInstance.matchOrders.callAsync( - leftSignedOrder, - rightSignedOrder, - leftSignedOrder.signature, - rightSignedOrder.signature, - { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - } - const txHash = await exchangeInstance.matchOrders.sendTransactionAsync( - leftSignedOrder, - rightSignedOrder, - leftSignedOrder.signature, - rightSignedOrder.signature, - { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - return txHash; - } - /** - * Approves a hash on-chain using any valid signature type. - * After presigning a hash, the preSign signature type will become valid for that hash and signer. - * @param hash Hash to pre-sign - * @param signerAddress Address that should have signed the given hash. - * @param signature Proof that the hash has been signed by signer. - * @param senderAddress Address that should send the transaction. - * @param orderTransactionOpts Optional arguments this method accepts. - * @returns Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async preSignAsync( - hash: string, - signerAddress: string, - signature: string, - senderAddress: string, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.isHexString('hash', hash); - assert.isETHAddressHex('signerAddress', signerAddress); - assert.isHexString('signature', signature); - await assert.isSenderAddressAsync('senderAddress', senderAddress, this._web3Wrapper); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - const normalizedTakerAddress = senderAddress.toLowerCase(); - const exchangeInstance = await this._getExchangeContractAsync(); - if (orderTransactionOpts.shouldValidate) { - await exchangeInstance.preSign.callAsync(hash, signerAddress, signature, { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }); - } - const txHash = await exchangeInstance.preSign.sendTransactionAsync(hash, signerAddress, signature, { - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }); - return txHash; - } - /** - * Checks if the signature is valid. - * @param hash Hash to pre-sign - * @param signerAddress Address that should have signed the given hash. - * @param signature Proof that the hash has been signed by signer. - * @param methodOpts Optional arguments this method accepts. - * @returns If the signature is valid - */ - @decorators.asyncZeroExErrorHandler - public async isValidSignatureAsync( - hash: string, - signerAddress: string, - signature: string, - methodOpts: MethodOpts = {}, - ): Promise { - assert.isHexString('hash', hash); - assert.isETHAddressHex('signerAddress', signerAddress); - assert.isHexString('signature', signature); - assert.doesConformToSchema('methodOpts', methodOpts, methodOptsSchema); - const exchangeInstance = await this._getExchangeContractAsync(); - const callData = {}; - const isValidSignature = await exchangeInstance.isValidSignature.callAsync( - hash, - signerAddress, - signature, - callData, - methodOpts.defaultBlock, - ); - return isValidSignature; - } - /** - * Checks if the validator is allowed by the signer. - * @param validatorAddress Address of a validator - * @param signerAddress Address of a signer - * @param methodOpts Optional arguments this method accepts. - * @returns If the validator is allowed - */ - @decorators.asyncZeroExErrorHandler - public async isAllowedValidatorAsync( - signerAddress: string, - validatorAddress: string, - methodOpts: MethodOpts = {}, - ): Promise { - assert.isETHAddressHex('signerAddress', signerAddress); - assert.isETHAddressHex('validatorAddress', validatorAddress); - if (methodOpts !== undefined) { - assert.doesConformToSchema('methodOpts', methodOpts, methodOptsSchema); - } - const normalizedSignerAddress = signerAddress.toLowerCase(); - const normalizedValidatorAddress = validatorAddress.toLowerCase(); - const exchangeInstance = await this._getExchangeContractAsync(); - const callData = {}; - const isValidSignature = await exchangeInstance.allowedValidators.callAsync( - normalizedSignerAddress, - normalizedValidatorAddress, - callData, - methodOpts.defaultBlock, - ); - return isValidSignature; - } - /** - * Check whether the hash is pre-signed on-chain. - * @param hash Hash to check if pre-signed - * @param signerAddress Address that should have signed the given hash. - * @param methodOpts Optional arguments this method accepts. - * @returns Whether the hash is pre-signed. - */ - @decorators.asyncZeroExErrorHandler - public async isPreSignedAsync(hash: string, signerAddress: string, methodOpts: MethodOpts = {}): Promise { - assert.isHexString('hash', hash); - assert.isETHAddressHex('signerAddress', signerAddress); - if (methodOpts !== undefined) { - assert.doesConformToSchema('methodOpts', methodOpts, methodOptsSchema); - } - const exchangeInstance = await this._getExchangeContractAsync(); - - const callData = {}; - const isPreSigned = await exchangeInstance.preSigned.callAsync( - hash, - signerAddress, - callData, - methodOpts.defaultBlock, - ); - return isPreSigned; - } - /** - * Checks if transaction is already executed. - * @param transactionHash Transaction hash to check - * @param signerAddress Address that should have signed the given hash. - * @param methodOpts Optional arguments this method accepts. - * @returns If transaction is already executed. - */ - @decorators.asyncZeroExErrorHandler - public async isTransactionExecutedAsync(transactionHash: string, methodOpts: MethodOpts = {}): Promise { - assert.isHexString('transactionHash', transactionHash); - if (methodOpts !== undefined) { - assert.doesConformToSchema('methodOpts', methodOpts, methodOptsSchema); - } - const exchangeInstance = await this._getExchangeContractAsync(); - const callData = {}; - const isExecuted = await exchangeInstance.transactions.callAsync( - transactionHash, - callData, - methodOpts.defaultBlock, - ); - return isExecuted; - } - /** - * Get order info - * @param order Order - * @param methodOpts Optional arguments this method accepts. - * @returns Order info - */ - @decorators.asyncZeroExErrorHandler - public async getOrderInfoAsync(order: Order | SignedOrder, methodOpts: MethodOpts = {}): Promise { - assert.doesConformToSchema('order', order, schemas.orderSchema); - if (methodOpts !== undefined) { - assert.doesConformToSchema('methodOpts', methodOpts, methodOptsSchema); - } - const exchangeInstance = await this._getExchangeContractAsync(); - const callData = {}; - const orderInfo = await exchangeInstance.getOrderInfo.callAsync(order, callData, methodOpts.defaultBlock); - return orderInfo; - } - /** - * Get order info for multiple orders - * @param orders Orders - * @param methodOpts Optional arguments this method accepts. - * @returns Array of Order infos - */ - @decorators.asyncZeroExErrorHandler - public async getOrdersInfoAsync( - orders: Array, - methodOpts: MethodOpts = {}, - ): Promise { - assert.doesConformToSchema('orders', orders, schemas.ordersSchema); - if (methodOpts !== undefined) { - assert.doesConformToSchema('methodOpts', methodOpts, methodOptsSchema); - } - const exchangeInstance = await this._getExchangeContractAsync(); - const callData = {}; - const ordersInfo = await exchangeInstance.getOrdersInfo.callAsync(orders, callData, methodOpts.defaultBlock); - return ordersInfo; - } - /** - * Cancel a given order. - * @param order An object that conforms to the Order or SignedOrder interface. The order you would like to cancel. - * @param orderTransactionOpts Optional arguments this method accepts. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async cancelOrderAsync( - order: Order | SignedOrder, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.doesConformToSchema('order', order, schemas.orderSchema); - await assert.isSenderAddressAsync('order.maker', order.makerAddress, this._web3Wrapper); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - const normalizedMakerAddress = order.makerAddress.toLowerCase(); - - const exchangeInstance = await this._getExchangeContractAsync(); - if (orderTransactionOpts.shouldValidate) { - await exchangeInstance.cancelOrder.callAsync(order, { - from: normalizedMakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }); - } - const txHash = await exchangeInstance.cancelOrder.sendTransactionAsync(order, { - from: normalizedMakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }); - return txHash; - } - /** - * Sets the signature validator approval - * @param validatorAddress Validator contract address. - * @param isApproved Boolean value to set approval to. - * @param senderAddress Sender address. - * @param orderTransactionOpts Optional arguments this method accepts. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async setSignatureValidatorApprovalAsync( - validatorAddress: string, - isApproved: boolean, - senderAddress: string, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.isETHAddressHex('validatorAddress', validatorAddress); - assert.isBoolean('isApproved', isApproved); - await assert.isSenderAddressAsync('senderAddress', senderAddress, this._web3Wrapper); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - const normalizedSenderAddress = senderAddress.toLowerCase(); - - const exchangeInstance = await this._getExchangeContractAsync(); - if (orderTransactionOpts.shouldValidate) { - await exchangeInstance.setSignatureValidatorApproval.callAsync(validatorAddress, isApproved, { - from: normalizedSenderAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }); - } - const txHash = await exchangeInstance.setSignatureValidatorApproval.sendTransactionAsync( - validatorAddress, - isApproved, - { - from: normalizedSenderAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - return txHash; - } - /** - * Cancels all orders created by makerAddress with a salt less than or equal to the targetOrderEpoch - * and senderAddress equal to msg.sender (or null address if msg.sender == makerAddress). - * @param targetOrderEpoch Target order epoch. - * @param senderAddress Address that should send the transaction. - * @param orderTransactionOpts Optional arguments this method accepts. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async cancelOrdersUpToAsync( - targetOrderEpoch: BigNumber, - senderAddress: string, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - assert.isBigNumber('targetOrderEpoch', targetOrderEpoch); - await assert.isSenderAddressAsync('senderAddress', senderAddress, this._web3Wrapper); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - const normalizedSenderAddress = senderAddress.toLowerCase(); - - const exchangeInstance = await this._getExchangeContractAsync(); - if (orderTransactionOpts.shouldValidate) { - await exchangeInstance.cancelOrdersUpTo.callAsync(targetOrderEpoch, { - from: normalizedSenderAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }); - } - const txHash = await exchangeInstance.cancelOrdersUpTo.sendTransactionAsync(targetOrderEpoch, { - from: normalizedSenderAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }); - return txHash; - } - /** - * Subscribe to an event type emitted by the Exchange contract. - * @param eventName The exchange contract event you would like to subscribe to. - * @param indexFilterValues An object where the keys are indexed args returned by the event and - * the value is the value you are interested in. E.g `{maker: aUserAddressHex}` - * @param callback Callback that gets called when a log is added/removed - * @param isVerbose Enable verbose subscription warnings (e.g recoverable network issues encountered) - * @return Subscription token used later to unsubscribe - */ - public subscribe( - eventName: ExchangeEvents, - indexFilterValues: IndexedFilterValues, - callback: EventCallback, - isVerbose: boolean = false, - ): string { - assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents); - assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); - assert.isFunction('callback', callback); - const subscriptionToken = this._subscribe( - this.address, - eventName, - indexFilterValues, - Exchange.compilerOutput.abi, - callback, - isVerbose, - ); - return subscriptionToken; - } - /** - * Cancel a subscription - * @param subscriptionToken Subscription token returned by `subscribe()` - */ - public unsubscribe(subscriptionToken: string): void { - this._unsubscribe(subscriptionToken); - } - /** - * Cancels all existing subscriptions - */ - public unsubscribeAll(): void { - super._unsubscribeAll(); - } - /** - * Gets historical logs without creating a subscription - * @param eventName The exchange contract event you would like to subscribe to. - * @param blockRange Block range to get logs from. - * @param indexFilterValues An object where the keys are indexed args returned by the event and - * the value is the value you are interested in. E.g `{_from: aUserAddressHex}` - * @return Array of logs that match the parameters - */ - public async getLogsAsync( - eventName: ExchangeEvents, - blockRange: BlockRange, - indexFilterValues: IndexedFilterValues, - ): Promise>> { - assert.doesBelongToStringEnum('eventName', eventName, ExchangeEvents); - assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema); - assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema); - const logs = await this._getLogsAsync( - this.address, - eventName, - blockRange, - indexFilterValues, - Exchange.compilerOutput.abi, - ); - return logs; - } - /** - * Validate if the supplied order is fillable, and throw if it isn't - * @param signedOrder SignedOrder of interest - * @param opts ValidateOrderFillableOpts options (e.g expectedFillTakerTokenAmount. - * If it isn't supplied, we check if the order is fillable for the remaining amount. - * To check if the order is fillable for a non-zero amount, set `validateRemainingOrderAmountIsFillable` to false.) - */ - public async validateOrderFillableOrThrowAsync( - signedOrder: SignedOrder, - opts: ValidateOrderFillableOpts = {}, - ): Promise { - assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); - assert.doesConformToSchema('opts', opts, validateOrderFillableOptsSchema); - - const balanceAllowanceFetcher = new AssetBalanceAndProxyAllowanceFetcher( - this._erc20TokenWrapper, - this._erc721TokenWrapper, - BlockParamLiteral.Latest, - ); - const balanceAllowanceStore = new BalanceAndProxyAllowanceLazyStore(balanceAllowanceFetcher); - const exchangeTradeSimulator = new ExchangeTransferSimulator(balanceAllowanceStore); - const filledCancelledFetcher = new OrderFilledCancelledFetcher(this, BlockParamLiteral.Latest); - - let fillableTakerAssetAmount; - const shouldValidateRemainingOrderAmountIsFillable = - opts.validateRemainingOrderAmountIsFillable === undefined - ? true - : opts.validateRemainingOrderAmountIsFillable; - if (opts.expectedFillTakerTokenAmount) { - // If the caller has specified a taker fill amount, we use this for all validation - fillableTakerAssetAmount = opts.expectedFillTakerTokenAmount; - } else if (shouldValidateRemainingOrderAmountIsFillable) { - // Default behaviour is to validate the amount left on the order. - const filledTakerTokenAmount = await this.getFilledTakerAssetAmountAsync( - orderHashUtils.getOrderHashHex(signedOrder), - ); - fillableTakerAssetAmount = signedOrder.takerAssetAmount.minus(filledTakerTokenAmount); - } else { - const orderStateUtils = new OrderStateUtils(balanceAllowanceStore, filledCancelledFetcher); - // Calculate the taker amount fillable given the maker balance and allowance - const orderRelevantState = await orderStateUtils.getOpenOrderRelevantStateAsync(signedOrder); - fillableTakerAssetAmount = orderRelevantState.remainingFillableTakerAssetAmount; - } - - const orderValidationUtils = new OrderValidationUtils(filledCancelledFetcher, this._web3Wrapper.getProvider()); - await orderValidationUtils.validateOrderFillableOrThrowAsync( - exchangeTradeSimulator, - signedOrder, - this.getZRXAssetData(), - fillableTakerAssetAmount, - ); - const makerTransferAmount = orderCalculationUtils.getMakerFillAmount(signedOrder, fillableTakerAssetAmount); - await this.validateMakerTransferThrowIfInvalidAsync( - signedOrder, - makerTransferAmount, - opts.simulationTakerAddress, - ); - } - /** - * Validate the transfer from the maker to the taker. This is simulated on-chain - * via an eth_call. If this call fails, the asset is currently nontransferable. - * @param signedOrder SignedOrder of interest - * @param makerAssetAmount Amount to transfer from the maker - * @param takerAddress The address to transfer to, defaults to signedOrder.takerAddress - */ - public async validateMakerTransferThrowIfInvalidAsync( - signedOrder: SignedOrder, - makerAssetAmount: BigNumber, - takerAddress?: string, - ): Promise { - const networkId = await this._web3Wrapper.getNetworkIdAsync(); - await OrderValidationUtils.validateMakerTransferThrowIfInvalidAsync( - networkId, - this._web3Wrapper.getProvider(), - signedOrder, - makerAssetAmount, - takerAddress, - ); - } - /** - * Validate a call to FillOrder and throw if it wouldn't succeed - * @param signedOrder SignedOrder of interest - * @param fillTakerAssetAmount Amount we'd like to fill the order for - * @param takerAddress The taker of the order - */ - public async validateFillOrderThrowIfInvalidAsync( - signedOrder: SignedOrder, - fillTakerAssetAmount: BigNumber, - takerAddress: string, - ): Promise { - const balanceAllowanceFetcher = new AssetBalanceAndProxyAllowanceFetcher( - this._erc20TokenWrapper, - this._erc721TokenWrapper, - BlockParamLiteral.Latest, - ); - const balanceAllowanceStore = new BalanceAndProxyAllowanceLazyStore(balanceAllowanceFetcher); - const exchangeTradeSimulator = new ExchangeTransferSimulator(balanceAllowanceStore); - - const filledCancelledFetcher = new OrderFilledCancelledFetcher(this, BlockParamLiteral.Latest); - const orderValidationUtils = new OrderValidationUtils(filledCancelledFetcher, this._web3Wrapper.getProvider()); - await orderValidationUtils.validateFillOrderThrowIfInvalidAsync( - exchangeTradeSimulator, - signedOrder, - fillTakerAssetAmount, - takerAddress, - this.getZRXAssetData(), - ); - } - /** - * Returns the ZRX asset data used by the exchange contract. - * @return ZRX asset data - */ - public getZRXAssetData(): string { - const zrxAssetData = assetDataUtils.encodeERC20AssetData(this.zrxTokenAddress); - return zrxAssetData; - } - /** - * Returns a Transaction Encoder. Transaction messages exist for the purpose of calling methods on the Exchange contract - * in the context of another address. - * @return TransactionEncoder - */ - public async transactionEncoderAsync(): Promise { - const chainId = await providerUtils.getChainIdAsync(this._web3Wrapper.getProvider()); - const exchangeInstance = await this._getExchangeContractAsync(); - const encoder = new TransactionEncoder(exchangeInstance, chainId); - return encoder; - } - // tslint:enable:no-unused-variable - private async _getExchangeContractAsync(): Promise { - if (this._exchangeContractIfExists !== undefined) { - return this._exchangeContractIfExists; - } - const contractInstance = new ExchangeContract( - this.address, - this._web3Wrapper.getProvider(), - this._web3Wrapper.getContractDefaults(), - ); - this._exchangeContractIfExists = contractInstance; - return this._exchangeContractIfExists; - } -} // tslint:disable:max-file-line-count diff --git a/packages/contract-wrappers/src/contract_wrappers/forwarder_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/forwarder_wrapper.ts deleted file mode 100644 index d189aa6def..0000000000 --- a/packages/contract-wrappers/src/contract_wrappers/forwarder_wrapper.ts +++ /dev/null @@ -1,251 +0,0 @@ -import { ForwarderContract } from '@0x/abi-gen-wrappers'; -import { Forwarder } from '@0x/contract-artifacts'; -import { schemas } from '@0x/json-schemas'; -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { ContractAbi } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema'; -import { txOptsSchema } from '../schemas/tx_opts_schema'; -import { OrderTransactionOpts } from '../types'; -import { assert } from '../utils/assert'; -import { calldataOptimizationUtils } from '../utils/calldata_optimization_utils'; -import { constants } from '../utils/constants'; -import { _getDefaultContractAddresses } from '../utils/contract_addresses'; -import { decorators } from '../utils/decorators'; -import { utils } from '../utils/utils'; - -import { ContractWrapper } from './contract_wrapper'; - -/** - * This class includes the functionality related to interacting with the Forwarder contract. - */ -export class ForwarderWrapper extends ContractWrapper { - public abi: ContractAbi = Forwarder.compilerOutput.abi; - public address: string; - public zrxTokenAddress: string; - public etherTokenAddress: string; - private _forwarderContractIfExists?: ForwarderContract; - - /** - * Instantiate ForwarderWrapper - * @param web3Wrapper Web3Wrapper instance to use. - * @param networkId Desired networkId. - * @param address The address of the Exchange contract. If undefined, will - * default to the known address corresponding to the networkId. - * @param zrxTokenAddress The address of the ZRXToken contract. If - * undefined, will default to the known address corresponding to the - * networkId. - * @param etherTokenAddress The address of a WETH (Ether token) contract. If - * undefined, will default to the known address corresponding to the - * networkId. - */ - constructor( - web3Wrapper: Web3Wrapper, - networkId: number, - address?: string, - zrxTokenAddress?: string, - etherTokenAddress?: string, - ) { - super(web3Wrapper, networkId); - this.address = address === undefined ? _getDefaultContractAddresses(networkId).exchange : address; - this.zrxTokenAddress = - zrxTokenAddress === undefined ? _getDefaultContractAddresses(networkId).zrxToken : zrxTokenAddress; - this.etherTokenAddress = - etherTokenAddress === undefined ? _getDefaultContractAddresses(networkId).etherToken : etherTokenAddress; - } - /** - * Purchases as much of orders' makerAssets as possible by selling up to 95% of transaction's ETH value. - * Any ZRX required to pay fees for primary orders will automatically be purchased by this contract. - * 5% of ETH value is reserved for paying fees to order feeRecipients (in ZRX) and forwarding contract feeRecipient (in ETH). - * Any ETH not spent will be refunded to sender. - * @param signedOrders An array of objects that conform to the SignedOrder interface. All orders must specify the same makerAsset. - * All orders must specify WETH as the takerAsset - * @param takerAddress The user Ethereum address who would like to fill this order. Must be available via the supplied - * Provider provided at instantiation. - * @param ethAmount The amount of eth to send with the transaction (in wei). - * @param signedFeeOrders An array of objects that conform to the SignedOrder interface. All orders must specify ZRX as makerAsset and WETH as takerAsset. - * Used to purchase ZRX for primary order fees. - * @param feePercentage The percentage of WETH sold that will payed as fee to forwarding contract feeRecipient. - * Defaults to 0. - * @param feeRecipientAddress The address that will receive ETH when signedFeeOrders are filled. - * @param orderTransactionOpts Transaction parameters. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async marketSellOrdersWithEthAsync( - signedOrders: SignedOrder[], - takerAddress: string, - ethAmount: BigNumber, - signedFeeOrders: SignedOrder[] = [], - feePercentage: number = 0, - feeRecipientAddress: string = constants.NULL_ADDRESS, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - // type assertions - assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); - await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - assert.isBigNumber('ethAmount', ethAmount); - assert.doesConformToSchema('signedFeeOrders', signedFeeOrders, schemas.signedOrdersSchema); - assert.isNumber('feePercentage', feePercentage); - assert.isETHAddressHex('feeRecipientAddress', feeRecipientAddress); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - // other assertions - assert.ordersCanBeUsedForForwarderContract(signedOrders, this.etherTokenAddress); - assert.feeOrdersCanBeUsedForForwarderContract(signedFeeOrders, this.zrxTokenAddress, this.etherTokenAddress); - // format feePercentage - const formattedFeePercentage = utils.numberPercentageToEtherTokenAmountPercentage(feePercentage); - // lowercase input addresses - const normalizedTakerAddress = takerAddress.toLowerCase(); - const normalizedFeeRecipientAddress = feeRecipientAddress.toLowerCase(); - // optimize orders - const optimizedMarketOrders = calldataOptimizationUtils.optimizeForwarderOrders(signedOrders); - const optimizedFeeOrders = calldataOptimizationUtils.optimizeForwarderFeeOrders(signedFeeOrders); - // compile signatures - const signatures = _.map(optimizedMarketOrders, order => order.signature); - const feeSignatures = _.map(optimizedFeeOrders, order => order.signature); - // get contract - const forwarderContractInstance = await this._getForwarderContractAsync(); - // validate transaction - if (orderTransactionOpts.shouldValidate) { - await forwarderContractInstance.marketSellOrdersWithEth.callAsync( - optimizedMarketOrders, - signatures, - optimizedFeeOrders, - feeSignatures, - formattedFeePercentage, - normalizedFeeRecipientAddress, - { - value: ethAmount, - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - } - // send transaction - const txHash = await forwarderContractInstance.marketSellOrdersWithEth.sendTransactionAsync( - optimizedMarketOrders, - signatures, - optimizedFeeOrders, - feeSignatures, - formattedFeePercentage, - feeRecipientAddress, - { - value: ethAmount, - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - return txHash; - } - /** - * Attempt to purchase makerAssetFillAmount of makerAsset by selling ethAmount provided with transaction. - * Any ZRX required to pay fees for primary orders will automatically be purchased by the contract. - * Any ETH not spent will be refunded to sender. - * @param signedOrders An array of objects that conform to the SignedOrder interface. All orders must specify the same makerAsset. - * All orders must specify WETH as the takerAsset - * @param makerAssetFillAmount The amount of the order (in taker asset baseUnits) that you wish to fill. - * @param takerAddress The user Ethereum address who would like to fill this order. Must be available via the supplied - * Provider provided at instantiation. - * @param ethAmount The amount of eth to send with the transaction (in wei). - * @param signedFeeOrders An array of objects that conform to the SignedOrder interface. All orders must specify ZRX as makerAsset and WETH as takerAsset. - * Used to purchase ZRX for primary order fees. - * @param feePercentage The percentage of WETH sold that will payed as fee to forwarding contract feeRecipient. - * Defaults to 0. - * @param feeRecipientAddress The address that will receive ETH when signedFeeOrders are filled. - * @param orderTransactionOpts Transaction parameters. - * @return Transaction hash. - */ - @decorators.asyncZeroExErrorHandler - public async marketBuyOrdersWithEthAsync( - signedOrders: SignedOrder[], - makerAssetFillAmount: BigNumber, - takerAddress: string, - ethAmount: BigNumber, - signedFeeOrders: SignedOrder[] = [], - feePercentage: number = 0, - feeRecipientAddress: string = constants.NULL_ADDRESS, - orderTransactionOpts: OrderTransactionOpts = { shouldValidate: true }, - ): Promise { - // type assertions - assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); - assert.isBigNumber('makerAssetFillAmount', makerAssetFillAmount); - await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - assert.isBigNumber('ethAmount', ethAmount); - assert.doesConformToSchema('signedFeeOrders', signedFeeOrders, schemas.signedOrdersSchema); - assert.isNumber('feePercentage', feePercentage); - assert.isETHAddressHex('feeRecipientAddress', feeRecipientAddress); - assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); - // other assertions - assert.ordersCanBeUsedForForwarderContract(signedOrders, this.etherTokenAddress); - assert.feeOrdersCanBeUsedForForwarderContract(signedFeeOrders, this.zrxTokenAddress, this.etherTokenAddress); - // format feePercentage - const formattedFeePercentage = utils.numberPercentageToEtherTokenAmountPercentage(feePercentage); - // lowercase input addresses - const normalizedTakerAddress = takerAddress.toLowerCase(); - const normalizedFeeRecipientAddress = feeRecipientAddress.toLowerCase(); - // optimize orders - const optimizedMarketOrders = calldataOptimizationUtils.optimizeForwarderOrders(signedOrders); - const optimizedFeeOrders = calldataOptimizationUtils.optimizeForwarderFeeOrders(signedFeeOrders); - // compile signatures - const signatures = _.map(optimizedMarketOrders, order => order.signature); - const feeSignatures = _.map(optimizedFeeOrders, order => order.signature); - // get contract - const forwarderContractInstance = await this._getForwarderContractAsync(); - // validate transaction - if (orderTransactionOpts.shouldValidate) { - await forwarderContractInstance.marketBuyOrdersWithEth.callAsync( - optimizedMarketOrders, - makerAssetFillAmount, - signatures, - optimizedFeeOrders, - feeSignatures, - formattedFeePercentage, - normalizedFeeRecipientAddress, - { - value: ethAmount, - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - } - // send transaction - const txHash = await forwarderContractInstance.marketBuyOrdersWithEth.sendTransactionAsync( - optimizedMarketOrders, - makerAssetFillAmount, - signatures, - optimizedFeeOrders, - feeSignatures, - formattedFeePercentage, - feeRecipientAddress, - { - value: ethAmount, - from: normalizedTakerAddress, - gas: orderTransactionOpts.gasLimit, - gasPrice: orderTransactionOpts.gasPrice, - nonce: orderTransactionOpts.nonce, - }, - ); - return txHash; - } - private async _getForwarderContractAsync(): Promise { - if (this._forwarderContractIfExists !== undefined) { - return this._forwarderContractIfExists; - } - const contractInstance = new ForwarderContract( - this.address, - this._web3Wrapper.getProvider(), - this._web3Wrapper.getContractDefaults(), - ); - this._forwarderContractIfExists = contractInstance; - return this._forwarderContractIfExists; - } -} diff --git a/packages/contract-wrappers/src/contract_wrappers/order_validator_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/order_validator_wrapper.ts deleted file mode 100644 index 02bacf000c..0000000000 --- a/packages/contract-wrappers/src/contract_wrappers/order_validator_wrapper.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { OrderValidatorContract } from '@0x/abi-gen-wrappers'; -import { OrderValidator } from '@0x/contract-artifacts'; -import { schemas } from '@0x/json-schemas'; -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import { ContractAbi } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { BalanceAndAllowance, OrderAndTraderInfo, TraderInfo } from '../types'; -import { assert } from '../utils/assert'; -import { _getDefaultContractAddresses } from '../utils/contract_addresses'; - -import { ContractWrapper } from './contract_wrapper'; - -/** - * This class includes the functionality related to interacting with the OrderValidator contract. - */ -export class OrderValidatorWrapper extends ContractWrapper { - public abi: ContractAbi = OrderValidator.compilerOutput.abi; - public address: string; - private _orderValidatorContractIfExists?: OrderValidatorContract; - /** - * Instantiate OrderValidatorWrapper - * @param web3Wrapper Web3Wrapper instance to use. - * @param networkId Desired networkId. - * @param address The address of the OrderValidator contract. If undefined, - * will default to the known address corresponding to the networkId. - */ - constructor(web3Wrapper: Web3Wrapper, networkId: number, address?: string) { - super(web3Wrapper, networkId); - this.address = address === undefined ? _getDefaultContractAddresses(networkId).orderValidator : address; - } - /** - * Get an object conforming to OrderAndTraderInfo containing on-chain information of the provided order and address - * @param order An object conforming to SignedOrder - * @param takerAddress An ethereum address - * @return OrderAndTraderInfo - */ - public async getOrderAndTraderInfoAsync(order: SignedOrder, takerAddress: string): Promise { - assert.doesConformToSchema('order', order, schemas.signedOrderSchema); - assert.isETHAddressHex('takerAddress', takerAddress); - const OrderValidatorContractInstance = await this._getOrderValidatorContractAsync(); - const orderAndTraderInfo = await OrderValidatorContractInstance.getOrderAndTraderInfo.callAsync( - order, - takerAddress, - ); - const result = { - orderInfo: orderAndTraderInfo[0], - traderInfo: orderAndTraderInfo[1], - }; - return result; - } - /** - * Get an array of objects conforming to OrderAndTraderInfo containing on-chain information of the provided orders and addresses - * @param orders An array of objects conforming to SignedOrder - * @param takerAddresses An array of ethereum addresses - * @return array of OrderAndTraderInfo - */ - public async getOrdersAndTradersInfoAsync( - orders: SignedOrder[], - takerAddresses: string[], - ): Promise { - assert.doesConformToSchema('orders', orders, schemas.signedOrdersSchema); - _.forEach(takerAddresses, (takerAddress, index) => - assert.isETHAddressHex(`takerAddresses[${index}]`, takerAddress), - ); - assert.assert(orders.length === takerAddresses.length, 'Expected orders.length to equal takerAddresses.length'); - const OrderValidatorContractInstance = await this._getOrderValidatorContractAsync(); - const ordersAndTradersInfo = await OrderValidatorContractInstance.getOrdersAndTradersInfo.callAsync( - orders, - takerAddresses, - ); - const orderInfos = ordersAndTradersInfo[0]; - const traderInfos = ordersAndTradersInfo[1]; - const result = _.map(orderInfos, (orderInfo, index) => { - const traderInfo = traderInfos[index]; - return { - orderInfo, - traderInfo, - }; - }); - return result; - } - /** - * Get an object conforming to TraderInfo containing on-chain balance and allowances for maker and taker of order - * @param order An object conforming to SignedOrder - * @param takerAddress An ethereum address - * @return TraderInfo - */ - public async getTraderInfoAsync(order: SignedOrder, takerAddress: string): Promise { - assert.doesConformToSchema('order', order, schemas.signedOrderSchema); - assert.isETHAddressHex('takerAddress', takerAddress); - const OrderValidatorContractInstance = await this._getOrderValidatorContractAsync(); - const result = await OrderValidatorContractInstance.getTraderInfo.callAsync(order, takerAddress); - return result; - } - /** - * Get an array of objects conforming to TraderInfo containing on-chain balance and allowances for maker and taker of order - * @param orders An array of objects conforming to SignedOrder - * @param takerAddresses An array of ethereum addresses - * @return array of TraderInfo - */ - public async getTradersInfoAsync(orders: SignedOrder[], takerAddresses: string[]): Promise { - assert.doesConformToSchema('orders', orders, schemas.signedOrdersSchema); - _.forEach(takerAddresses, (takerAddress, index) => - assert.isETHAddressHex(`takerAddresses[${index}]`, takerAddress), - ); - assert.assert(orders.length === takerAddresses.length, 'Expected orders.length to equal takerAddresses.length'); - const OrderValidatorContractInstance = await this._getOrderValidatorContractAsync(); - const result = await OrderValidatorContractInstance.getTradersInfo.callAsync(orders, takerAddresses); - return result; - } - /** - * Get an object conforming to BalanceAndAllowance containing on-chain balance and allowance for some address and assetData - * @param address An ethereum address - * @param assetData An encoded string that can be decoded by a specified proxy contract - * @return BalanceAndAllowance - */ - public async getBalanceAndAllowanceAsync(address: string, assetData: string): Promise { - assert.isETHAddressHex('address', address); - assert.isHexString('assetData', assetData); - const OrderValidatorContractInstance = await this._getOrderValidatorContractAsync(); - const balanceAndAllowance = await OrderValidatorContractInstance.getBalanceAndAllowance.callAsync( - address, - assetData, - ); - const result = { - balance: balanceAndAllowance[0], - allowance: balanceAndAllowance[1], - }; - return result; - } - /** - * Get an array of objects conforming to BalanceAndAllowance containing on-chain balance and allowance for some address and array of assetDatas - * @param address An ethereum address - * @param assetDatas An array of encoded strings that can be decoded by a specified proxy contract - * @return BalanceAndAllowance - */ - public async getBalancesAndAllowancesAsync(address: string, assetDatas: string[]): Promise { - assert.isETHAddressHex('address', address); - _.forEach(assetDatas, (assetData, index) => assert.isHexString(`assetDatas[${index}]`, assetData)); - const OrderValidatorContractInstance = await this._getOrderValidatorContractAsync(); - const balancesAndAllowances = await OrderValidatorContractInstance.getBalancesAndAllowances.callAsync( - address, - assetDatas, - ); - const balances = balancesAndAllowances[0]; - const allowances = balancesAndAllowances[1]; - const result = _.map(balances, (balance, index) => { - const allowance = allowances[index]; - return { - balance, - allowance, - }; - }); - return result; - } - /** - * Get owner address of tokenId by calling `token.ownerOf(tokenId)`, but returns a null owner instead of reverting on an unowned token. - * @param tokenAddress An ethereum address - * @param tokenId An ERC721 tokenId - * @return Owner of tokenId or null address if unowned - */ - public async getERC721TokenOwnerAsync(tokenAddress: string, tokenId: BigNumber): Promise { - assert.isETHAddressHex('tokenAddress', tokenAddress); - assert.isBigNumber('tokenId', tokenId); - const OrderValidatorContractInstance = await this._getOrderValidatorContractAsync(); - const result = await OrderValidatorContractInstance.getERC721TokenOwner.callAsync(tokenAddress, tokenId); - return result; - } - private async _getOrderValidatorContractAsync(): Promise { - if (this._orderValidatorContractIfExists !== undefined) { - return this._orderValidatorContractIfExists; - } - const contractInstance = new OrderValidatorContract( - this.address, - this._web3Wrapper.getProvider(), - this._web3Wrapper.getContractDefaults(), - ); - this._orderValidatorContractIfExists = contractInstance; - return this._orderValidatorContractIfExists; - } -} diff --git a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts b/packages/contract-wrappers/src/coordinator_wrapper.ts similarity index 92% rename from packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts rename to packages/contract-wrappers/src/coordinator_wrapper.ts index e7c22020e9..8c0445cef4 100644 --- a/packages/contract-wrappers/src/contract_wrappers/coordinator_wrapper.ts +++ b/packages/contract-wrappers/src/coordinator_wrapper.ts @@ -1,4 +1,3 @@ -import { CoordinatorContract, CoordinatorRegistryContract, ExchangeContract } from '@0x/abi-gen-wrappers'; import { getContractAddressesForNetworkOrThrow } from '@0x/contract-addresses'; import { Coordinator } from '@0x/contract-artifacts'; import { schemas } from '@0x/json-schemas'; @@ -10,10 +9,12 @@ import { ContractAbi } from 'ethereum-types'; import * as HttpStatus from 'http-status-codes'; import { flatten } from 'lodash'; -import { orderTxOptsSchema } from '../schemas/order_tx_opts_schema'; -import { txOptsSchema } from '../schemas/tx_opts_schema'; -import { CoordinatorTransaction, OrderTransactionOpts } from '../types'; -import { assert } from '../utils/assert'; +import { CoordinatorContract, CoordinatorRegistryContract, ExchangeContract } from './index'; + +import { orderTxOptsSchema } from './schemas/order_tx_opts_schema'; +import { txOptsSchema } from './schemas/tx_opts_schema'; +import { CoordinatorTransaction, OrderTransactionOpts } from './types'; +import { assert } from './utils/assert'; import { CoordinatorServerApprovalRawResponse, CoordinatorServerApprovalResponse, @@ -21,25 +22,24 @@ import { CoordinatorServerError, CoordinatorServerErrorMsg, CoordinatorServerResponse, -} from '../utils/coordinator_server_types'; -import { decorators } from '../utils/decorators'; -import { TransactionEncoder } from '../utils/transaction_encoder'; +} from './utils/coordinator_server_types'; +import { decorators } from './utils/decorators'; +import { getAbiEncodedTransactionData } from './utils/getAbiEncodedTransactionData'; -import { ContractWrapper } from './contract_wrapper'; /** * This class includes all the functionality related to filling or cancelling orders through * the 0x V2 Coordinator extension contract. */ -export class CoordinatorWrapper extends ContractWrapper { +export class CoordinatorWrapper { public abi: ContractAbi = Coordinator.compilerOutput.abi; public networkId: number; public address: string; public exchangeAddress: string; public registryAddress: string; + private readonly _web3Wrapper: Web3Wrapper; private readonly _contractInstance: CoordinatorContract; private readonly _registryInstance: CoordinatorRegistryContract; private readonly _exchangeInstance: ExchangeContract; - private readonly _transactionEncoder: TransactionEncoder; private readonly _feeRecipientToEndpoint: { [feeRecipient: string]: string } = {}; /** @@ -60,13 +60,12 @@ export class CoordinatorWrapper extends ContractWrapper { exchangeAddress?: string, registryAddress?: string, ) { - super(web3Wrapper, networkId); this.networkId = networkId; - const contractAddresses = getContractAddressesForNetworkOrThrow(networkId); this.address = address === undefined ? contractAddresses.coordinator : address; this.exchangeAddress = exchangeAddress === undefined ? contractAddresses.coordinator : exchangeAddress; this.registryAddress = registryAddress === undefined ? contractAddresses.coordinatorRegistry : registryAddress; + this._web3Wrapper = web3Wrapper; this._contractInstance = new CoordinatorContract( this.address, @@ -83,8 +82,6 @@ export class CoordinatorWrapper extends ContractWrapper { this._web3Wrapper.getProvider(), this._web3Wrapper.getContractDefaults(), ); - - this._transactionEncoder = new TransactionEncoder(this._exchangeInstance); } /** @@ -113,7 +110,12 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const data = this._transactionEncoder.fillOrderTx(signedOrder, takerAssetFillAmount); + const data = this._getAbiEncodedTransactionData( + 'fillOrder', + signedOrder, + takerAssetFillAmount, + signedOrder.signature, + ); const txHash = await this._handleFillsAsync(data, takerAddress, [signedOrder], orderTransactionOpts); return txHash; } @@ -140,7 +142,12 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const data = this._transactionEncoder.fillOrderNoThrowTx(signedOrder, takerAssetFillAmount); + const data = this._getAbiEncodedTransactionData( + 'fillOrderNoThrow', + signedOrder, + takerAssetFillAmount, + signedOrder.signature, + ); const txHash = await this._handleFillsAsync(data, takerAddress, [signedOrder], orderTransactionOpts); return txHash; } @@ -168,7 +175,12 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const data = this._transactionEncoder.fillOrKillOrderTx(signedOrder, takerAssetFillAmount); + const data = this._getAbiEncodedTransactionData( + 'fillOrKillOrder', + signedOrder, + takerAssetFillAmount, + signedOrder.signature, + ); const txHash = await this._handleFillsAsync(data, takerAddress, [signedOrder], orderTransactionOpts); return txHash; } @@ -202,7 +214,13 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const data = this._transactionEncoder.batchFillOrdersTx(signedOrders, takerAssetFillAmounts); + const signatures = signedOrders.map(o => o.signature); + const data = this._getAbiEncodedTransactionData( + 'batchFillOrders', + signedOrders, + takerAssetFillAmounts, + signatures, + ); const txHash = await this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); return txHash; } @@ -231,7 +249,13 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const data = this._transactionEncoder.batchFillOrdersNoThrowTx(signedOrders, takerAssetFillAmounts); + const signatures = signedOrders.map(o => o.signature); + const data = this._getAbiEncodedTransactionData( + 'batchFillOrdersNoThrow', + signedOrders, + takerAssetFillAmounts, + signatures, + ); const txHash = await this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); return txHash; } @@ -260,7 +284,13 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const data = this._transactionEncoder.batchFillOrKillOrdersTx(signedOrders, takerAssetFillAmounts); + const signatures = signedOrders.map(o => o.signature); + const data = this._getAbiEncodedTransactionData( + 'batchFillOrKillOrders', + signedOrders, + takerAssetFillAmounts, + signatures, + ); const txHash = await this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); return txHash; } @@ -292,7 +322,13 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const data = this._transactionEncoder.marketBuyOrdersTx(signedOrders, makerAssetFillAmount); + const signatures = signedOrders.map(o => o.signature); + const data = this._getAbiEncodedTransactionData( + 'marketBuyOrders', + signedOrders, + makerAssetFillAmount, + signatures, + ); const txHash = await this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); return txHash; } @@ -324,7 +360,13 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const data = this._transactionEncoder.marketSellOrdersTx(signedOrders, takerAssetFillAmount); + const signatures = signedOrders.map(o => o.signature); + const data = this._getAbiEncodedTransactionData( + 'marketSellOrders', + signedOrders, + takerAssetFillAmount, + signatures, + ); const txHash = await this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); return txHash; } @@ -351,7 +393,13 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const data = this._transactionEncoder.marketBuyOrdersNoThrowTx(signedOrders, makerAssetFillAmount); + const signatures = signedOrders.map(o => o.signature); + const data = this._getAbiEncodedTransactionData( + 'marketBuyOrdersNoThrow', + signedOrders, + makerAssetFillAmount, + signatures, + ); const txHash = await this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); return txHash; } @@ -378,7 +426,13 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); await assert.isSenderAddressAsync('takerAddress', takerAddress, this._web3Wrapper); - const data = this._transactionEncoder.marketSellOrdersNoThrowTx(signedOrders, takerAssetFillAmount); + const signatures = signedOrders.map(o => o.signature); + const data = this._getAbiEncodedTransactionData( + 'marketSellOrdersNoThrow', + signedOrders, + takerAssetFillAmount, + signatures, + ); const txHash = await this._handleFillsAsync(data, takerAddress, signedOrders, orderTransactionOpts); return txHash; } @@ -395,7 +449,7 @@ export class CoordinatorWrapper extends ContractWrapper { assert.isETHAddressHex('feeRecipientAddress', order.feeRecipientAddress); assert.isSenderAddressAsync('makerAddress', order.makerAddress, this._web3Wrapper); - const data = this._transactionEncoder.cancelOrderTx(order); + const data = this._getAbiEncodedTransactionData('cancelOrder', order); const transaction = await this._generateSignedZeroExTransactionAsync(data, order.makerAddress); const endpoint = await this._getServerEndpointOrThrowAsync(order.feeRecipientAddress); @@ -429,7 +483,7 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('orders', orders, schemas.ordersSchema); const makerAddress = getMakerAddressOrThrow(orders); assert.isSenderAddressAsync('makerAddress', makerAddress, this._web3Wrapper); - const data = this._transactionEncoder.batchCancelOrdersTx(orders); + const data = this._getAbiEncodedTransactionData('batchCancelOrders', orders); const serverEndpointsToOrders = await this._mapServerEndpointsToOrdersAsync(orders); @@ -487,7 +541,7 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); await assert.isSenderAddressAsync('makerAddress', order.makerAddress, this._web3Wrapper); - const data = this._transactionEncoder.cancelOrderTx(order); + const data = this._getAbiEncodedTransactionData('cancelOrder', order); const transaction = await this._generateSignedZeroExTransactionAsync(data, order.makerAddress); const approvalSignatures = new Array(); @@ -520,7 +574,7 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); await assert.isSenderAddressAsync('makerAddress', makerAddress, this._web3Wrapper); - const data = this._transactionEncoder.batchCancelOrdersTx(orders); + const data = this._getAbiEncodedTransactionData('batchCancelOrders', orders); const transaction = await this._generateSignedZeroExTransactionAsync(data, makerAddress); const approvalSignatures = new Array(); @@ -555,7 +609,7 @@ export class CoordinatorWrapper extends ContractWrapper { assert.doesConformToSchema('orderTransactionOpts', orderTransactionOpts, orderTxOptsSchema, [txOptsSchema]); await assert.isSenderAddressAsync('senderAddress', senderAddress, this._web3Wrapper); - const data = this._transactionEncoder.cancelOrdersUpToTx(targetOrderEpoch); + const data = this._getAbiEncodedTransactionData('cancelOrdersUpTo', targetOrderEpoch); const transaction = await this._generateSignedZeroExTransactionAsync(data, senderAddress); const approvalSignatures = new Array(); @@ -619,6 +673,10 @@ export class CoordinatorWrapper extends ContractWrapper { return signerAddress; } + private _getAbiEncodedTransactionData(methodName: K, ...args: any[]): string { + return getAbiEncodedTransactionData(this._exchangeInstance, methodName, ...args); + } + private async _handleFillsAsync( data: string, takerAddress: string, diff --git a/packages/contract-wrappers/src/fetchers/asset_balance_and_proxy_allowance_fetcher.ts b/packages/contract-wrappers/src/fetchers/asset_balance_and_proxy_allowance_fetcher.ts deleted file mode 100644 index e5ff03862d..0000000000 --- a/packages/contract-wrappers/src/fetchers/asset_balance_and_proxy_allowance_fetcher.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { AbstractBalanceAndProxyAllowanceFetcher, assetDataUtils } from '@0x/order-utils'; -import { BigNumber } from '@0x/utils'; -import { BlockParamLiteral } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { ERC20TokenWrapper } from '../contract_wrappers/erc20_token_wrapper'; -import { ERC721TokenWrapper } from '../contract_wrappers/erc721_token_wrapper'; - -export class AssetBalanceAndProxyAllowanceFetcher implements AbstractBalanceAndProxyAllowanceFetcher { - private readonly _erc20Token: ERC20TokenWrapper; - private readonly _erc721Token: ERC721TokenWrapper; - private readonly _stateLayer: BlockParamLiteral; - constructor(erc20Token: ERC20TokenWrapper, erc721Token: ERC721TokenWrapper, stateLayer: BlockParamLiteral) { - this._erc20Token = erc20Token; - this._erc721Token = erc721Token; - this._stateLayer = stateLayer; - } - public async getBalanceAsync(assetData: string, userAddress: string): Promise { - const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData); - let balance: BigNumber | undefined; - if (assetDataUtils.isERC20AssetData(decodedAssetData)) { - balance = await this._erc20Token.getBalanceAsync(decodedAssetData.tokenAddress, userAddress, { - defaultBlock: this._stateLayer, - }); - } else if (assetDataUtils.isERC721AssetData(decodedAssetData)) { - const tokenOwner = await this._erc721Token.getOwnerOfAsync( - decodedAssetData.tokenAddress, - decodedAssetData.tokenId, - { - defaultBlock: this._stateLayer, - }, - ); - balance = tokenOwner === userAddress ? new BigNumber(1) : new BigNumber(0); - } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) { - // The `balance` for MultiAssetData is the total units of the entire `assetData` that are held by the `userAddress`. - for (const [index, nestedAssetDataElement] of decodedAssetData.nestedAssetData.entries()) { - const nestedAmountElement = decodedAssetData.amounts[index]; - const nestedAssetBalance = (await this.getBalanceAsync( - nestedAssetDataElement, - userAddress, - )).dividedToIntegerBy(nestedAmountElement); - if (balance === undefined || nestedAssetBalance.isLessThan(balance)) { - balance = nestedAssetBalance; - } - } - } - return balance as BigNumber; - } - public async getProxyAllowanceAsync(assetData: string, userAddress: string): Promise { - const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData); - let proxyAllowance: BigNumber | undefined; - if (assetDataUtils.isERC20AssetData(decodedAssetData)) { - proxyAllowance = await this._erc20Token.getProxyAllowanceAsync(decodedAssetData.tokenAddress, userAddress, { - defaultBlock: this._stateLayer, - }); - } else if (assetDataUtils.isERC721AssetData(decodedAssetData)) { - const isApprovedForAll = await this._erc721Token.isProxyApprovedForAllAsync( - decodedAssetData.tokenAddress, - userAddress, - { - defaultBlock: this._stateLayer, - }, - ); - if (isApprovedForAll) { - return new BigNumber(this._erc20Token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS); - } else { - const isApproved = await this._erc721Token.isProxyApprovedAsync( - decodedAssetData.tokenAddress, - decodedAssetData.tokenId, - { - defaultBlock: this._stateLayer, - }, - ); - proxyAllowance = isApproved ? new BigNumber(1) : new BigNumber(0); - } - } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) { - // The `proxyAllowance` for MultiAssetData is the total units of the entire `assetData` that the proxies have been approved to spend by the `userAddress`. - for (const [index, nestedAssetDataElement] of decodedAssetData.nestedAssetData.entries()) { - const nestedAmountElement = decodedAssetData.amounts[index]; - const nestedAssetAllowance = (await this.getProxyAllowanceAsync( - nestedAssetDataElement, - userAddress, - )).dividedToIntegerBy(nestedAmountElement); - if (proxyAllowance === undefined || nestedAssetAllowance.isLessThan(proxyAllowance)) { - proxyAllowance = nestedAssetAllowance; - } - } - } - return proxyAllowance as BigNumber; - } -} diff --git a/packages/contract-wrappers/src/fetchers/order_filled_cancelled_fetcher.ts b/packages/contract-wrappers/src/fetchers/order_filled_cancelled_fetcher.ts deleted file mode 100644 index 5d350916cf..0000000000 --- a/packages/contract-wrappers/src/fetchers/order_filled_cancelled_fetcher.ts +++ /dev/null @@ -1,39 +0,0 @@ -// tslint:disable:no-unnecessary-type-assertion -import { AbstractOrderFilledCancelledFetcher, orderHashUtils } from '@0x/order-utils'; -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { BlockParamLiteral } from 'ethereum-types'; - -import { ExchangeWrapper } from '../contract_wrappers/exchange_wrapper'; - -export class OrderFilledCancelledFetcher implements AbstractOrderFilledCancelledFetcher { - private readonly _exchange: ExchangeWrapper; - private readonly _stateLayer: BlockParamLiteral; - constructor(exchange: ExchangeWrapper, stateLayer: BlockParamLiteral) { - this._exchange = exchange; - this._stateLayer = stateLayer; - } - public async getFilledTakerAmountAsync(orderHash: string): Promise { - const filledTakerAmount = this._exchange.getFilledTakerAssetAmountAsync(orderHash, { - defaultBlock: this._stateLayer, - }); - return filledTakerAmount; - } - public async isOrderCancelledAsync(signedOrder: SignedOrder): Promise { - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - const isCancelled = await this._exchange.isCancelledAsync(orderHash); - const orderEpoch = await this._exchange.getOrderEpochAsync( - signedOrder.makerAddress, - signedOrder.senderAddress, - { - defaultBlock: this._stateLayer, - }, - ); - const isCancelledByOrderEpoch = orderEpoch > signedOrder.salt; - return isCancelled || isCancelledByOrderEpoch; - } - public getZRXAssetData(): string { - const zrxAssetData = this._exchange.getZRXAssetData(); - return zrxAssetData; - } -} diff --git a/packages/contract-wrappers/src/index.ts b/packages/contract-wrappers/src/index.ts index 2c9f869392..0cdaefd19b 100644 --- a/packages/contract-wrappers/src/index.ts +++ b/packages/contract-wrappers/src/index.ts @@ -1,124 +1,44 @@ -export { ContractAddresses } from '@0x/contract-addresses'; +export * from './generated-wrappers/asset_proxy_owner'; +export * from './generated-wrappers/dev_utils'; +export * from './generated-wrappers/dummy_erc20_token'; +export * from './generated-wrappers/dummy_erc721_token'; +export * from './generated-wrappers/dutch_auction'; +export * from './generated-wrappers/erc20_proxy'; +export * from './generated-wrappers/erc20_token'; +export * from './generated-wrappers/erc721_proxy'; +export * from './generated-wrappers/erc721_token'; +export * from './generated-wrappers/exchange'; +export * from './generated-wrappers/forwarder'; +export * from './generated-wrappers/i_asset_proxy'; +export * from './generated-wrappers/i_validator'; +export * from './generated-wrappers/i_wallet'; +export * from './generated-wrappers/multi_asset_proxy'; +export * from './generated-wrappers/order_validator'; +export * from './generated-wrappers/weth9'; +export * from './generated-wrappers/zrx_token'; +export * from './generated-wrappers/coordinator'; +export * from './generated-wrappers/coordinator_registry'; +export * from './generated-wrappers/eth_balance_checker'; -export { - WETH9Events, - WETH9WithdrawalEventArgs, - WETH9ApprovalEventArgs, - WETH9EventArgs, - WETH9DepositEventArgs, - WETH9TransferEventArgs, - ERC20TokenTransferEventArgs, - ERC20TokenApprovalEventArgs, - ERC20TokenEvents, - ERC20TokenEventArgs, - ERC721TokenApprovalEventArgs, - ERC721TokenApprovalForAllEventArgs, - ERC721TokenTransferEventArgs, - ERC721TokenEvents, - ERC721TokenEventArgs, - ExchangeCancelUpToEventArgs, - ExchangeAssetProxyRegisteredEventArgs, - ExchangeSignatureValidatorApprovalEventArgs, - ExchangeFillEventArgs, - ExchangeCancelEventArgs, - ExchangeEventArgs, - ExchangeEvents, -} from '@0x/abi-gen-wrappers'; +export * from '@0x/contract-addresses'; export { ContractWrappers } from './contract_wrappers'; -export { CoordinatorWrapper } from './contract_wrappers/coordinator_wrapper'; -export { ERC20TokenWrapper } from './contract_wrappers/erc20_token_wrapper'; -export { ERC721TokenWrapper } from './contract_wrappers/erc721_token_wrapper'; -export { EtherTokenWrapper } from './contract_wrappers/ether_token_wrapper'; -export { ExchangeWrapper } from './contract_wrappers/exchange_wrapper'; -export { ERC20ProxyWrapper } from './contract_wrappers/erc20_proxy_wrapper'; -export { ERC721ProxyWrapper } from './contract_wrappers/erc721_proxy_wrapper'; -export { ForwarderWrapper } from './contract_wrappers/forwarder_wrapper'; -export { OrderValidatorWrapper } from './contract_wrappers/order_validator_wrapper'; -export { DutchAuctionWrapper } from './contract_wrappers/dutch_auction_wrapper'; - -export { TransactionEncoder } from './utils/transaction_encoder'; - -export { AbiDecoder, DecodedCalldata } from '@0x/utils'; +export { CoordinatorWrapper } from './coordinator_wrapper'; +export { BlockRange } from '@0x/base-contract'; export { - ContractWrappersError, - ForwarderWrapperError, + OrderStatus, + ContractError, + ForwarderError, + OrderAndTraderInfo, + CoordinatorServerCancellationResponse, + CoordinatorServerError, IndexedFilterValues, - BlockRange, ContractWrappersConfig, - MethodOpts, OrderTransactionOpts, TransactionOpts, - OrderStatus, OrderInfo, EventCallback, DecodedLogEvent, - BalanceAndAllowance, - OrderAndTraderInfo, TraderInfo, - ValidateOrderFillableOpts, - CoordinatorServerCancellationResponse, - CoordinatorServerError, } from './types'; - -export { - AssetData, - ERC20AssetData, - ERC721AssetData, - ERC1155AssetData, - SingleAssetData, - MultiAssetData, - StaticCallAssetData, - MultiAssetDataWithRecursiveDecoding, - DutchAuctionDetails, - DutchAuctionData, - Order, - SignedOrder, - AssetProxyId, - SignedZeroExTransaction, - ZeroExTransaction, -} from '@0x/types'; - -export { - BlockParamLiteral, - BlockParam, - ContractEventArg, - SupportedProvider, - ContractAbi, - JSONRPCRequestPayload, - JSONRPCResponsePayload, - JSONRPCErrorCallback, - JSONRPCResponseError, - AbiDefinition, - LogWithDecodedArgs, - LogEntry, - DecodedLogEntry, - DecodedLogEntryEvent, - LogEntryEvent, - RawLog, - FunctionAbi, - EventAbi, - EventParameter, - DecodedLogArgs, - MethodAbi, - ConstructorAbi, - FallbackAbi, - DataItem, - TupleDataItem, - ConstructorStateMutability, - StateMutability, - Web3JsProvider, - GanacheProvider, - EIP1193Provider, - ZeroExProvider, - EIP1193Event, - Web3JsV1Provider, - Web3JsV2Provider, - Web3JsV3Provider, -} from 'ethereum-types'; - -export { AbstractBalanceAndProxyAllowanceFetcher, AbstractOrderFilledCancelledFetcher } from '@0x/order-utils'; - -export { AssetBalanceAndProxyAllowanceFetcher } from './fetchers/asset_balance_and_proxy_allowance_fetcher'; -export { OrderFilledCancelledFetcher } from './fetchers/order_filled_cancelled_fetcher'; diff --git a/packages/contract-wrappers/src/schemas/method_opts_schema.ts b/packages/contract-wrappers/src/schemas/method_opts_schema.ts deleted file mode 100644 index 83003f8188..0000000000 --- a/packages/contract-wrappers/src/schemas/method_opts_schema.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const methodOptsSchema = { - id: '/MethodOpts', - properties: { - defaultBlock: { $ref: '/blockParamSchema' }, - }, - type: 'object', -}; diff --git a/packages/contract-wrappers/src/schemas/validate_order_fillable_opts_schema.ts b/packages/contract-wrappers/src/schemas/validate_order_fillable_opts_schema.ts deleted file mode 100644 index 2e111af04c..0000000000 --- a/packages/contract-wrappers/src/schemas/validate_order_fillable_opts_schema.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const validateOrderFillableOptsSchema = { - id: '/ValidateOrderFillableOpts', - properties: { - expectedFillTakerTokenAmount: { $ref: '/wholeNumberSchema' }, - }, - type: 'object', -}; diff --git a/packages/contract-wrappers/src/types.ts b/packages/contract-wrappers/src/types.ts index de190c62d1..46f189790f 100644 --- a/packages/contract-wrappers/src/types.ts +++ b/packages/contract-wrappers/src/types.ts @@ -1,28 +1,34 @@ -import { - ERC20TokenEventArgs, - ERC20TokenEvents, - ERC721TokenEventArgs, - ERC721TokenEvents, - ExchangeEventArgs, - ExchangeEvents, - WETH9EventArgs, - WETH9Events, -} from '@0x/abi-gen-wrappers'; import { ContractAddresses } from '@0x/contract-addresses'; -import { OrderState, SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; -import { BlockParam, ContractEventArg, DecodedLogArgs, LogEntryEvent, LogWithDecodedArgs } from 'ethereum-types'; +import { ContractEventArg, DecodedLogArgs, LogWithDecodedArgs } from 'ethereum-types'; -export enum ExchangeWrapperError { - AssetDataMismatch = 'ASSET_DATA_MISMATCH', +export interface DecodedLogEvent { + isRemoved: boolean; + log: LogWithDecodedArgs; } -export enum ForwarderWrapperError { +export type EventCallback = ( + err: null | Error, + log?: DecodedLogEvent, +) => void; + +export interface TxOpts { + from: string; + gas?: number; + value?: BigNumber; + gasPrice?: BigNumber; +} + +export interface IndexedFilterValues { + [index: string]: ContractEventArg; +} + +export enum ForwarderError { CompleteFillFailed = 'COMPLETE_FILL_FAILED', } -export enum ContractWrappersError { +export enum ContractError { ContractNotDeployedOnNetwork = 'CONTRACT_NOT_DEPLOYED_ON_NETWORK', InsufficientAllowanceForTransfer = 'INSUFFICIENT_ALLOWANCE_FOR_TRANSFER', InsufficientBalanceForTransfer = 'INSUFFICIENT_BALANCE_FOR_TRANSFER', @@ -37,75 +43,6 @@ export enum ContractWrappersError { SignatureRequestDenied = 'SIGNATURE_REQUEST_DENIED', } -export enum InternalContractWrappersError { - NoAbiDecoder = 'NO_ABI_DECODER', -} - -export type LogEvent = LogEntryEvent; -export interface DecodedLogEvent { - isRemoved: boolean; - log: LogWithDecodedArgs; -} - -export type EventCallback = ( - err: null | Error, - log?: DecodedLogEvent, -) => void; - -export interface ContractEvent { - logIndex: number; - transactionIndex: number; - transactionHash: string; - blockHash: string; - blockNumber: number; - address: string; - type: string; - event: string; - args: ContractEventArgs; -} - -export type ContractEventArgs = ExchangeEventArgs | ERC20TokenEventArgs | ERC721TokenEventArgs | WETH9EventArgs; - -// [address, name, symbol, decimals, ipfsHash, swarmHash] -export type TokenMetadata = [string, string, string, number, string, string]; - -export interface Token { - name: string; - address: string; - symbol: string; - decimals: number; -} - -export interface TxOpts { - from: string; - gas?: number; - value?: BigNumber; - gasPrice?: BigNumber; -} - -export interface TokenAddressBySymbol { - [symbol: string]: string; -} - -export type ContractEvents = ERC20TokenEvents | ERC721TokenEvents | ExchangeEvents | WETH9Events; - -export interface IndexedFilterValues { - [index: string]: ContractEventArg; -} - -export interface BlockRange { - fromBlock: BlockParam; - toBlock: BlockParam; -} - -export interface OrderFillRequest { - signedOrder: SignedOrder; - takerAssetFillAmount: BigNumber; -} - -export type AsyncMethod = (...args: any[]) => Promise; -export type SyncMethod = (...args: any[]) => any; - /** * networkId: The id of the underlying ethereum network your provider is connected to. (1-mainnet, 3-ropsten, 4-rinkeby, 42-kovan, 50-testrpc) * gasPrice: Gas price to use with every transaction @@ -119,35 +56,6 @@ export interface ContractWrappersConfig { blockPollingIntervalMs?: number; } -/** - * `expectedFillTakerTokenAmount`: If specified, the validation method will ensure that the supplied order maker has a sufficient - * allowance/balance to fill this amount of the order's takerTokenAmount. - * - * `validateRemainingOrderAmountIsFillable`: The validation method ensures that the maker has sufficient allowance/balance to fill - * the entire remaining order amount. If this option is set to false, the balances - * and allowances are calculated to determine the order is fillable for a - * non-zero amount (some value less than or equal to the order remaining amount). - * We call such orders "partially fillable orders". Default is `true`. - * - * `simulationTakerAddress`: During the maker transfer simulation, tokens are sent from the maker to the `simulationTakerAddress`. This defaults - * to the `takerAddress` specified in the order. Some tokens prevent transfer to the NULL address so this address can be specified. - */ -export interface ValidateOrderFillableOpts { - expectedFillTakerTokenAmount?: BigNumber; - validateRemainingOrderAmountIsFillable?: boolean; - simulationTakerAddress?: string; -} - -/** - * defaultBlock: The block up to which to query the blockchain state. Setting this to a historical block number - * let's the user query the blockchain's state at an arbitrary point in time. In order for this to work, the - * backing Ethereum node must keep the entire historical state of the chain (e.g setting `--pruning=archive` - * flag when running Parity). - */ -export interface MethodOpts { - defaultBlock?: BlockParam; -} - /** * gasPrice: Gas price in Wei to use for a transaction * gasLimit: The amount of gas to send with a transaction (in Gwei) @@ -167,18 +75,6 @@ export interface OrderTransactionOpts extends TransactionOpts { shouldValidate?: boolean; } -export enum TradeSide { - Maker = 'maker', - Taker = 'taker', -} - -export enum TransferType { - Trade = 'trade', - Fee = 'fee', -} - -export type OnOrderStateChangeCallback = (err: Error | null, orderState?: OrderState) => void; - export interface OrderInfo { orderStatus: OrderStatus; orderHash: string; @@ -211,15 +107,6 @@ export interface OrderAndTraderInfo { traderInfo: TraderInfo; } -export interface BalanceAndAllowance { - balance: BigNumber; - allowance: BigNumber; -} - -export enum DutchAuctionWrapperError { - AssetDataMismatch = 'ASSET_DATA_MISMATCH', -} - export { CoordinatorServerCancellationResponse, CoordinatorServerError } from './utils/coordinator_server_types'; export interface CoordinatorTransaction { diff --git a/packages/contract-wrappers/src/utils/assert.ts b/packages/contract-wrappers/src/utils/assert.ts index c4214542c6..1f1c8201a5 100644 --- a/packages/contract-wrappers/src/utils/assert.ts +++ b/packages/contract-wrappers/src/utils/assert.ts @@ -8,7 +8,7 @@ import { Web3Wrapper } from '@0x/web3-wrapper'; import { SupportedProvider } from 'ethereum-types'; import * as _ from 'lodash'; -import { constants } from './constants'; +const NULL_ADDRESS = '0x0000000000000000000000000000000000000000'; export const assert = { ...sharedAssert, @@ -56,7 +56,7 @@ export const assert = { } }, allTakerAddressesAreNull(orders: Order[]): void { - assert.ordersHaveAtMostOneUniqueValueForProperty(orders, 'takerAddress', constants.NULL_ADDRESS); + assert.ordersHaveAtMostOneUniqueValueForProperty(orders, 'takerAddress', NULL_ADDRESS); }, allMakerAssetDatasAreErc20Token(orders: Order[], tokenAddress: string): void { assert.ordersHaveAtMostOneUniqueValueForProperty( diff --git a/packages/contract-wrappers/src/utils/calldata_optimization_utils.ts b/packages/contract-wrappers/src/utils/calldata_optimization_utils.ts deleted file mode 100644 index bee7acaa7c..0000000000 --- a/packages/contract-wrappers/src/utils/calldata_optimization_utils.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { SignedOrder } from '@0x/types'; -import * as _ from 'lodash'; - -import { constants } from './constants'; - -export const calldataOptimizationUtils = { - /** - * Takes an array of orders and outputs an array of equivalent orders where all takerAssetData are '0x' and - * all makerAssetData are '0x' except for that of the first order, which retains its original value - * @param orders An array of SignedOrder objects - * @returns optimized orders - */ - optimizeForwarderOrders(orders: SignedOrder[]): SignedOrder[] { - const optimizedOrders = _.map(orders, (order, index) => - transformOrder(order, { - makerAssetData: index === 0 ? order.makerAssetData : constants.NULL_BYTES, - takerAssetData: constants.NULL_BYTES, - }), - ); - return optimizedOrders; - }, - /** - * Takes an array of orders and outputs an array of equivalent orders where all takerAssetData are '0x' and - * all makerAssetData are '0x' - * @param orders An array of SignedOrder objects - * @returns optimized orders - */ - optimizeForwarderFeeOrders(orders: SignedOrder[]): SignedOrder[] { - const optimizedOrders = _.map(orders, (order, index) => - transformOrder(order, { - makerAssetData: constants.NULL_BYTES, - takerAssetData: constants.NULL_BYTES, - }), - ); - return optimizedOrders; - }, -}; - -const transformOrder = (order: SignedOrder, partialOrder: Partial) => { - return { - ...order, - ...partialOrder, - }; -}; diff --git a/packages/contract-wrappers/src/utils/constants.ts b/packages/contract-wrappers/src/utils/constants.ts deleted file mode 100644 index 94afdc1127..0000000000 --- a/packages/contract-wrappers/src/utils/constants.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { BigNumber } from '@0x/utils'; - -export const constants = { - NULL_ADDRESS: '0x0000000000000000000000000000000000000000', - NULL_BYTES: '0x', - TESTRPC_NETWORK_ID: 50, - INVALID_JUMP_PATTERN: 'invalid JUMP at', - REVERT: 'revert', - OUT_OF_GAS_PATTERN: 'out of gas', - INVALID_TAKER_FORMAT: 'instance.taker is not of a type(s) string', - // tslint:disable-next-line:custom-no-magic-numbers - UNLIMITED_ALLOWANCE_IN_BASE_UNITS: new BigNumber(2).pow(256).minus(1), - DEFAULT_BLOCK_POLLING_INTERVAL: 1000, - ZERO_AMOUNT: new BigNumber(0), - ONE_AMOUNT: new BigNumber(1), - ETHER_TOKEN_DECIMALS: 18, - METAMASK_USER_DENIED_SIGNATURE_PATTERN: 'User denied transaction signature', - TRUST_WALLET_USER_DENIED_SIGNATURE_PATTERN: 'cancelled', -}; diff --git a/packages/contract-wrappers/src/utils/decorators.ts b/packages/contract-wrappers/src/utils/decorators.ts index 3acfa3a886..5862f5017f 100644 --- a/packages/contract-wrappers/src/utils/decorators.ts +++ b/packages/contract-wrappers/src/utils/decorators.ts @@ -1,17 +1,40 @@ import * as _ from 'lodash'; -import { AsyncMethod, ContractWrappersError, SyncMethod } from '../types'; +export enum ContractError { + ContractNotDeployedOnNetwork = 'CONTRACT_NOT_DEPLOYED_ON_NETWORK', + InsufficientAllowanceForTransfer = 'INSUFFICIENT_ALLOWANCE_FOR_TRANSFER', + InsufficientBalanceForTransfer = 'INSUFFICIENT_BALANCE_FOR_TRANSFER', + InsufficientEthBalanceForDeposit = 'INSUFFICIENT_ETH_BALANCE_FOR_DEPOSIT', + InsufficientWEthBalanceForWithdrawal = 'INSUFFICIENT_WETH_BALANCE_FOR_WITHDRAWAL', + InvalidJump = 'INVALID_JUMP', + OutOfGas = 'OUT_OF_GAS', + SubscriptionNotFound = 'SUBSCRIPTION_NOT_FOUND', + SubscriptionAlreadyPresent = 'SUBSCRIPTION_ALREADY_PRESENT', + ERC721OwnerNotFound = 'ERC_721_OWNER_NOT_FOUND', + ERC721NoApproval = 'ERC_721_NO_APPROVAL', + SignatureRequestDenied = 'SIGNATURE_REQUEST_DENIED', +} -import { constants } from './constants'; +export type AsyncMethod = (...args: any[]) => Promise; +export type SyncMethod = (...args: any[]) => any; + +const constants = { + INVALID_JUMP_PATTERN: 'invalid JUMP at', + REVERT: 'revert', + OUT_OF_GAS_PATTERN: 'out of gas', + INVALID_TAKER_FORMAT: 'instance.taker is not of a type(s) string', + METAMASK_USER_DENIED_SIGNATURE_PATTERN: 'User denied transaction signature', + TRUST_WALLET_USER_DENIED_SIGNATURE_PATTERN: 'cancelled', +}; type ErrorTransformer = (err: Error) => Error; const contractCallErrorTransformer = (error: Error) => { if (_.includes(error.message, constants.INVALID_JUMP_PATTERN)) { - return new Error(ContractWrappersError.InvalidJump); + return new Error(ContractError.InvalidJump); } if (_.includes(error.message, constants.OUT_OF_GAS_PATTERN)) { - return new Error(ContractWrappersError.OutOfGas); + return new Error(ContractError.OutOfGas); } if (_.includes(error.message, constants.REVERT)) { const revertReason = error.message.split(constants.REVERT)[1].trim(); @@ -34,7 +57,7 @@ const signatureRequestErrorTransformer = (error: Error) => { _.includes(error.message, constants.METAMASK_USER_DENIED_SIGNATURE_PATTERN) || _.includes(error.message, constants.TRUST_WALLET_USER_DENIED_SIGNATURE_PATTERN) ) { - const errMsg = ContractWrappersError.SignatureRequestDenied; + const errMsg = ContractError.SignatureRequestDenied; return new Error(errMsg); } return error; diff --git a/packages/contract-wrappers/src/utils/getAbiEncodedTransactionData.ts b/packages/contract-wrappers/src/utils/getAbiEncodedTransactionData.ts new file mode 100644 index 0000000000..5ef476d49f --- /dev/null +++ b/packages/contract-wrappers/src/utils/getAbiEncodedTransactionData.ts @@ -0,0 +1,24 @@ +import { ExchangeContract } from '../index'; + +/** + * Returns the ABI encoded transaction hash for a given method and arguments + * @param methodName Must be a valid name of a function in the Solidity Exchange Contract + * @param params The appropriate arguments for the method given, in order + */ +export function getAbiEncodedTransactionData( + contractInstance: ExchangeContract, + methodName: K, + ...params: any[] // tslint:disable-line:trailing-comma +): string { + // HACK (xianny): we haven't formalised contract method functions into a type interface, and would have to + // differentiate contract method members from other class members to get this to work non-hackily + const method = (contractInstance[methodName] as any) as { + getABIEncodedTransactionData: (...args: any[]) => string; + }; + if (method.getABIEncodedTransactionData) { + const abiEncodedData = method.getABIEncodedTransactionData(...params); + return abiEncodedData; + } else { + return ''; + } +} diff --git a/packages/contract-wrappers/src/utils/transaction_encoder.ts b/packages/contract-wrappers/src/utils/transaction_encoder.ts deleted file mode 100644 index 6612503ea8..0000000000 --- a/packages/contract-wrappers/src/utils/transaction_encoder.ts +++ /dev/null @@ -1,303 +0,0 @@ -import { ExchangeContract } from '@0x/abi-gen-wrappers'; - -import { schemas } from '@0x/json-schemas'; -import { transactionHashUtils } from '@0x/order-utils'; -import { Order, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import _ = require('lodash'); - -import { assert } from './assert'; - -/** - * Transaction Encoder. Transaction messages exist for the purpose of calling methods on the Exchange contract - * in the context of another address. For example, UserA can encode and sign a fillOrder transaction and UserB - * can submit this to the blockchain. The Exchange context executes as if UserA had directly submitted this transaction. - */ -export class TransactionEncoder { - private readonly _exchangeInstance: ExchangeContract; - private readonly _chainId: number; - - constructor(exchangeInstance: ExchangeContract, chainId: number) { - this._exchangeInstance = exchangeInstance; - this._chainId = chainId; - } - /** - * Hashes the transaction data for use with the Exchange contract. - * @param data The ABI Encoded 0x Exchange method. I.e fillOrder - * @param salt A random value to provide uniqueness and prevent replay attacks. - * @param signerAddress The address which will sign this transaction. - * @return The hash of the 0x transaction. - */ - public getTransactionHashHex(data: string, salt: BigNumber, signerAddress: string): string { - const exchangeAddress = this._getExchangeContract().address; - const transaction = { - salt, - signerAddress, - data, - domain: { - verifyingContractAddress: exchangeAddress, - chainId: this._chainId, - }, - }; - const hashHex = transactionHashUtils.getTransactionHashHex(transaction); - return hashHex; - } - /** - * Encodes a fillOrder transaction. - * @param signedOrder An object that conforms to the SignedOrder interface. - * @param takerAssetFillAmount The amount of the order (in taker asset baseUnits) that you wish to fill. - * @return Hex encoded abi of the function call. - */ - public fillOrderTx(signedOrder: SignedOrder, takerAssetFillAmount: BigNumber): string { - assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); - assert.isValidBaseUnitAmount('takerAssetFillAmount', takerAssetFillAmount); - const abiEncodedData = this._getExchangeContract().fillOrder.getABIEncodedTransactionData( - signedOrder, - takerAssetFillAmount, - signedOrder.signature, - ); - return abiEncodedData; - } - /** - * Encodes a fillOrderNoThrow transaction. - * @param signedOrder An object that conforms to the SignedOrder interface. - * @param takerAssetFillAmount The amount of the order (in taker asset baseUnits) that you wish to fill. - * @return Hex encoded abi of the function call. - */ - public fillOrderNoThrowTx(signedOrder: SignedOrder, takerAssetFillAmount: BigNumber): string { - assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); - assert.isValidBaseUnitAmount('takerAssetFillAmount', takerAssetFillAmount); - const abiEncodedData = this._getExchangeContract().fillOrderNoThrow.getABIEncodedTransactionData( - signedOrder, - takerAssetFillAmount, - signedOrder.signature, - ); - return abiEncodedData; - } - /** - * Encodes a fillOrKillOrder transaction. - * @param signedOrder An object that conforms to the SignedOrder interface. - * @param takerAssetFillAmount The amount of the order (in taker asset baseUnits) that you wish to fill. - * @return Hex encoded abi of the function call. - */ - public fillOrKillOrderTx(signedOrder: SignedOrder, takerAssetFillAmount: BigNumber): string { - assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); - assert.isValidBaseUnitAmount('takerAssetFillAmount', takerAssetFillAmount); - const abiEncodedData = this._getExchangeContract().fillOrKillOrder.getABIEncodedTransactionData( - signedOrder, - takerAssetFillAmount, - signedOrder.signature, - ); - return abiEncodedData; - } - /** - * Encodes a batchFillOrders transaction. - * @param signedOrders An array of signed orders to fill. - * @param takerAssetFillAmounts The amounts of the orders (in taker asset baseUnits) that you wish to fill. - * @return Hex encoded abi of the function call. - */ - public batchFillOrdersTx(signedOrders: SignedOrder[], takerAssetFillAmounts: BigNumber[]): string { - assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); - _.forEach(takerAssetFillAmounts, takerAssetFillAmount => - assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount), - ); - const signatures = _.map(signedOrders, signedOrder => signedOrder.signature); - const abiEncodedData = this._getExchangeContract().batchFillOrders.getABIEncodedTransactionData( - signedOrders, - takerAssetFillAmounts, - signatures, - ); - return abiEncodedData; - } - /** - * Encodes a batchFillOrKillOrders transaction. - * @param signedOrders An array of signed orders to fill. - * @param takerAssetFillAmounts The amounts of the orders (in taker asset baseUnits) that you wish to fill. - * @return Hex encoded abi of the function call. - */ - public batchFillOrKillOrdersTx(signedOrders: SignedOrder[], takerAssetFillAmounts: BigNumber[]): string { - assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); - _.forEach(takerAssetFillAmounts, takerAssetFillAmount => - assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount), - ); - const signatures = _.map(signedOrders, signedOrder => signedOrder.signature); - const abiEncodedData = this._getExchangeContract().batchFillOrKillOrders.getABIEncodedTransactionData( - signedOrders, - takerAssetFillAmounts, - signatures, - ); - return abiEncodedData; - } - /** - * Encodes a batchFillOrdersNoThrow transaction. - * @param signedOrders An array of signed orders to fill. - * @param takerAssetFillAmounts The amounts of the orders (in taker asset baseUnits) that you wish to fill. - * @return Hex encoded abi of the function call. - */ - public batchFillOrdersNoThrowTx(signedOrders: SignedOrder[], takerAssetFillAmounts: BigNumber[]): string { - assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); - _.forEach(takerAssetFillAmounts, takerAssetFillAmount => - assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount), - ); - const signatures = _.map(signedOrders, signedOrder => signedOrder.signature); - const abiEncodedData = this._getExchangeContract().batchFillOrdersNoThrow.getABIEncodedTransactionData( - signedOrders, - takerAssetFillAmounts, - signatures, - ); - return abiEncodedData; - } - /** - * Encodes a batchCancelOrders transaction. - * @param signedOrders An array of orders to cancel. - * @return Hex encoded abi of the function call. - */ - public batchCancelOrdersTx(signedOrders: SignedOrder[]): string { - assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); - const abiEncodedData = this._getExchangeContract().batchCancelOrders.getABIEncodedTransactionData(signedOrders); - return abiEncodedData; - } - /** - * Encodes a cancelOrdersUpTo transaction. - * @param targetOrderEpoch Target order epoch. - * @return Hex encoded abi of the function call. - */ - public cancelOrdersUpToTx(targetOrderEpoch: BigNumber): string { - assert.isBigNumber('targetOrderEpoch', targetOrderEpoch); - const abiEncodedData = this._getExchangeContract().cancelOrdersUpTo.getABIEncodedTransactionData( - targetOrderEpoch, - ); - return abiEncodedData; - } - /** - * Encodes a cancelOrder transaction. - * @param order An object that conforms to the Order or SignedOrder interface. The order you would like to cancel. - * @return Hex encoded abi of the function call. - */ - public cancelOrderTx(order: Order | SignedOrder): string { - assert.doesConformToSchema('order', order, schemas.orderSchema); - const abiEncodedData = this._getExchangeContract().cancelOrder.getABIEncodedTransactionData(order); - return abiEncodedData; - } - /** - * Encodes a marketSellOrders transaction. - * @param signedOrders An array of signed orders to fill. - * @param takerAssetFillAmount Taker asset fill amount. - * @return Hex encoded abi of the function call. - */ - public marketSellOrdersTx(signedOrders: SignedOrder[], takerAssetFillAmount: BigNumber): string { - assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); - assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount); - const signatures = _.map(signedOrders, signedOrder => signedOrder.signature); - const abiEncodedData = this._getExchangeContract().marketSellOrders.getABIEncodedTransactionData( - signedOrders, - takerAssetFillAmount, - signatures, - ); - return abiEncodedData; - } - /** - * Encodes a marketSellOrdersNoThrow transaction. - * @param signedOrders An array of signed orders to fill. - * @param takerAssetFillAmount Taker asset fill amount. - * @return Hex encoded abi of the function call. - */ - public marketSellOrdersNoThrowTx(signedOrders: SignedOrder[], takerAssetFillAmount: BigNumber): string { - assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); - assert.isBigNumber('takerAssetFillAmount', takerAssetFillAmount); - const signatures = _.map(signedOrders, signedOrder => signedOrder.signature); - const abiEncodedData = this._getExchangeContract().marketSellOrdersNoThrow.getABIEncodedTransactionData( - signedOrders, - takerAssetFillAmount, - signatures, - ); - return abiEncodedData; - } - /** - * Encodes a maketBuyOrders transaction. - * @param signedOrders An array of signed orders to fill. - * @param makerAssetFillAmount Maker asset fill amount. - * @return Hex encoded abi of the function call. - */ - public marketBuyOrdersTx(signedOrders: SignedOrder[], makerAssetFillAmount: BigNumber): string { - assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); - assert.isBigNumber('makerAssetFillAmount', makerAssetFillAmount); - const signatures = _.map(signedOrders, signedOrder => signedOrder.signature); - const abiEncodedData = this._getExchangeContract().marketBuyOrders.getABIEncodedTransactionData( - signedOrders, - makerAssetFillAmount, - signatures, - ); - return abiEncodedData; - } - /** - * Encodes a maketBuyOrdersNoThrow transaction. - * @param signedOrders An array of signed orders to fill. - * @param makerAssetFillAmount Maker asset fill amount. - * @return Hex encoded abi of the function call. - */ - public marketBuyOrdersNoThrowTx(signedOrders: SignedOrder[], makerAssetFillAmount: BigNumber): string { - assert.doesConformToSchema('signedOrders', signedOrders, schemas.signedOrdersSchema); - assert.isBigNumber('makerAssetFillAmount', makerAssetFillAmount); - const signatures = _.map(signedOrders, signedOrder => signedOrder.signature); - const abiEncodedData = this._getExchangeContract().marketBuyOrdersNoThrow.getABIEncodedTransactionData( - signedOrders, - makerAssetFillAmount, - signatures, - ); - return abiEncodedData; - } - /** - * Encodes a matchOrders transaction. - * @param leftOrder First order to match. - * @param rightOrder Second order to match. - * @return Hex encoded abi of the function call. - */ - public matchOrdersTx(leftOrder: SignedOrder, rightOrder: SignedOrder): string { - assert.doesConformToSchema('leftOrder', leftOrder, schemas.orderSchema); - assert.doesConformToSchema('rightOrder', rightOrder, schemas.orderSchema); - const abiEncodedData = this._getExchangeContract().matchOrders.getABIEncodedTransactionData( - leftOrder, - rightOrder, - leftOrder.signature, - rightOrder.signature, - ); - return abiEncodedData; - } - /** - * Encodes a preSign transaction. - * @param hash Hash to pre-sign - * @param signerAddress Address that should have signed the given hash. - * @param signature Proof that the hash has been signed by signer. - * @return Hex encoded abi of the function call. - */ - public preSignTx(hash: string, signerAddress: string, signature: string): string { - assert.isHexString('hash', hash); - assert.isETHAddressHex('signerAddress', signerAddress); - assert.isHexString('signature', signature); - const abiEncodedData = this._getExchangeContract().preSign.getABIEncodedTransactionData( - hash, - signerAddress, - signature, - ); - return abiEncodedData; - } - /** - * Encodes a setSignatureValidatorApproval transaction. - * @param validatorAddress Validator contract address. - * @param isApproved Boolean value to set approval to. - * @return Hex encoded abi of the function call. - */ - public setSignatureValidatorApprovalTx(validatorAddress: string, isApproved: boolean): string { - assert.isETHAddressHex('validatorAddress', validatorAddress); - assert.isBoolean('isApproved', isApproved); - const abiEncodedData = this._getExchangeContract().setSignatureValidatorApproval.getABIEncodedTransactionData( - validatorAddress, - isApproved, - ); - return abiEncodedData; - } - private _getExchangeContract(): ExchangeContract { - return this._exchangeInstance; - } -} diff --git a/packages/contract-wrappers/src/utils/utils.ts b/packages/contract-wrappers/src/utils/utils.ts deleted file mode 100644 index ab69385e7a..0000000000 --- a/packages/contract-wrappers/src/utils/utils.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as _ from 'lodash'; - -import { constants } from './constants'; - -export const utils = { - getCurrentUnixTimestampSec(): BigNumber { - const milisecondsInSecond = 1000; - return new BigNumber(Date.now() / milisecondsInSecond).integerValue(); - }, - getCurrentUnixTimestampMs(): BigNumber { - return new BigNumber(Date.now()); - }, - numberPercentageToEtherTokenAmountPercentage(percentage: number): BigNumber { - return Web3Wrapper.toBaseUnitAmount(constants.ONE_AMOUNT, constants.ETHER_TOKEN_DECIMALS).multipliedBy( - percentage, - ); - }, - removeUndefinedProperties(obj: T): Partial { - return _.pickBy(obj); - }, -}; diff --git a/packages/contract-wrappers/test/calldata_decoder_test.ts b/packages/contract-wrappers/test/calldata_decoder_test.ts index 180c157ef6..0c59235734 100644 --- a/packages/contract-wrappers/test/calldata_decoder_test.ts +++ b/packages/contract-wrappers/test/calldata_decoder_test.ts @@ -8,6 +8,7 @@ import * as _ from 'lodash'; import 'mocha'; import { ContractAddresses, ContractWrappers } from '../src'; +import { getAbiEncodedTransactionData } from '../src/utils/getAbiEncodedTransactionData'; import { chaiSetup } from './utils/chai_setup'; import { migrateOnceAsync } from './utils/migrate'; @@ -85,8 +86,14 @@ describe('ABI Decoding Calldata', () => { blockPollingIntervalMs: 10, }; contractWrappers = new ContractWrappers(provider, config); - const transactionEncoder = await contractWrappers.exchange.transactionEncoderAsync(); - matchOrdersTxData = transactionEncoder.matchOrdersTx(signedOrderLeft, signedOrderRight); + matchOrdersTxData = getAbiEncodedTransactionData( + contractWrappers.exchange, + 'matchOrders', + signedOrderLeft, + signedOrderRight, + signedOrderLeft.signature, + signedOrderRight.signature, + ); }); describe('decode', () => { diff --git a/packages/contract-wrappers/test/calldata_optimization_utils_test.ts b/packages/contract-wrappers/test/calldata_optimization_utils_test.ts deleted file mode 100644 index 70430ed81c..0000000000 --- a/packages/contract-wrappers/test/calldata_optimization_utils_test.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { orderFactory } from '@0x/order-utils/lib/src/order_factory'; -import * as chai from 'chai'; -import * as _ from 'lodash'; -import 'mocha'; - -import { calldataOptimizationUtils } from '../src/utils/calldata_optimization_utils'; -import { constants } from '../src/utils/constants'; - -import { chaiSetup } from './utils/chai_setup'; - -chaiSetup.configure(); -const expect = chai.expect; - -// utility for generating a set of order objects with mostly NULL values -// except for a specified makerAssetData and takerAssetData -const FAKE_ORDERS_COUNT = 5; -const CHAIN_ID = 1337; -const generateFakeOrders = (makerAssetData: string, takerAssetData: string) => - _.map(_.range(FAKE_ORDERS_COUNT), () => { - const order = orderFactory.createOrder( - constants.NULL_ADDRESS, - constants.ZERO_AMOUNT, - makerAssetData, - constants.ZERO_AMOUNT, - takerAssetData, - constants.NULL_ADDRESS, - CHAIN_ID, - ); - return { - ...order, - signature: 'dummy signature', - }; - }); - -describe('calldataOptimizationUtils', () => { - const fakeMakerAssetData = 'fakeMakerAssetData'; - const fakeTakerAssetData = 'fakeTakerAssetData'; - const orders = generateFakeOrders(fakeMakerAssetData, fakeTakerAssetData); - describe('#optimizeForwarderOrders', () => { - it('should make makerAssetData `0x` unless first order', () => { - const optimizedOrders = calldataOptimizationUtils.optimizeForwarderOrders(orders); - expect(optimizedOrders[0].makerAssetData).to.equal(fakeMakerAssetData); - const ordersWithoutHead = _.slice(optimizedOrders, 1); - _.forEach(ordersWithoutHead, order => expect(order.makerAssetData).to.equal(constants.NULL_BYTES)); - }); - it('should make all takerAssetData `0x`', () => { - const optimizedOrders = calldataOptimizationUtils.optimizeForwarderOrders(orders); - _.forEach(optimizedOrders, order => expect(order.takerAssetData).to.equal(constants.NULL_BYTES)); - }); - }); - describe('#optimizeForwarderFeeOrders', () => { - it('should make all makerAssetData `0x`', () => { - const optimizedOrders = calldataOptimizationUtils.optimizeForwarderFeeOrders(orders); - _.forEach(optimizedOrders, order => expect(order.makerAssetData).to.equal(constants.NULL_BYTES)); - }); - it('should make all takerAssetData `0x`', () => { - const optimizedOrders = calldataOptimizationUtils.optimizeForwarderFeeOrders(orders); - _.forEach(optimizedOrders, order => expect(order.takerAssetData).to.equal(constants.NULL_BYTES)); - }); - }); -}); diff --git a/packages/contract-wrappers/test/coordinator_wrapper_test.ts b/packages/contract-wrappers/test/coordinator_wrapper_test.ts index 6783cc0c41..573b943b3e 100644 --- a/packages/contract-wrappers/test/coordinator_wrapper_test.ts +++ b/packages/contract-wrappers/test/coordinator_wrapper_test.ts @@ -1,7 +1,6 @@ -import { CoordinatorRegistryContract } from '@0x/abi-gen-wrappers'; import { constants } from '@0x/contracts-test-utils'; import { defaultOrmConfig, getAppAsync } from '@0x/coordinator-server'; -import { BlockchainLifecycle } from '@0x/dev-utils'; +import { BlockchainLifecycle, tokenUtils } from '@0x/dev-utils'; import { FillScenarios } from '@0x/fill-scenarios'; import { assetDataUtils } from '@0x/order-utils'; import { SignedOrder } from '@0x/types'; @@ -12,11 +11,11 @@ import 'mocha'; import * as nock from 'nock'; import { ContractWrappers } from '../src'; +import { CoordinatorRegistryContract } from '../src/index'; import { CoordinatorServerErrorMsg } from '../src/utils/coordinator_server_types'; import { chaiSetup } from './utils/chai_setup'; import { migrateOnceAsync } from './utils/migrate'; -import { tokenUtils } from './utils/token_utils'; import { provider, web3Wrapper } from './utils/web3_wrapper'; chaiSetup.configure(); @@ -71,7 +70,7 @@ describe('CoordinatorWrapper', () => { contractWrappers = new ContractWrappers(provider, config); exchangeContractAddress = contractWrappers.exchange.address; userAddresses = await web3Wrapper.getAvailableAddressesAsync(); - zrxTokenAddress = contractWrappers.exchange.zrxTokenAddress; + zrxTokenAddress = contractAddresses.zrxToken; fillScenarios = new FillScenarios( provider, userAddresses, @@ -99,7 +98,7 @@ describe('CoordinatorWrapper', () => { const coordinatorServerConfigs = { HTTP_PORT: 3000, // Only used in default instantiation in 0x-coordinator-server/server.js; not used here NETWORK_ID_TO_SETTINGS: { - 50: { + [config.networkId]: { FEE_RECIPIENTS: [ { ADDRESS: feeRecipientAddressOne, @@ -125,6 +124,9 @@ describe('CoordinatorWrapper', () => { RPC_URL: 'http://ignore', }, }, + NETWORK_ID_TO_CONTRACT_ADDRESSES: { + [config.networkId]: contractAddresses, + }, // Optional selective delay on fill requests SELECTIVE_DELAY_MS: 0, EXPIRATION_DURATION_SECONDS: 60, // 1 minute @@ -134,7 +136,15 @@ describe('CoordinatorWrapper', () => { [config.networkId]: provider, }, coordinatorServerConfigs, - defaultOrmConfig, + { + name: 'coord_server_1', + type: 'sqlite', + database: ':memory:', + entities: defaultOrmConfig.entities, + cli: defaultOrmConfig.cli, + logging: defaultOrmConfig.logging, + synchronize: defaultOrmConfig.synchronize, + }, ); coordinatorServerApp.listen(coordinatorPort, () => { @@ -148,7 +158,8 @@ describe('CoordinatorWrapper', () => { coordinatorServerConfigs, { type: 'sqlite', - database: 'database.sqlite_2', + name: 'coord_server_2', + database: ':memory:', entities: defaultOrmConfig.entities, cli: defaultOrmConfig.cli, logging: defaultOrmConfig.logging, @@ -410,7 +421,7 @@ describe('CoordinatorWrapper', () => { txHash = await contractWrappers.coordinator.hardCancelOrdersUpToAsync(targetOrderEpoch, makerAddress); await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const orderEpoch = await contractWrappers.exchange.getOrderEpochAsync( + const orderEpoch = await contractWrappers.exchange.orderEpoch.callAsync( makerAddress, contractWrappers.coordinator.address, ); diff --git a/packages/contract-wrappers/test/dutch_auction_wrapper_test.ts b/packages/contract-wrappers/test/dutch_auction_wrapper_test.ts deleted file mode 100644 index 15936a2eed..0000000000 --- a/packages/contract-wrappers/test/dutch_auction_wrapper_test.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { expectTransactionFailedAsync, getLatestBlockTimestampAsync } from '@0x/contracts-test-utils'; -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { assetDataUtils } from '@0x/order-utils'; -import { ERC20AssetData, RevertReason, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as chai from 'chai'; -import 'mocha'; - -import { ContractWrappers, DutchAuctionWrapper } from '../src'; - -import { chaiSetup } from './utils/chai_setup'; -import { constants } from './utils/constants'; -import { DutchAuctionUtils } from './utils/dutch_auction_utils'; -import { migrateOnceAsync } from './utils/migrate'; -import { tokenUtils } from './utils/token_utils'; -import { provider, web3Wrapper } from './utils/web3_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -// tslint:disable:custom-no-magic-numbers -describe('DutchAuctionWrapper', () => { - const makerAssetAmount = new BigNumber(5); - const auctionEndTakerAmount = new BigNumber(10); - const auctionBeginTakerAmount = auctionEndTakerAmount.times(2); - const tenMinutesInSeconds = 10 * 60; - let contractWrappers: ContractWrappers; - let exchangeContractAddress: string; - let userAddresses: string[]; - let makerAddress: string; - let takerAddress: string; - let makerTokenAddress: string; - let takerTokenAddress: string; - let buyOrder: SignedOrder; - let sellOrder: SignedOrder; - let makerTokenAssetData: string; - let takerTokenAssetData: string; - let auctionBeginTimeSeconds: BigNumber; - let auctionEndTimeSeconds: BigNumber; - before(async () => { - // setup contract wrappers & addresses - const contractAddresses = await migrateOnceAsync(); - await blockchainLifecycle.startAsync(); - const config = { - networkId: constants.TESTRPC_NETWORK_ID, - contractAddresses, - blockPollingIntervalMs: 10, - }; - contractWrappers = new ContractWrappers(provider, config); - exchangeContractAddress = contractWrappers.exchange.address; - userAddresses = await web3Wrapper.getAvailableAddressesAsync(); - [, makerAddress, takerAddress] = userAddresses; - [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); - // construct asset data for tokens being swapped - [makerTokenAssetData, takerTokenAssetData] = [ - assetDataUtils.encodeERC20AssetData(makerTokenAddress), - assetDataUtils.encodeERC20AssetData(takerTokenAddress), - ]; - // setup auction details in maker asset data - const currentBlockTimestamp: number = await getLatestBlockTimestampAsync(); - auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds); - auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp + tenMinutesInSeconds); - // create auction orders - const coinbase = userAddresses[0]; - const dutchAuctionUtils = new DutchAuctionUtils( - web3Wrapper, - coinbase, - exchangeContractAddress, - contractWrappers.erc20Proxy.address, - ); - sellOrder = await dutchAuctionUtils.createSignedSellOrderAsync( - auctionBeginTimeSeconds, - auctionEndTimeSeconds, - auctionBeginTakerAmount, - auctionEndTakerAmount, - makerAssetAmount, - makerTokenAssetData, - takerTokenAssetData, - makerAddress, - constants.NULL_ADDRESS, - ); - buyOrder = await dutchAuctionUtils.createSignedBuyOrderAsync(sellOrder, takerAddress); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - describe('.decodeDutchAuctionAssetData', () => { - it('decodes to the encoded values', async () => { - const encodedAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData( - makerTokenAssetData, - auctionBeginTimeSeconds, - makerAssetAmount, - ); - const decodedAssetData = DutchAuctionWrapper.decodeDutchAuctionData(encodedAssetData); - // tslint:disable-next-line:no-unnecessary-type-assertion - const erc20AssetData = decodedAssetData.assetData as ERC20AssetData; - expect(erc20AssetData.tokenAddress).to.eq(makerTokenAddress); - expect(decodedAssetData.beginAmount).to.be.bignumber.eq(makerAssetAmount); - expect(decodedAssetData.beginTimeSeconds).to.be.bignumber.eq(auctionBeginTimeSeconds); - }); - }); - describe('#matchOrdersAsync', () => { - it('should match two orders', async () => { - const txHash = await contractWrappers.dutchAuction.matchOrdersAsync(buyOrder, sellOrder, takerAddress); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - }); - it('should throw when invalid transaction and shouldValidate is true', async () => { - // request match with bad buy/sell orders - const badSellOrder = buyOrder; - const badBuyOrder = sellOrder; - return expectTransactionFailedAsync( - contractWrappers.dutchAuction.matchOrdersAsync(badBuyOrder, badSellOrder, takerAddress, { - shouldValidate: true, - }), - RevertReason.InvalidAssetData, - ); - }); - }); - - describe('#getAuctionDetailsAsync', () => { - it('should get auction details', async () => { - // get auction details - const auctionDetails = await contractWrappers.dutchAuction.getAuctionDetailsAsync(sellOrder); - // run some basic sanity checks on the return value - expect(auctionDetails.beginTimeSeconds, 'auctionDetails.beginTimeSeconds').to.be.bignumber.equal( - auctionBeginTimeSeconds, - ); - expect(auctionDetails.beginAmount, 'auctionDetails.beginAmount').to.be.bignumber.equal( - auctionBeginTakerAmount, - ); - expect(auctionDetails.endTimeSeconds, 'auctionDetails.endTimeSeconds').to.be.bignumber.equal( - auctionEndTimeSeconds, - ); - }); - }); -}); diff --git a/packages/contract-wrappers/test/erc20_proxy_wrapper_test.ts b/packages/contract-wrappers/test/erc20_proxy_wrapper_test.ts deleted file mode 100644 index d8dfa42047..0000000000 --- a/packages/contract-wrappers/test/erc20_proxy_wrapper_test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import * as chai from 'chai'; - -import { ContractWrappers } from '../src'; - -import { chaiSetup } from './utils/chai_setup'; -import { constants } from './utils/constants'; -import { migrateOnceAsync } from './utils/migrate'; -import { provider } from './utils/web3_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; - -describe('ERC20ProxyWrapper', () => { - let contractWrappers: ContractWrappers; - before(async () => { - const contractAddresses = await migrateOnceAsync(); - const config = { - networkId: constants.TESTRPC_NETWORK_ID, - contractAddresses, - blockPollingIntervalMs: 10, - }; - contractWrappers = new ContractWrappers(provider, config); - }); - describe('#isAuthorizedAsync', () => { - it('should return false if the address is not authorized', async () => { - const isAuthorized = await contractWrappers.erc20Proxy.isAuthorizedAsync(constants.NULL_ADDRESS); - expect(isAuthorized).to.be.false(); - }); - }); - describe('#getAuthorizedAddressesAsync', () => { - it('should return the list of authorized addresses', async () => { - const authorizedAddresses = await contractWrappers.erc20Proxy.getAuthorizedAddressesAsync(); - for (const authorizedAddress of authorizedAddresses) { - const isAuthorized = await contractWrappers.erc20Proxy.isAuthorizedAsync(authorizedAddress); - expect(isAuthorized).to.be.true(); - } - }); - }); -}); diff --git a/packages/contract-wrappers/test/erc20_wrapper_test.ts b/packages/contract-wrappers/test/erc20_wrapper_test.ts deleted file mode 100644 index bfbb2196d6..0000000000 --- a/packages/contract-wrappers/test/erc20_wrapper_test.ts +++ /dev/null @@ -1,633 +0,0 @@ -import { ContractAddresses } from '@0x/contract-addresses'; -import { BlockchainLifecycle, callbackErrorReporter } from '@0x/dev-utils'; -import { EmptyWalletSubprovider, Web3ProviderEngine } from '@0x/subproviders'; -import { DoneCallback } from '@0x/types'; -import { BigNumber, providerUtils } from '@0x/utils'; -import * as chai from 'chai'; -import 'mocha'; - -import { - BlockParamLiteral, - BlockRange, - ContractWrappers, - ContractWrappersConfig, - ContractWrappersError, - DecodedLogEvent, - ERC20TokenApprovalEventArgs, - ERC20TokenEvents, - ERC20TokenTransferEventArgs, -} from '../src'; - -import { chaiSetup } from './utils/chai_setup'; -import { constants } from './utils/constants'; -import { migrateOnceAsync } from './utils/migrate'; -import { tokenUtils } from './utils/token_utils'; -import { provider, web3Wrapper } from './utils/web3_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -describe('ERC20Wrapper', () => { - let contractWrappers: ContractWrappers; - let contractAddresses: ContractAddresses; - let userAddresses: string[]; - let tokens: string[]; - let coinbase: string; - let addressWithoutFunds: string; - let config: ContractWrappersConfig; - - before(async () => { - contractAddresses = await migrateOnceAsync(); - config = { - networkId: constants.TESTRPC_NETWORK_ID, - contractAddresses, - blockPollingIntervalMs: 10, - }; - contractWrappers = new ContractWrappers(provider, config); - userAddresses = await web3Wrapper.getAvailableAddressesAsync(); - tokens = tokenUtils.getDummyERC20TokenAddresses(); - coinbase = userAddresses[0]; - addressWithoutFunds = userAddresses[1]; - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - describe('#transferAsync', () => { - let tokenAddress: string; - let transferAmount: BigNumber; - before(() => { - tokenAddress = tokens[0]; - transferAmount = new BigNumber(42); - }); - it('should successfully transfer tokens', async () => { - const fromAddress = coinbase; - const toAddress = addressWithoutFunds; - const preBalance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, toAddress); - expect(preBalance).to.be.bignumber.equal(0); - await contractWrappers.erc20Token.transferAsync(tokenAddress, fromAddress, toAddress, transferAmount); - const postBalance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, toAddress); - return expect(postBalance).to.be.bignumber.equal(transferAmount); - }); - it('should fail to transfer tokens if fromAddress has an insufficient balance', async () => { - const fromAddress = addressWithoutFunds; - const toAddress = coinbase; - return expect( - contractWrappers.erc20Token.transferAsync(tokenAddress, fromAddress, toAddress, transferAmount), - ).to.be.rejectedWith(ContractWrappersError.InsufficientBalanceForTransfer); - }); - }); - describe('#transferFromAsync', () => { - let tokenAddress: string; - let toAddress: string; - let senderAddress: string; - before(async () => { - tokenAddress = tokens[0]; - toAddress = addressWithoutFunds; - senderAddress = userAddresses[2]; - }); - it('should fail to transfer tokens if fromAddress has insufficient allowance set', async () => { - const fromAddress = coinbase; - const transferAmount = new BigNumber(42); - - const fromAddressBalance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, fromAddress); - expect(fromAddressBalance).to.be.bignumber.greaterThan(transferAmount); - - const fromAddressAllowance = await contractWrappers.erc20Token.getAllowanceAsync( - tokenAddress, - fromAddress, - toAddress, - ); - expect(fromAddressAllowance).to.be.bignumber.equal(0); - - return expect( - contractWrappers.erc20Token.transferFromAsync( - tokenAddress, - fromAddress, - toAddress, - senderAddress, - transferAmount, - ), - ).to.be.rejectedWith(ContractWrappersError.InsufficientAllowanceForTransfer); - }); - it('[regression] should fail to transfer tokens if set allowance for toAddress instead of senderAddress', async () => { - const fromAddress = coinbase; - const transferAmount = new BigNumber(42); - - await contractWrappers.erc20Token.setAllowanceAsync(tokenAddress, fromAddress, toAddress, transferAmount); - - return expect( - contractWrappers.erc20Token.transferFromAsync( - tokenAddress, - fromAddress, - toAddress, - senderAddress, - transferAmount, - ), - ).to.be.rejectedWith(ContractWrappersError.InsufficientAllowanceForTransfer); - }); - it('should fail to transfer tokens if fromAddress has insufficient balance', async () => { - const fromAddress = addressWithoutFunds; - const transferAmount = new BigNumber(42); - - const fromAddressBalance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, fromAddress); - expect(fromAddressBalance).to.be.bignumber.equal(0); - - await contractWrappers.erc20Token.setAllowanceAsync( - tokenAddress, - fromAddress, - senderAddress, - transferAmount, - ); - const fromAddressAllowance = await contractWrappers.erc20Token.getAllowanceAsync( - tokenAddress, - fromAddress, - senderAddress, - ); - expect(fromAddressAllowance).to.be.bignumber.equal(transferAmount); - - return expect( - contractWrappers.erc20Token.transferFromAsync( - tokenAddress, - fromAddress, - toAddress, - senderAddress, - transferAmount, - ), - ).to.be.rejectedWith(ContractWrappersError.InsufficientBalanceForTransfer); - }); - it('should successfully transfer tokens', async () => { - const fromAddress = coinbase; - - const preBalance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, toAddress); - expect(preBalance).to.be.bignumber.equal(0); - - const transferAmount = new BigNumber(42); - await contractWrappers.erc20Token.setAllowanceAsync( - tokenAddress, - fromAddress, - senderAddress, - transferAmount, - ); - - await contractWrappers.erc20Token.transferFromAsync( - tokenAddress, - fromAddress, - toAddress, - senderAddress, - transferAmount, - ); - const postBalance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, toAddress); - return expect(postBalance).to.be.bignumber.equal(transferAmount); - }); - }); - describe('#getBalanceAsync', () => { - describe('With provider with accounts', () => { - it('should return the balance for an existing ERC20 token', async () => { - const tokenAddress = tokens[0]; - const ownerAddress = coinbase; - const balance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, ownerAddress); - const expectedBalance = new BigNumber('1000000000000000000000000000'); - return expect(balance).to.be.bignumber.equal(expectedBalance); - }); - it('should return a balance of 0 for a non-existent owner address', async () => { - const tokenAddress = tokens[0]; - const nonExistentOwner = '0x198c6ad858f213fb31b6fe809e25040e6b964593'; - const balance = await contractWrappers.erc20Token.getBalanceAsync(tokenAddress, nonExistentOwner); - const expectedBalance = new BigNumber(0); - return expect(balance).to.be.bignumber.equal(expectedBalance); - }); - }); - describe('With provider without accounts', () => { - let zeroExContractWithoutAccounts: ContractWrappers; - before(async () => { - const emptyWalletProvider = addEmptyWalletSubprovider(provider); - zeroExContractWithoutAccounts = new ContractWrappers(emptyWalletProvider, config); - }); - it('should return balance even when called with provider instance without addresses', async () => { - const tokenAddress = tokens[0]; - const ownerAddress = coinbase; - const balance = await zeroExContractWithoutAccounts.erc20Token.getBalanceAsync( - tokenAddress, - ownerAddress, - ); - const expectedBalance = new BigNumber('1000000000000000000000000000'); - return expect(balance).to.be.bignumber.equal(expectedBalance); - }); - }); - }); - describe('#setAllowanceAsync', () => { - it("should set the spender's allowance", async () => { - const tokenAddress = tokens[0]; - const ownerAddress = coinbase; - const spenderAddress = addressWithoutFunds; - - const allowanceBeforeSet = await contractWrappers.erc20Token.getAllowanceAsync( - tokenAddress, - ownerAddress, - spenderAddress, - ); - const expectedAllowanceBeforeAllowanceSet = new BigNumber(0); - expect(allowanceBeforeSet).to.be.bignumber.equal(expectedAllowanceBeforeAllowanceSet); - - const amountInBaseUnits = new BigNumber(50); - await contractWrappers.erc20Token.setAllowanceAsync( - tokenAddress, - ownerAddress, - spenderAddress, - amountInBaseUnits, - ); - - const allowanceAfterSet = await contractWrappers.erc20Token.getAllowanceAsync( - tokenAddress, - ownerAddress, - spenderAddress, - ); - const expectedAllowanceAfterAllowanceSet = amountInBaseUnits; - return expect(allowanceAfterSet).to.be.bignumber.equal(expectedAllowanceAfterAllowanceSet); - }); - }); - describe('#setUnlimitedAllowanceAsync', () => { - it("should set the unlimited spender's allowance", async () => { - const tokenAddress = tokens[0]; - const ownerAddress = coinbase; - const spenderAddress = addressWithoutFunds; - - await contractWrappers.erc20Token.setUnlimitedAllowanceAsync(tokenAddress, ownerAddress, spenderAddress); - const allowance = await contractWrappers.erc20Token.getAllowanceAsync( - tokenAddress, - ownerAddress, - spenderAddress, - ); - return expect(allowance).to.be.bignumber.equal( - contractWrappers.erc20Token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, - ); - }); - it('should reduce the gas cost for transfers including tokens with unlimited allowance support', async () => { - const transferAmount = new BigNumber(5); - const zrxAddress = contractAddresses.zrxToken; - const [, userWithNormalAllowance, userWithUnlimitedAllowance] = userAddresses; - await contractWrappers.erc20Token.setAllowanceAsync( - zrxAddress, - coinbase, - userWithNormalAllowance, - transferAmount, - ); - await contractWrappers.erc20Token.setUnlimitedAllowanceAsync( - zrxAddress, - coinbase, - userWithUnlimitedAllowance, - ); - - const initBalanceWithNormalAllowance = await web3Wrapper.getBalanceInWeiAsync(userWithNormalAllowance); - const initBalanceWithUnlimitedAllowance = await web3Wrapper.getBalanceInWeiAsync( - userWithUnlimitedAllowance, - ); - - await contractWrappers.erc20Token.transferFromAsync( - zrxAddress, - coinbase, - userWithNormalAllowance, - userWithNormalAllowance, - transferAmount, - ); - await contractWrappers.erc20Token.transferFromAsync( - zrxAddress, - coinbase, - userWithUnlimitedAllowance, - userWithUnlimitedAllowance, - transferAmount, - ); - - const finalBalanceWithNormalAllowance = await web3Wrapper.getBalanceInWeiAsync(userWithNormalAllowance); - const finalBalanceWithUnlimitedAllowance = await web3Wrapper.getBalanceInWeiAsync( - userWithUnlimitedAllowance, - ); - - const normalGasCost = initBalanceWithNormalAllowance.minus(finalBalanceWithNormalAllowance); - const unlimitedGasCost = initBalanceWithUnlimitedAllowance.minus(finalBalanceWithUnlimitedAllowance); - - // In theory the gas cost with unlimited allowance should be smaller, but with testrpc it's actually bigger. - // This needs to be investigated in ethereumjs-vm. This test is essentially a repro. - // TODO: Make this test pass with inverted assertion. - expect(unlimitedGasCost.toNumber()).to.be.gt(normalGasCost.toNumber()); - }); - }); - describe('#getAllowanceAsync', () => { - describe('With provider with accounts', () => { - it('should get the proxy allowance', async () => { - const tokenAddress = tokens[0]; - const ownerAddress = coinbase; - const spenderAddress = addressWithoutFunds; - - const amountInBaseUnits = new BigNumber(50); - await contractWrappers.erc20Token.setAllowanceAsync( - tokenAddress, - ownerAddress, - spenderAddress, - amountInBaseUnits, - ); - - const allowance = await contractWrappers.erc20Token.getAllowanceAsync( - tokenAddress, - ownerAddress, - spenderAddress, - ); - const expectedAllowance = amountInBaseUnits; - return expect(allowance).to.be.bignumber.equal(expectedAllowance); - }); - it('should return 0 if no allowance set yet', async () => { - const tokenAddress = tokens[0]; - const ownerAddress = coinbase; - const spenderAddress = addressWithoutFunds; - const allowance = await contractWrappers.erc20Token.getAllowanceAsync( - tokenAddress, - ownerAddress, - spenderAddress, - ); - const expectedAllowance = new BigNumber(0); - return expect(allowance).to.be.bignumber.equal(expectedAllowance); - }); - }); - describe('With provider without accounts', () => { - let zeroExContractWithoutAccounts: ContractWrappers; - before(async () => { - const emptyWalletProvider = addEmptyWalletSubprovider(provider); - zeroExContractWithoutAccounts = new ContractWrappers(emptyWalletProvider, config); - }); - it('should get the proxy allowance', async () => { - const tokenAddress = tokens[0]; - const ownerAddress = coinbase; - const spenderAddress = addressWithoutFunds; - - const amountInBaseUnits = new BigNumber(50); - await contractWrappers.erc20Token.setAllowanceAsync( - tokenAddress, - ownerAddress, - spenderAddress, - amountInBaseUnits, - ); - - const allowance = await zeroExContractWithoutAccounts.erc20Token.getAllowanceAsync( - tokenAddress, - ownerAddress, - spenderAddress, - ); - const expectedAllowance = amountInBaseUnits; - return expect(allowance).to.be.bignumber.equal(expectedAllowance); - }); - }); - }); - describe('#getProxyAllowanceAsync', () => { - it('should get the proxy allowance', async () => { - const tokenAddress = tokens[0]; - const ownerAddress = coinbase; - - const amountInBaseUnits = new BigNumber(50); - await contractWrappers.erc20Token.setProxyAllowanceAsync(tokenAddress, ownerAddress, amountInBaseUnits); - - const allowance = await contractWrappers.erc20Token.getProxyAllowanceAsync(tokenAddress, ownerAddress); - const expectedAllowance = amountInBaseUnits; - return expect(allowance).to.be.bignumber.equal(expectedAllowance); - }); - }); - describe('#setProxyAllowanceAsync', () => { - it('should set the proxy allowance', async () => { - const tokenAddress = tokens[0]; - const ownerAddress = coinbase; - - const allowanceBeforeSet = await contractWrappers.erc20Token.getProxyAllowanceAsync( - tokenAddress, - ownerAddress, - ); - const expectedAllowanceBeforeAllowanceSet = new BigNumber(0); - expect(allowanceBeforeSet).to.be.bignumber.equal(expectedAllowanceBeforeAllowanceSet); - - const amountInBaseUnits = new BigNumber(50); - await contractWrappers.erc20Token.setProxyAllowanceAsync(tokenAddress, ownerAddress, amountInBaseUnits); - - const allowanceAfterSet = await contractWrappers.erc20Token.getProxyAllowanceAsync( - tokenAddress, - ownerAddress, - ); - const expectedAllowanceAfterAllowanceSet = amountInBaseUnits; - return expect(allowanceAfterSet).to.be.bignumber.equal(expectedAllowanceAfterAllowanceSet); - }); - }); - describe('#setUnlimitedProxyAllowanceAsync', () => { - it('should set the unlimited proxy allowance', async () => { - const tokenAddress = tokens[0]; - const ownerAddress = coinbase; - - await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync(tokenAddress, ownerAddress); - const allowance = await contractWrappers.erc20Token.getProxyAllowanceAsync(tokenAddress, ownerAddress); - return expect(allowance).to.be.bignumber.equal( - contractWrappers.erc20Token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS, - ); - }); - }); - describe('#subscribe', () => { - const indexFilterValues = {}; - let tokenAddress: string; - const transferAmount = new BigNumber(42); - const allowanceAmount = new BigNumber(42); - before(() => { - tokenAddress = tokens[0]; - }); - afterEach(() => { - contractWrappers.erc20Token.unsubscribeAll(); - }); - // Hack: Mocha does not allow a test to be both async and have a `done` callback - // Since we need to await the receipt of the event in the `subscribe` callback, - // we do need both. A hack is to make the top-level a sync fn w/ a done callback and then - // wrap the rest of the test in an async block - // Source: https://github.com/mochajs/mocha/issues/2407 - it('Should receive the Transfer event when tokens are transfered', (done: DoneCallback) => { - (async () => { - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)( - (logEvent: DecodedLogEvent) => { - expect(logEvent.isRemoved).to.be.false(); - expect(logEvent.log.logIndex).to.be.equal(0); - expect(logEvent.log.transactionIndex).to.be.equal(0); - expect(logEvent.log.blockNumber).to.be.a('number'); - const args = logEvent.log.args; - expect(args._from).to.be.equal(coinbase); - expect(args._to).to.be.equal(addressWithoutFunds); - expect(args._value).to.be.bignumber.equal(transferAmount); - }, - ); - contractWrappers.erc20Token.subscribe( - tokenAddress, - ERC20TokenEvents.Transfer, - indexFilterValues, - callback, - ); - await contractWrappers.erc20Token.transferAsync( - tokenAddress, - coinbase, - addressWithoutFunds, - transferAmount, - ); - })().catch(done); - }); - it('Should receive the Approval event when allowance is being set', (done: DoneCallback) => { - (async () => { - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)( - (logEvent: DecodedLogEvent) => { - expect(logEvent).to.not.be.undefined(); - expect(logEvent.isRemoved).to.be.false(); - const args = logEvent.log.args; - expect(args._owner).to.be.equal(coinbase); - expect(args._spender).to.be.equal(addressWithoutFunds); - expect(args._value).to.be.bignumber.equal(allowanceAmount); - }, - ); - contractWrappers.erc20Token.subscribe( - tokenAddress, - ERC20TokenEvents.Approval, - indexFilterValues, - callback, - ); - await contractWrappers.erc20Token.setAllowanceAsync( - tokenAddress, - coinbase, - addressWithoutFunds, - allowanceAmount, - ); - })().catch(done); - }); - it('Outstanding subscriptions are cancelled when contractWrappers.unsubscribeAll called', (done: DoneCallback) => { - (async () => { - const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)( - (_logEvent: DecodedLogEvent) => { - done(new Error('Expected this subscription to have been cancelled')); - }, - ); - contractWrappers.erc20Token.subscribe( - tokenAddress, - ERC20TokenEvents.Transfer, - indexFilterValues, - callbackNeverToBeCalled, - ); - const callbackToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)(); - contractWrappers.unsubscribeAll(); - contractWrappers.erc20Token.subscribe( - tokenAddress, - ERC20TokenEvents.Transfer, - indexFilterValues, - callbackToBeCalled, - ); - await contractWrappers.erc20Token.transferAsync( - tokenAddress, - coinbase, - addressWithoutFunds, - transferAmount, - ); - })().catch(done); - }); - it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => { - (async () => { - const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)( - (_logEvent: DecodedLogEvent) => { - done(new Error('Expected this subscription to have been cancelled')); - }, - ); - const subscriptionToken = contractWrappers.erc20Token.subscribe( - tokenAddress, - ERC20TokenEvents.Transfer, - indexFilterValues, - callbackNeverToBeCalled, - ); - contractWrappers.erc20Token.unsubscribe(subscriptionToken); - await contractWrappers.erc20Token.transferAsync( - tokenAddress, - coinbase, - addressWithoutFunds, - transferAmount, - ); - done(); - })().catch(done); - }); - }); - describe('#getLogsAsync', () => { - let tokenAddress: string; - let tokenTransferProxyAddress: string; - const blockRange: BlockRange = { - fromBlock: 0, - toBlock: BlockParamLiteral.Latest, - }; - let txHash: string; - before(() => { - tokenAddress = tokens[0]; - tokenTransferProxyAddress = contractWrappers.erc20Proxy.address; - }); - it('should get logs with decoded args emitted by Approval', async () => { - txHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const eventName = ERC20TokenEvents.Approval; - const indexFilterValues = {}; - const logs = await contractWrappers.erc20Token.getLogsAsync( - tokenAddress, - eventName, - blockRange, - indexFilterValues, - ); - expect(logs).to.have.length(1); - const args = logs[0].args; - expect(logs[0].event).to.be.equal(eventName); - expect(args._owner).to.be.equal(coinbase); - expect(args._spender).to.be.equal(tokenTransferProxyAddress); - expect(args._value).to.be.bignumber.equal(contractWrappers.erc20Token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS); - }); - it('should only get the logs with the correct event name', async () => { - txHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const differentEventName = ERC20TokenEvents.Transfer; - const indexFilterValues = {}; - const logs = await contractWrappers.erc20Token.getLogsAsync( - tokenAddress, - differentEventName, - blockRange, - indexFilterValues, - ); - expect(logs).to.have.length(0); - }); - it('should only get the logs with the correct indexed fields', async () => { - txHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync(tokenAddress, coinbase); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - txHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync( - tokenAddress, - addressWithoutFunds, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const eventName = ERC20TokenEvents.Approval; - const indexFilterValues = { - _owner: coinbase, - }; - const logs = await contractWrappers.erc20Token.getLogsAsync( - tokenAddress, - eventName, - blockRange, - indexFilterValues, - ); - expect(logs).to.have.length(1); - const args = logs[0].args; - expect(args._owner).to.be.equal(coinbase); - }); - }); -}); -// tslint:disable:max-file-line-count - -function addEmptyWalletSubprovider(p: Web3ProviderEngine): Web3ProviderEngine { - const providerEngine = new Web3ProviderEngine(); - providerEngine.addProvider(new EmptyWalletSubprovider()); - const currentSubproviders = (p as any)._providers; - for (const subprovider of currentSubproviders) { - providerEngine.addProvider(subprovider); - } - providerUtils.startProviderEngine(providerEngine); - return providerEngine; -} diff --git a/packages/contract-wrappers/test/erc721_proxy_wrapper_test.ts b/packages/contract-wrappers/test/erc721_proxy_wrapper_test.ts deleted file mode 100644 index 9b0fe88172..0000000000 --- a/packages/contract-wrappers/test/erc721_proxy_wrapper_test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import * as chai from 'chai'; - -import { ContractWrappers } from '../src'; - -import { chaiSetup } from './utils/chai_setup'; -import { constants } from './utils/constants'; -import { migrateOnceAsync } from './utils/migrate'; -import { provider } from './utils/web3_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; - -describe('ERC721ProxyWrapper', () => { - let contractWrappers: ContractWrappers; - before(async () => { - const contractAddresses = await migrateOnceAsync(); - const config = { - networkId: constants.TESTRPC_NETWORK_ID, - contractAddresses, - blockPollingIntervalMs: 10, - }; - contractWrappers = new ContractWrappers(provider, config); - }); - describe('#isAuthorizedAsync', () => { - it('should return false if the address is not authorized', async () => { - const isAuthorized = await contractWrappers.erc721Proxy.isAuthorizedAsync(constants.NULL_ADDRESS); - expect(isAuthorized).to.be.false(); - }); - }); - describe('#getAuthorizedAddressesAsync', () => { - it('should return the list of authorized addresses', async () => { - const authorizedAddresses = await contractWrappers.erc721Proxy.getAuthorizedAddressesAsync(); - for (const authorizedAddress of authorizedAddresses) { - const isAuthorized = await contractWrappers.erc721Proxy.isAuthorizedAsync(authorizedAddress); - expect(isAuthorized).to.be.true(); - } - }); - }); -}); diff --git a/packages/contract-wrappers/test/erc721_wrapper_test.ts b/packages/contract-wrappers/test/erc721_wrapper_test.ts deleted file mode 100644 index 2679ef8d3b..0000000000 --- a/packages/contract-wrappers/test/erc721_wrapper_test.ts +++ /dev/null @@ -1,465 +0,0 @@ -import { BlockchainLifecycle, callbackErrorReporter } from '@0x/dev-utils'; -import { EmptyWalletSubprovider, Web3ProviderEngine } from '@0x/subproviders'; -import { DoneCallback } from '@0x/types'; -import { BigNumber, providerUtils } from '@0x/utils'; -import * as chai from 'chai'; -import 'mocha'; - -import { - BlockParamLiteral, - BlockRange, - ContractWrappers, - ContractWrappersConfig, - ContractWrappersError, - DecodedLogEvent, - ERC721TokenApprovalEventArgs, - ERC721TokenApprovalForAllEventArgs, - ERC721TokenEvents, - ERC721TokenTransferEventArgs, -} from '../src'; - -import { chaiSetup } from './utils/chai_setup'; -import { constants } from './utils/constants'; -import { migrateOnceAsync } from './utils/migrate'; -import { tokenUtils } from './utils/token_utils'; -import { provider, web3Wrapper } from './utils/web3_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -describe('ERC721Wrapper', () => { - let contractWrappers: ContractWrappers; - let userAddresses: string[]; - let tokens: string[]; - let ownerAddress: string; - let tokenAddress: string; - let anotherOwnerAddress: string; - let operatorAddress: string; - let approvedAddress: string; - let receiverAddress: string; - let config: ContractWrappersConfig; - - before(async () => { - const contractAddresses = await migrateOnceAsync(); - config = { - networkId: constants.TESTRPC_NETWORK_ID, - contractAddresses, - blockPollingIntervalMs: 10, - }; - contractWrappers = new ContractWrappers(provider, config); - userAddresses = await web3Wrapper.getAvailableAddressesAsync(); - tokens = tokenUtils.getDummyERC721TokenAddresses(); - tokenAddress = tokens[0]; - [ownerAddress, operatorAddress, anotherOwnerAddress, approvedAddress, receiverAddress] = userAddresses; - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - describe('#transferFromAsync', () => { - it('should fail to transfer NFT if fromAddress has no approvals set', async () => { - const tokenId = await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress); - return expect( - contractWrappers.erc721Token.transferFromAsync(tokenAddress, receiverAddress, approvedAddress, tokenId), - ).to.be.rejectedWith(ContractWrappersError.ERC721NoApproval); - }); - it('should successfully transfer tokens when sender is an approved address', async () => { - const tokenId = await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress); - let txHash = await contractWrappers.erc721Token.setApprovalAsync(tokenAddress, approvedAddress, tokenId); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const owner = await contractWrappers.erc721Token.getOwnerOfAsync(tokenAddress, tokenId); - expect(owner).to.be.equal(ownerAddress); - txHash = await contractWrappers.erc721Token.transferFromAsync( - tokenAddress, - receiverAddress, - approvedAddress, - tokenId, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const newOwner = await contractWrappers.erc721Token.getOwnerOfAsync(tokenAddress, tokenId); - expect(newOwner).to.be.equal(receiverAddress); - }); - it('should successfully transfer tokens when sender is an approved operator', async () => { - const tokenId = await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress); - const isApprovedForAll = true; - let txHash = await contractWrappers.erc721Token.setApprovalForAllAsync( - tokenAddress, - ownerAddress, - operatorAddress, - isApprovedForAll, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const owner = await contractWrappers.erc721Token.getOwnerOfAsync(tokenAddress, tokenId); - expect(owner).to.be.equal(ownerAddress); - txHash = await contractWrappers.erc721Token.transferFromAsync( - tokenAddress, - receiverAddress, - operatorAddress, - tokenId, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const newOwner = await contractWrappers.erc721Token.getOwnerOfAsync(tokenAddress, tokenId); - expect(newOwner).to.be.equal(receiverAddress); - }); - }); - describe('#getTokenCountAsync', () => { - describe('With provider with accounts', () => { - it('should return the count for an existing ERC721 token', async () => { - let tokenCount = await contractWrappers.erc721Token.getTokenCountAsync(tokenAddress, ownerAddress); - expect(tokenCount).to.be.bignumber.equal(0); - await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress); - tokenCount = await contractWrappers.erc721Token.getTokenCountAsync(tokenAddress, ownerAddress); - expect(tokenCount).to.be.bignumber.equal(1); - }); - it('should return a balance of 0 for a non-existent owner address', async () => { - const nonExistentOwner = '0x198c6ad858f213fb31b6fe809e25040e6b964593'; - const balance = await contractWrappers.erc721Token.getTokenCountAsync(tokenAddress, nonExistentOwner); - const expectedBalance = new BigNumber(0); - return expect(balance).to.be.bignumber.equal(expectedBalance); - }); - }); - describe('With provider without accounts', () => { - let zeroExContractWithoutAccounts: ContractWrappers; - before(async () => { - const emptyWalletProvider = addEmptyWalletSubprovider(provider); - zeroExContractWithoutAccounts = new ContractWrappers(emptyWalletProvider, config); - }); - it('should return balance even when called with provider instance without addresses', async () => { - const balance = await zeroExContractWithoutAccounts.erc721Token.getTokenCountAsync( - tokenAddress, - ownerAddress, - ); - return expect(balance).to.be.bignumber.equal(0); - }); - }); - }); - describe('#getOwnerOfAsync', () => { - it('should return the owner for an existing ERC721 token', async () => { - const tokenId = await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress); - const tokenOwner = await contractWrappers.erc721Token.getOwnerOfAsync(tokenAddress, tokenId); - expect(tokenOwner).to.be.bignumber.equal(ownerAddress); - }); - it('should return undefined not 0 for a non-existent ERC721', async () => { - const fakeTokenId = new BigNumber(42); - return expect(contractWrappers.erc721Token.getOwnerOfAsync(tokenAddress, fakeTokenId)).to.be.rejectedWith( - ContractWrappersError.ERC721OwnerNotFound, - ); - }); - }); - describe('#setApprovalForAllAsync/isApprovedForAllAsync', () => { - it('should check if operator address is approved', async () => { - let isApprovedForAll = await contractWrappers.erc721Token.isApprovedForAllAsync( - tokenAddress, - ownerAddress, - operatorAddress, - ); - expect(isApprovedForAll).to.be.false(); - // set - isApprovedForAll = true; - let txHash = await contractWrappers.erc721Token.setApprovalForAllAsync( - tokenAddress, - ownerAddress, - operatorAddress, - isApprovedForAll, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - isApprovedForAll = await contractWrappers.erc721Token.isApprovedForAllAsync( - tokenAddress, - ownerAddress, - operatorAddress, - ); - expect(isApprovedForAll).to.be.true(); - // unset - txHash = await contractWrappers.erc721Token.setApprovalForAllAsync( - tokenAddress, - ownerAddress, - operatorAddress, - false, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - isApprovedForAll = await contractWrappers.erc721Token.isApprovedForAllAsync( - tokenAddress, - ownerAddress, - operatorAddress, - ); - expect(isApprovedForAll).to.be.false(); - }); - }); - describe('#setProxyApprovalForAllAsync/isProxyApprovedForAllAsync', () => { - it('should check if proxy address is approved', async () => { - let isApprovedForAll = true; - const txHash = await contractWrappers.erc721Token.setProxyApprovalForAllAsync( - tokenAddress, - ownerAddress, - isApprovedForAll, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - isApprovedForAll = await contractWrappers.erc721Token.isProxyApprovedForAllAsync( - tokenAddress, - ownerAddress, - ); - expect(isApprovedForAll).to.be.true(); - }); - }); - describe('#setApprovalAsync/getApprovedIfExistsAsync', () => { - it("should set the spender's approval", async () => { - const tokenId = await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress); - - const approvalBeforeSet = await contractWrappers.erc721Token.getApprovedIfExistsAsync( - tokenAddress, - tokenId, - ); - expect(approvalBeforeSet).to.be.undefined(); - await contractWrappers.erc721Token.setApprovalAsync(tokenAddress, approvedAddress, tokenId); - const approvalAfterSet = await contractWrappers.erc721Token.getApprovedIfExistsAsync(tokenAddress, tokenId); - expect(approvalAfterSet).to.be.equal(approvedAddress); - }); - }); - describe('#setProxyApprovalAsync/isProxyApprovedAsync', () => { - it('should set the proxy approval', async () => { - const tokenId = await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress); - - const isProxyApprovedBeforeSet = await contractWrappers.erc721Token.isProxyApprovedAsync( - tokenAddress, - tokenId, - ); - expect(isProxyApprovedBeforeSet).to.be.false(); - await contractWrappers.erc721Token.setProxyApprovalAsync(tokenAddress, tokenId); - const isProxyApprovedAfterSet = await contractWrappers.erc721Token.isProxyApprovedAsync( - tokenAddress, - tokenId, - ); - expect(isProxyApprovedAfterSet).to.be.true(); - }); - }); - describe('#subscribe', () => { - const indexFilterValues = {}; - afterEach(() => { - contractWrappers.erc721Token.unsubscribeAll(); - }); - // Hack: Mocha does not allow a test to be both async and have a `done` callback - // Since we need to await the receipt of the event in the `subscribe` callback, - // we do need both. A hack is to make the top-level a sync fn w/ a done callback and then - // wrap the rest of the test in an async block - // Source: https://github.com/mochajs/mocha/issues/2407 - it('Should receive the Transfer event when tokens are transfered', (done: DoneCallback) => { - (async () => { - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)( - (logEvent: DecodedLogEvent) => { - expect(logEvent.isRemoved).to.be.false(); - expect(logEvent.log.logIndex).to.be.equal(0); - expect(logEvent.log.transactionIndex).to.be.equal(0); - expect(logEvent.log.blockNumber).to.be.a('number'); - const args = logEvent.log.args; - expect(args._from).to.be.equal(ownerAddress); - expect(args._to).to.be.equal(receiverAddress); - expect(args._tokenId).to.be.bignumber.equal(tokenId); - }, - ); - const tokenId = await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress); - const isApprovedForAll = true; - await web3Wrapper.awaitTransactionSuccessAsync( - await contractWrappers.erc721Token.setApprovalForAllAsync( - tokenAddress, - ownerAddress, - operatorAddress, - isApprovedForAll, - ), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - contractWrappers.erc721Token.subscribe( - tokenAddress, - ERC721TokenEvents.Transfer, - indexFilterValues, - callback, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await contractWrappers.erc721Token.transferFromAsync( - tokenAddress, - receiverAddress, - operatorAddress, - tokenId, - ), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - })().catch(done); - }); - it('Should receive the Approval event when allowance is being set', (done: DoneCallback) => { - (async () => { - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)( - (logEvent: DecodedLogEvent) => { - expect(logEvent).to.not.be.undefined(); - expect(logEvent.isRemoved).to.be.false(); - const args = logEvent.log.args; - expect(args._owner).to.be.equal(ownerAddress); - expect(args._approved).to.be.equal(approvedAddress); - expect(args._tokenId).to.be.bignumber.equal(tokenId); - }, - ); - contractWrappers.erc721Token.subscribe( - tokenAddress, - ERC721TokenEvents.Approval, - indexFilterValues, - callback, - ); - const tokenId = await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress); - await web3Wrapper.awaitTransactionSuccessAsync( - await contractWrappers.erc721Token.setApprovalAsync(tokenAddress, approvedAddress, tokenId), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - })().catch(done); - }); - it('Outstanding subscriptions are cancelled when contractWrappers.unsubscribeAll called', (done: DoneCallback) => { - (async () => { - const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)( - (logEvent: DecodedLogEvent) => { - done(new Error('Expected this subscription to have been cancelled')); - }, - ); - contractWrappers.erc721Token.subscribe( - tokenAddress, - ERC721TokenEvents.Transfer, - indexFilterValues, - callbackNeverToBeCalled, - ); - const callbackToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)(); - contractWrappers.unsubscribeAll(); - contractWrappers.erc721Token.subscribe( - tokenAddress, - ERC721TokenEvents.Approval, - indexFilterValues, - callbackToBeCalled, - ); - const tokenId = await tokenUtils.mintDummyERC721Async(tokenAddress, ownerAddress); - await web3Wrapper.awaitTransactionSuccessAsync( - await contractWrappers.erc721Token.setApprovalAsync(tokenAddress, approvedAddress, tokenId), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - done(); - })().catch(done); - }); - it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => { - (async () => { - const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)( - (logEvent: DecodedLogEvent) => { - done(new Error('Expected this subscription to have been cancelled')); - }, - ); - const subscriptionToken = contractWrappers.erc721Token.subscribe( - tokenAddress, - ERC721TokenEvents.ApprovalForAll, - indexFilterValues, - callbackNeverToBeCalled, - ); - contractWrappers.erc721Token.unsubscribe(subscriptionToken); - - const isApproved = true; - await web3Wrapper.awaitTransactionSuccessAsync( - await contractWrappers.erc721Token.setApprovalForAllAsync( - tokenAddress, - ownerAddress, - operatorAddress, - isApproved, - ), - constants.AWAIT_TRANSACTION_MINED_MS, - ); - done(); - })().catch(done); - }); - }); - describe('#getLogsAsync', () => { - const blockRange: BlockRange = { - fromBlock: 0, - toBlock: BlockParamLiteral.Latest, - }; - let txHash: string; - it('should get logs with decoded args emitted by ApprovalForAll', async () => { - const isApprovedForAll = true; - txHash = await contractWrappers.erc721Token.setApprovalForAllAsync( - tokenAddress, - ownerAddress, - operatorAddress, - isApprovedForAll, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const eventName = ERC721TokenEvents.ApprovalForAll; - const indexFilterValues = {}; - const logs = await contractWrappers.erc721Token.getLogsAsync( - tokenAddress, - eventName, - blockRange, - indexFilterValues, - ); - expect(logs).to.have.length(1); - const args = logs[0].args; - expect(logs[0].event).to.be.equal(eventName); - expect(args._owner).to.be.equal(ownerAddress); - expect(args._operator).to.be.equal(operatorAddress); - expect(args._approved).to.be.equal(isApprovedForAll); - }); - it('should only get the logs with the correct event name', async () => { - const isApprovedForAll = true; - txHash = await contractWrappers.erc721Token.setApprovalForAllAsync( - tokenAddress, - ownerAddress, - operatorAddress, - isApprovedForAll, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const differentEventName = ERC721TokenEvents.Transfer; - const indexFilterValues = {}; - const logs = await contractWrappers.erc721Token.getLogsAsync( - tokenAddress, - differentEventName, - blockRange, - indexFilterValues, - ); - expect(logs).to.have.length(0); - }); - it('should only get the logs with the correct indexed fields', async () => { - const isApprovedForAll = true; - txHash = await contractWrappers.erc721Token.setApprovalForAllAsync( - tokenAddress, - ownerAddress, - operatorAddress, - isApprovedForAll, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - txHash = await contractWrappers.erc721Token.setApprovalForAllAsync( - tokenAddress, - anotherOwnerAddress, - operatorAddress, - isApprovedForAll, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const eventName = ERC721TokenEvents.ApprovalForAll; - const indexFilterValues = { - _owner: anotherOwnerAddress, - }; - const logs = await contractWrappers.erc721Token.getLogsAsync( - tokenAddress, - eventName, - blockRange, - indexFilterValues, - ); - expect(logs).to.have.length(1); - const args = logs[0].args; - expect(args._owner).to.be.equal(anotherOwnerAddress); - }); - }); -}); -// tslint:disable:max-file-line-count - -function addEmptyWalletSubprovider(p: Web3ProviderEngine): Web3ProviderEngine { - const providerEngine = new Web3ProviderEngine(); - providerEngine.addProvider(new EmptyWalletSubprovider()); - const currentSubproviders = (p as any)._providers; - for (const subprovider of currentSubproviders) { - providerEngine.addProvider(subprovider); - } - providerUtils.startProviderEngine(providerEngine); - return providerEngine; -} diff --git a/packages/contract-wrappers/test/ether_token_wrapper_test.ts b/packages/contract-wrappers/test/ether_token_wrapper_test.ts deleted file mode 100644 index cc2419aa25..0000000000 --- a/packages/contract-wrappers/test/ether_token_wrapper_test.ts +++ /dev/null @@ -1,437 +0,0 @@ -import { ContractAddresses } from '@0x/contract-addresses'; -import { BlockchainLifecycle, callbackErrorReporter } from '@0x/dev-utils'; -import { DoneCallback } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as chai from 'chai'; -import 'mocha'; - -import { - BlockParamLiteral, - BlockRange, - ContractWrappers, - ContractWrappersError, - WETH9ApprovalEventArgs, - WETH9DepositEventArgs, - WETH9Events, - WETH9TransferEventArgs, - WETH9WithdrawalEventArgs, -} from '../src'; -import { DecodedLogEvent } from '../src/types'; - -import { chaiSetup } from './utils/chai_setup'; -import { constants } from './utils/constants'; -import { migrateOnceAsync } from './utils/migrate'; -import { provider, web3Wrapper } from './utils/web3_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -// Since the address depositing/withdrawing ETH/WETH also needs to pay gas costs for the transaction, -// a small amount of ETH will be used to pay this gas cost. We therefore check that the difference between -// the expected balance and actual balance (given the amount of ETH deposited), only deviates by the amount -// required to pay gas costs. -const MAX_REASONABLE_GAS_COST_IN_WEI = 62517; - -describe('EtherTokenWrapper', () => { - let contractWrappers: ContractWrappers; - let contractAddresses: ContractAddresses; - let userAddresses: string[]; - let addressWithETH: string; - let wethContractAddress: string; - let depositWeiAmount: BigNumber; - const decimalPlaces = 7; - let addressWithoutFunds: string; - const gasPrice = new BigNumber(1); - const transferAmount = new BigNumber(42); - const allowanceAmount = new BigNumber(42); - const depositAmount = new BigNumber(42); - const withdrawalAmount = new BigNumber(42); - before(async () => { - contractAddresses = await migrateOnceAsync(); - const config = { - gasPrice, - networkId: constants.TESTRPC_NETWORK_ID, - contractAddresses, - blockPollingIntervalMs: 10, - }; - contractWrappers = new ContractWrappers(provider, config); - userAddresses = await web3Wrapper.getAvailableAddressesAsync(); - addressWithETH = userAddresses[0]; - wethContractAddress = contractAddresses.etherToken; - depositWeiAmount = Web3Wrapper.toWei(new BigNumber(5)); - addressWithoutFunds = userAddresses[1]; - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - describe('#getContractAddressIfExists', async () => { - it('should return contract address if connected to a known network', () => { - const contractAddressIfExists = contractAddresses.etherToken; - expect(contractAddressIfExists).to.not.be.undefined(); - }); - it('should throw if connected to a private network and contract addresses are not specified', () => { - const UNKNOWN_NETWORK_NETWORK_ID = 10; - expect( - () => - new ContractWrappers(provider, { - networkId: UNKNOWN_NETWORK_NETWORK_ID, - } as any), - ).to.throw(); - }); - }); - describe('#depositAsync', () => { - it('should successfully deposit ETH and issue Wrapped ETH tokens', async () => { - const preETHBalance = await web3Wrapper.getBalanceInWeiAsync(addressWithETH); - const preWETHBalance = await contractWrappers.erc20Token.getBalanceAsync( - wethContractAddress, - addressWithETH, - ); - expect(preETHBalance).to.be.bignumber.gt(0); - expect(preWETHBalance).to.be.bignumber.equal(0); - - const txHash = await contractWrappers.etherToken.depositAsync( - wethContractAddress, - depositWeiAmount, - addressWithETH, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - - const postETHBalanceInWei = await web3Wrapper.getBalanceInWeiAsync(addressWithETH); - const postWETHBalanceInBaseUnits = await contractWrappers.erc20Token.getBalanceAsync( - wethContractAddress, - addressWithETH, - ); - - expect(postWETHBalanceInBaseUnits).to.be.bignumber.equal(depositWeiAmount); - const remainingETHInWei = preETHBalance.minus(depositWeiAmount); - const gasCost = remainingETHInWei.minus(postETHBalanceInWei); - expect(gasCost).to.be.bignumber.lte(MAX_REASONABLE_GAS_COST_IN_WEI); - }); - it('should throw if user has insufficient ETH balance for deposit', async () => { - const preETHBalance = await web3Wrapper.getBalanceInWeiAsync(addressWithETH); - - const extraETHBalance = Web3Wrapper.toWei(new BigNumber(5)); - const overETHBalanceinWei = preETHBalance.plus(extraETHBalance); - - return expect( - contractWrappers.etherToken.depositAsync(wethContractAddress, overETHBalanceinWei, addressWithETH), - ).to.be.rejectedWith(ContractWrappersError.InsufficientEthBalanceForDeposit); - }); - }); - describe('#withdrawAsync', () => { - it('should successfully withdraw ETH in return for Wrapped ETH tokens', async () => { - const ETHBalanceInWei = await web3Wrapper.getBalanceInWeiAsync(addressWithETH); - - await contractWrappers.etherToken.depositAsync(wethContractAddress, depositWeiAmount, addressWithETH); - - const expectedPreETHBalance = ETHBalanceInWei.minus(depositWeiAmount); - const preETHBalance = await web3Wrapper.getBalanceInWeiAsync(addressWithETH); - const preWETHBalance = await contractWrappers.erc20Token.getBalanceAsync( - wethContractAddress, - addressWithETH, - ); - let gasCost = expectedPreETHBalance.minus(preETHBalance); - expect(gasCost).to.be.bignumber.lte(MAX_REASONABLE_GAS_COST_IN_WEI); - expect(preWETHBalance).to.be.bignumber.equal(depositWeiAmount); - - const txHash = await contractWrappers.etherToken.withdrawAsync( - wethContractAddress, - depositWeiAmount, - addressWithETH, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - - const postETHBalance = await web3Wrapper.getBalanceInWeiAsync(addressWithETH); - const postWETHBalanceInBaseUnits = await contractWrappers.erc20Token.getBalanceAsync( - wethContractAddress, - addressWithETH, - ); - - expect(postWETHBalanceInBaseUnits).to.be.bignumber.equal(0); - const expectedETHBalance = preETHBalance.plus(depositWeiAmount).integerValue(decimalPlaces); - gasCost = expectedETHBalance.minus(postETHBalance); - expect(gasCost).to.be.bignumber.lte(MAX_REASONABLE_GAS_COST_IN_WEI); - }); - it('should throw if user has insufficient WETH balance for withdrawal', async () => { - const preWETHBalance = await contractWrappers.erc20Token.getBalanceAsync( - wethContractAddress, - addressWithETH, - ); - expect(preWETHBalance).to.be.bignumber.equal(0); - - // tslint:disable-next-line:custom-no-magic-numbers - const overWETHBalance = preWETHBalance.plus(999999999); - - return expect( - contractWrappers.etherToken.withdrawAsync(wethContractAddress, overWETHBalance, addressWithETH), - ).to.be.rejectedWith(ContractWrappersError.InsufficientWEthBalanceForWithdrawal); - }); - }); - describe('#subscribe', () => { - const indexFilterValues = {}; - let etherTokenAddress: string; - before(async () => { - etherTokenAddress = contractAddresses.etherToken; - }); - afterEach(() => { - contractWrappers.etherToken.unsubscribeAll(); - }); - // Hack: Mocha does not allow a test to be both async and have a `done` callback - // Since we need to await the receipt of the event in the `subscribe` callback, - // we do need both. A hack is to make the top-level async fn w/ a done callback and then - // wrap the rest of the test in an async block - // Source: https://github.com/mochajs/mocha/issues/2407 - it('Should receive the Transfer event when tokens are transfered', (done: DoneCallback) => { - (async () => { - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)( - (logEvent: DecodedLogEvent) => { - expect(logEvent).to.not.be.undefined(); - expect(logEvent.isRemoved).to.be.false(); - expect(logEvent.log.logIndex).to.be.equal(0); - expect(logEvent.log.transactionIndex).to.be.equal(0); - expect(logEvent.log.blockNumber).to.be.a('number'); - const args = logEvent.log.args; - expect(args._from).to.be.equal(addressWithETH); - expect(args._to).to.be.equal(addressWithoutFunds); - expect(args._value).to.be.bignumber.equal(transferAmount); - }, - ); - await contractWrappers.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH); - contractWrappers.etherToken.subscribe( - etherTokenAddress, - WETH9Events.Transfer, - indexFilterValues, - callback, - ); - await contractWrappers.erc20Token.transferAsync( - etherTokenAddress, - addressWithETH, - addressWithoutFunds, - transferAmount, - ); - })().catch(done); - }); - it('Should receive the Approval event when allowance is being set', (done: DoneCallback) => { - (async () => { - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)( - (logEvent: DecodedLogEvent) => { - expect(logEvent).to.not.be.undefined(); - expect(logEvent.isRemoved).to.be.false(); - const args = logEvent.log.args; - expect(args._owner).to.be.equal(addressWithETH); - expect(args._spender).to.be.equal(addressWithoutFunds); - expect(args._value).to.be.bignumber.equal(allowanceAmount); - }, - ); - contractWrappers.etherToken.subscribe( - etherTokenAddress, - WETH9Events.Approval, - indexFilterValues, - callback, - ); - await contractWrappers.erc20Token.setAllowanceAsync( - etherTokenAddress, - addressWithETH, - addressWithoutFunds, - allowanceAmount, - ); - })().catch(done); - }); - it('Should receive the Deposit event when ether is being deposited', (done: DoneCallback) => { - (async () => { - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)( - (logEvent: DecodedLogEvent) => { - expect(logEvent).to.not.be.undefined(); - expect(logEvent.isRemoved).to.be.false(); - const args = logEvent.log.args; - expect(args._owner).to.be.equal(addressWithETH); - expect(args._value).to.be.bignumber.equal(depositAmount); - }, - ); - contractWrappers.etherToken.subscribe( - etherTokenAddress, - WETH9Events.Deposit, - indexFilterValues, - callback, - ); - await contractWrappers.etherToken.depositAsync(etherTokenAddress, depositAmount, addressWithETH); - })().catch(done); - }); - it('Should receive the Withdrawal event when ether is being withdrawn', (done: DoneCallback) => { - (async () => { - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)( - (logEvent: DecodedLogEvent) => { - expect(logEvent).to.not.be.undefined(); - expect(logEvent.isRemoved).to.be.false(); - const args = logEvent.log.args; - expect(args._owner).to.be.equal(addressWithETH); - expect(args._value).to.be.bignumber.equal(depositAmount); - }, - ); - await contractWrappers.etherToken.depositAsync(etherTokenAddress, depositAmount, addressWithETH); - contractWrappers.etherToken.subscribe( - etherTokenAddress, - WETH9Events.Withdrawal, - indexFilterValues, - callback, - ); - await contractWrappers.etherToken.withdrawAsync(etherTokenAddress, withdrawalAmount, addressWithETH); - })().catch(done); - }); - it('should cancel outstanding subscriptions when contractWrappers.unsubscribeAll is called', (done: DoneCallback) => { - (async () => { - const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)( - (_logEvent: DecodedLogEvent) => { - done(new Error('Expected this subscription to have been cancelled')); - }, - ); - contractWrappers.etherToken.subscribe( - etherTokenAddress, - WETH9Events.Transfer, - indexFilterValues, - callbackNeverToBeCalled, - ); - const callbackToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)(); - contractWrappers.unsubscribeAll(); - await contractWrappers.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH); - contractWrappers.etherToken.subscribe( - etherTokenAddress, - WETH9Events.Transfer, - indexFilterValues, - callbackToBeCalled, - ); - await contractWrappers.erc20Token.transferAsync( - etherTokenAddress, - addressWithETH, - addressWithoutFunds, - transferAmount, - ); - })().catch(done); - }); - it('Should cancel subscription when unsubscribe called', (done: DoneCallback) => { - (async () => { - const callbackNeverToBeCalled = callbackErrorReporter.reportNodeCallbackErrors(done)( - (_logEvent: DecodedLogEvent) => { - done(new Error('Expected this subscription to have been cancelled')); - }, - ); - await contractWrappers.etherToken.depositAsync(etherTokenAddress, transferAmount, addressWithETH); - const subscriptionToken = contractWrappers.etherToken.subscribe( - etherTokenAddress, - WETH9Events.Transfer, - indexFilterValues, - callbackNeverToBeCalled, - ); - contractWrappers.etherToken.unsubscribe(subscriptionToken); - await contractWrappers.erc20Token.transferAsync( - etherTokenAddress, - addressWithETH, - addressWithoutFunds, - transferAmount, - ); - done(); - })().catch(done); - }); - }); - describe('#getLogsAsync', () => { - let etherTokenAddress: string; - let erc20ProxyAddress: string; - let blockRange: BlockRange; - let txHash: string; - before(async () => { - addressWithETH = userAddresses[0]; - etherTokenAddress = contractAddresses.etherToken; - erc20ProxyAddress = contractWrappers.erc20Proxy.address; - // Start the block range after all migrations to avoid unexpected logs - const currentBlock: number = await web3Wrapper.getBlockNumberAsync(); - const fromBlock = currentBlock + 1; - blockRange = { - fromBlock, - toBlock: BlockParamLiteral.Latest, - }; - }); - it('should get logs with decoded args emitted by Approval', async () => { - txHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync( - etherTokenAddress, - addressWithETH, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const eventName = WETH9Events.Approval; - const indexFilterValues = {}; - const logs = await contractWrappers.etherToken.getLogsAsync( - etherTokenAddress, - eventName, - blockRange, - indexFilterValues, - ); - expect(logs).to.have.length(1); - const args = logs[0].args; - expect(logs[0].event).to.be.equal(eventName); - expect(args._owner).to.be.equal(addressWithETH); - expect(args._spender).to.be.equal(erc20ProxyAddress); - expect(args._value).to.be.bignumber.equal(contractWrappers.erc20Token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS); - }); - it('should get logs with decoded args emitted by Deposit', async () => { - await contractWrappers.etherToken.depositAsync(etherTokenAddress, depositAmount, addressWithETH); - const eventName = WETH9Events.Deposit; - const indexFilterValues = {}; - const logs = await contractWrappers.etherToken.getLogsAsync( - etherTokenAddress, - eventName, - blockRange, - indexFilterValues, - ); - expect(logs).to.have.length(1); - const args = logs[0].args; - expect(logs[0].event).to.be.equal(eventName); - expect(args._owner).to.be.equal(addressWithETH); - expect(args._value).to.be.bignumber.equal(depositAmount); - }); - it('should only get the logs with the correct event name', async () => { - txHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync( - etherTokenAddress, - addressWithETH, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const differentEventName = WETH9Events.Transfer; - const indexFilterValues = {}; - const logs = await contractWrappers.etherToken.getLogsAsync( - etherTokenAddress, - differentEventName, - blockRange, - indexFilterValues, - ); - expect(logs).to.have.length(0); - }); - it('should only get the logs with the correct indexed fields', async () => { - txHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync( - etherTokenAddress, - addressWithETH, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - txHash = await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync( - etherTokenAddress, - addressWithoutFunds, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const eventName = WETH9Events.Approval; - const indexFilterValues = { - _owner: addressWithETH, - }; - const logs = await contractWrappers.etherToken.getLogsAsync( - etherTokenAddress, - eventName, - blockRange, - indexFilterValues, - ); - expect(logs).to.have.length(1); - const args = logs[0].args; - expect(args._owner).to.be.equal(addressWithETH); - }); - }); -}); diff --git a/packages/contract-wrappers/test/exchange_wrapper_test.ts b/packages/contract-wrappers/test/exchange_wrapper_test.ts index 8f18bb29b6..1f894a3841 100644 --- a/packages/contract-wrappers/test/exchange_wrapper_test.ts +++ b/packages/contract-wrappers/test/exchange_wrapper_test.ts @@ -1,8 +1,7 @@ -import { DummyERC20TokenContract } from '@0x/abi-gen-wrappers'; import { BlockchainLifecycle, callbackErrorReporter } from '@0x/dev-utils'; import { FillScenarios } from '@0x/fill-scenarios'; import { assetDataUtils, orderHashUtils, signatureUtils } from '@0x/order-utils'; -import { DoneCallback, RevertReason, SignedOrder } from '@0x/types'; +import { DoneCallback, SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; import * as chai from 'chai'; import { BlockParamLiteral } from 'ethereum-types'; @@ -10,8 +9,8 @@ import 'mocha'; import { ContractWrappers, ExchangeCancelEventArgs, ExchangeEvents, ExchangeFillEventArgs, OrderStatus } from '../src'; import { DecodedLogEvent } from '../src/types'; +import { _getDefaultContractAddresses } from '../src/utils/contract_addresses'; -import { UntransferrableDummyERC20Token } from './artifacts/UntransferrableDummyERC20Token'; import { chaiSetup } from './utils/chai_setup'; import { constants } from './utils/constants'; import { migrateOnceAsync } from './utils/migrate'; @@ -35,7 +34,6 @@ describe('ExchangeWrapper', () => { let takerAddress: string; let makerAssetData: string; let takerAssetData: string; - let txHash: string; const fillableAmount = new BigNumber(5); const takerTokenFillAmount = new BigNumber(5); let signedOrder: SignedOrder; @@ -52,7 +50,7 @@ describe('ExchangeWrapper', () => { contractWrappers = new ContractWrappers(provider, config); exchangeContractAddress = contractWrappers.exchange.address; userAddresses = await web3Wrapper.getAvailableAddressesAsync(); - zrxTokenAddress = contractWrappers.exchange.zrxTokenAddress; + zrxTokenAddress = contractAddresses.zrxToken; fillScenarios = new FillScenarios( provider, userAddresses, @@ -94,71 +92,71 @@ describe('ExchangeWrapper', () => { describe('fill order(s)', () => { describe('#fillOrderAsync', () => { it('should fill a valid order', async () => { - txHash = await contractWrappers.exchange.fillOrderAsync( + await contractWrappers.exchange.fillOrder.awaitTransactionSuccessAsync( signedOrder, takerTokenFillAmount, - takerAddress, + signedOrder.signature, + { from: takerAddress }, ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); describe('#fillOrderNoThrowAsync', () => { it('should fill a valid order', async () => { - txHash = await contractWrappers.exchange.fillOrderNoThrowAsync( + await contractWrappers.exchange.fillOrderNoThrow.awaitTransactionSuccessAsync( signedOrder, takerTokenFillAmount, - takerAddress, + signedOrder.signature, + { from: takerAddress }, ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); + const orderInfo = await contractWrappers.exchange.getOrderInfo.callAsync(signedOrder); expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); }); }); describe('#fillOrKillOrderAsync', () => { it('should fill or kill a valid order', async () => { - txHash = await contractWrappers.exchange.fillOrKillOrderAsync( + await contractWrappers.exchange.fillOrKillOrder.awaitTransactionSuccessAsync( signedOrder, takerTokenFillAmount, - takerAddress, + signedOrder.signature, + { from: takerAddress }, ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); describe('#batchFillOrdersAsync', () => { it('should fill a batch of valid orders', async () => { const signedOrders = [signedOrder, anotherSignedOrder]; const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount]; - txHash = await contractWrappers.exchange.batchFillOrdersAsync( + await contractWrappers.exchange.batchFillOrders.awaitTransactionSuccessAsync( signedOrders, takerAssetFillAmounts, - takerAddress, + signedOrders.map(o => o.signature), + { from: takerAddress }, ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); describe('#marketBuyOrdersAsync', () => { it('should maker buy', async () => { const signedOrders = [signedOrder, anotherSignedOrder]; const makerAssetFillAmount = takerTokenFillAmount; - txHash = await contractWrappers.exchange.marketBuyOrdersAsync( + await contractWrappers.exchange.marketBuyOrders.awaitTransactionSuccessAsync( signedOrders, makerAssetFillAmount, - takerAddress, + signedOrders.map(o => o.signature), + { from: takerAddress }, ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); describe('#marketBuyOrdersNoThrowAsync', () => { it('should no throw maker buy', async () => { const signedOrders = [signedOrder, anotherSignedOrder]; const makerAssetFillAmount = takerTokenFillAmount; - txHash = await contractWrappers.exchange.marketBuyOrdersNoThrowAsync( + await contractWrappers.exchange.marketBuyOrdersNoThrow.awaitTransactionSuccessAsync( signedOrders, makerAssetFillAmount, - takerAddress, + signedOrders.map(o => o.signature), + { from: takerAddress }, ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); + const orderInfo = await contractWrappers.exchange.getOrderInfo.callAsync(signedOrder); expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); }); }); @@ -166,25 +164,25 @@ describe('ExchangeWrapper', () => { it('should maker sell', async () => { const signedOrders = [signedOrder, anotherSignedOrder]; const takerAssetFillAmount = takerTokenFillAmount; - txHash = await contractWrappers.exchange.marketSellOrdersAsync( + await contractWrappers.exchange.marketSellOrders.awaitTransactionSuccessAsync( signedOrders, takerAssetFillAmount, - takerAddress, + signedOrders.map(o => o.signature), + { from: takerAddress }, ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); describe('#marketSellOrdersNoThrowAsync', () => { it('should no throw maker sell', async () => { const signedOrders = [signedOrder, anotherSignedOrder]; const takerAssetFillAmount = takerTokenFillAmount; - txHash = await contractWrappers.exchange.marketSellOrdersNoThrowAsync( + await contractWrappers.exchange.marketSellOrdersNoThrow.awaitTransactionSuccessAsync( signedOrders, takerAssetFillAmount, - takerAddress, + signedOrders.map(o => o.signature), + { from: takerAddress }, ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); + const orderInfo = await contractWrappers.exchange.getOrderInfo.callAsync(signedOrder); expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); }); }); @@ -192,15 +190,15 @@ describe('ExchangeWrapper', () => { it('should fill a batch of valid orders', async () => { const signedOrders = [signedOrder, anotherSignedOrder]; const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount]; - txHash = await contractWrappers.exchange.batchFillOrdersNoThrowAsync( + await contractWrappers.exchange.batchFillOrdersNoThrow.awaitTransactionSuccessAsync( signedOrders, takerAssetFillAmounts, - takerAddress, + signedOrders.map(o => o.signature), + { from: takerAddress }, ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - let orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); + let orderInfo = await contractWrappers.exchange.getOrderInfo.callAsync(signedOrder); expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); - orderInfo = await contractWrappers.exchange.getOrderInfoAsync(anotherSignedOrder); + orderInfo = await contractWrappers.exchange.getOrderInfo.callAsync(anotherSignedOrder); expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FullyFilled); }); }); @@ -208,12 +206,12 @@ describe('ExchangeWrapper', () => { it('should fill or kill a batch of valid orders', async () => { const signedOrders = [signedOrder, anotherSignedOrder]; const takerAssetFillAmounts = [takerTokenFillAmount, takerTokenFillAmount]; - txHash = await contractWrappers.exchange.batchFillOrKillOrdersAsync( + await contractWrappers.exchange.batchFillOrKillOrders.awaitTransactionSuccessAsync( signedOrders, takerAssetFillAmounts, - takerAddress, + signedOrders.map(o => o.signature), + { from: takerAddress }, ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); describe('#matchOrdersAsync', () => { @@ -225,35 +223,39 @@ describe('ExchangeWrapper', () => { takerAddress, fillableAmount, ); - txHash = await contractWrappers.exchange.matchOrdersAsync( + await contractWrappers.exchange.matchOrders.awaitTransactionSuccessAsync( signedOrder, matchingSignedOrder, - takerAddress, + signedOrder.signature, + matchingSignedOrder.signature, + { from: takerAddress }, ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); }); describe('cancel order(s)', () => { describe('#cancelOrderAsync', () => { it('should cancel a valid order', async () => { - txHash = await contractWrappers.exchange.cancelOrderAsync(signedOrder); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + await contractWrappers.exchange.cancelOrder.awaitTransactionSuccessAsync(signedOrder, { + from: makerAddress, + }); }); }); describe('#batchCancelOrdersAsync', () => { it('should cancel a batch of valid orders', async () => { const orders = [signedOrder, anotherSignedOrder]; - txHash = await contractWrappers.exchange.batchCancelOrdersAsync(orders); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + await contractWrappers.exchange.batchCancelOrders.awaitTransactionSuccessAsync(orders, { + from: makerAddress, + }); }); }); describe('#cancelOrdersUpTo/getOrderEpochAsync', () => { it('should cancel orders up to target order epoch', async () => { const targetOrderEpoch = new BigNumber(42); - txHash = await contractWrappers.exchange.cancelOrdersUpToAsync(targetOrderEpoch, makerAddress); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const orderEpoch = await contractWrappers.exchange.getOrderEpochAsync( + await contractWrappers.exchange.cancelOrdersUpTo.awaitTransactionSuccessAsync(targetOrderEpoch, { + from: makerAddress, + }); + const orderEpoch = await contractWrappers.exchange.orderEpoch.callAsync( makerAddress, constants.NULL_ADDRESS, ); @@ -261,136 +263,35 @@ describe('ExchangeWrapper', () => { }); }); }); - describe('#getZRXAssetData', () => { - it('should get the asset data', () => { - const ZRX_ASSET_DATA = contractWrappers.exchange.getZRXAssetData(); - const ASSET_DATA_HEX_LENGTH = 74; - expect(ZRX_ASSET_DATA).to.have.length(ASSET_DATA_HEX_LENGTH); - }); - }); describe('#getOrderInfoAsync', () => { it('should get the order info', async () => { - const orderInfo = await contractWrappers.exchange.getOrderInfoAsync(signedOrder); + const orderInfo = await contractWrappers.exchange.getOrderInfo.callAsync(signedOrder); const orderHash = orderHashUtils.getOrderHashHex(signedOrder); expect(orderInfo.orderHash).to.be.equal(orderHash); }); }); describe('#getOrdersInfoAsync', () => { it('should get the orders info', async () => { - const ordersInfo = await contractWrappers.exchange.getOrdersInfoAsync([signedOrder, anotherSignedOrder]); + const ordersInfo = await contractWrappers.exchange.getOrdersInfo.callAsync([ + signedOrder, + anotherSignedOrder, + ]); const orderHash = orderHashUtils.getOrderHashHex(signedOrder); expect(ordersInfo[0].orderHash).to.be.equal(orderHash); const anotherOrderHash = orderHashUtils.getOrderHashHex(anotherSignedOrder); expect(ordersInfo[1].orderHash).to.be.equal(anotherOrderHash); }); }); - describe('#validateOrderFillableOrThrowAsync', () => { - it('should throw if signature is invalid', async () => { - const signedOrderWithInvalidSignature = { - ...signedOrder, - signature: - '0x1b61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace225403', - }; - - return expect( - contractWrappers.exchange.validateOrderFillableOrThrowAsync(signedOrderWithInvalidSignature), - ).to.eventually.to.be.rejectedWith(RevertReason.InvalidOrderSignature); - }); - it('should validate the order with the current balances and allowances for the maker', async () => { - await contractWrappers.exchange.validateOrderFillableOrThrowAsync(signedOrder, { - validateRemainingOrderAmountIsFillable: false, - }); - }); - it('should validate the order with remaining fillable amount for the order', async () => { - await contractWrappers.exchange.validateOrderFillableOrThrowAsync(signedOrder); - }); - it('should validate the order with specified amount', async () => { - await contractWrappers.exchange.validateOrderFillableOrThrowAsync(signedOrder, { - expectedFillTakerTokenAmount: signedOrder.takerAssetAmount, - }); - }); - it('should throw if the amount is greater than the allowance/balance', async () => { - return expect( - contractWrappers.exchange.validateOrderFillableOrThrowAsync(signedOrder, { - // tslint:disable-next-line:custom-no-magic-numbers - expectedFillTakerTokenAmount: new BigNumber(2).pow(256).minus(1), - }), - ).to.eventually.to.be.rejected(); - }); - it('should throw when the maker does not have enough balance for the remaining order amount', async () => { - const makerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, makerAddress); - // Change maker balance to have less than the order amount - const remainingBalance = makerBalance.minus(signedOrder.makerAssetAmount.minus(1)); - await web3Wrapper.awaitTransactionSuccessAsync( - await contractWrappers.erc20Token.transferAsync( - makerTokenAddress, - makerAddress, - constants.NULL_ADDRESS, - remainingBalance, - ), - ); - return expect( - contractWrappers.exchange.validateOrderFillableOrThrowAsync(signedOrder), - ).to.eventually.to.be.rejected(); - }); - it('should validate the order when remaining order amount has some fillable amount', async () => { - const makerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, makerAddress); - // Change maker balance to have less than the order amount - const remainingBalance = makerBalance.minus(signedOrder.makerAssetAmount.minus(1)); - await web3Wrapper.awaitTransactionSuccessAsync( - await contractWrappers.erc20Token.transferAsync( - makerTokenAddress, - makerAddress, - constants.NULL_ADDRESS, - remainingBalance, - ), - ); - // An amount is still transferrable - await contractWrappers.exchange.validateOrderFillableOrThrowAsync(signedOrder, { - validateRemainingOrderAmountIsFillable: false, - }); - }); - it('should throw when the ERC20 token has transfer restrictions', async () => { - const untransferrableToken = await DummyERC20TokenContract.deployFrom0xArtifactAsync( - UntransferrableDummyERC20Token, - provider, - { from: userAddresses[0] }, - 'UntransferrableToken', - 'UTT', - new BigNumber(constants.ZRX_DECIMALS), - // tslint:disable-next-line:custom-no-magic-numbers - new BigNumber(2).pow(20).minus(1), - ); - const untransferrableMakerAssetData = assetDataUtils.encodeERC20AssetData(untransferrableToken.address); - const invalidSignedOrder = await fillScenarios.createFillableSignedOrderAsync( - untransferrableMakerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - ); - await web3Wrapper.awaitTransactionSuccessAsync( - await contractWrappers.erc20Token.setProxyAllowanceAsync( - untransferrableToken.address, - makerAddress, - signedOrder.makerAssetAmount, - ), - ); - return expect( - contractWrappers.exchange.validateOrderFillableOrThrowAsync(invalidSignedOrder), - ).to.eventually.to.be.rejectedWith('TRANSFER_FAILED'); - }); - }); describe('#isValidSignature', () => { it('should check if the signature is valid', async () => { const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - let isValid = await contractWrappers.exchange.isValidSignatureAsync( + let isValid = await contractWrappers.exchange.isValidSignature.callAsync( orderHash, signedOrder.makerAddress, signedOrder.signature, ); expect(isValid).to.be.true(); - isValid = await contractWrappers.exchange.isValidSignatureAsync( + isValid = await contractWrappers.exchange.isValidSignature.callAsync( orderHash, signedOrder.takerAddress, signedOrder.signature, @@ -402,7 +303,10 @@ describe('ExchangeWrapper', () => { it('should check if the validator is allowed', async () => { const signerAddress = makerAddress; const validatorAddress = constants.NULL_ADDRESS; - const isAllowed = await contractWrappers.exchange.isAllowedValidatorAsync(signerAddress, validatorAddress); + const isAllowed = await contractWrappers.exchange.allowedValidators.callAsync( + signerAddress, + validatorAddress, + ); expect(isAllowed).to.be.false(); }); }); @@ -411,52 +315,50 @@ describe('ExchangeWrapper', () => { const validatorAddress = constants.NULL_ADDRESS; const isApproved = true; const senderAddress = makerAddress; - txHash = await contractWrappers.exchange.setSignatureValidatorApprovalAsync( + await contractWrappers.exchange.setSignatureValidatorApproval.awaitTransactionSuccessAsync( validatorAddress, isApproved, - senderAddress, + { from: senderAddress }, ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); }); }); describe('#isTransactionExecutedAsync', () => { it('should check if the transaction is executed', async () => { const transactionHash = '0x0000000000000000000000000000000000000000000000000000000000000000'; - const isExecuted = await contractWrappers.exchange.isTransactionExecutedAsync(transactionHash); + const isExecuted = await contractWrappers.exchange.transactions.callAsync(transactionHash); expect(isExecuted).to.be.false(); }); }); describe('#getAssetProxyBySignatureAsync', () => { it('should fill or kill a valid order', async () => { - const erc20ProxyId = await contractWrappers.erc20Proxy.getProxyIdAsync(); - const erc20ProxyAddressById = await contractWrappers.exchange.getAssetProxyBySignatureAsync(erc20ProxyId); + const erc20ProxyId = await contractWrappers.erc20Proxy.getProxyId.callAsync(); + const erc20ProxyAddressById = await contractWrappers.exchange.getAssetProxy.callAsync(erc20ProxyId); const erc20ProxyAddress = contractWrappers.erc20Proxy.address; expect(erc20ProxyAddressById).to.be.equal(erc20ProxyAddress); - const erc721ProxyId = await contractWrappers.erc721Proxy.getProxyIdAsync(); - const erc721ProxyAddressById = await contractWrappers.exchange.getAssetProxyBySignatureAsync(erc721ProxyId); + const erc721ProxyId = await contractWrappers.erc721Proxy.getProxyId.callAsync(); + const erc721ProxyAddressById = await contractWrappers.exchange.getAssetProxy.callAsync(erc721ProxyId); const erc721ProxyAddress = contractWrappers.erc721Proxy.address; expect(erc721ProxyAddressById).to.be.equal(erc721ProxyAddress); }); }); - describe('#preSignAsync/isPreSignedAsync', () => { + describe('#preSign/isPresigned', () => { it('should preSign the hash', async () => { const senderAddress = takerAddress; const hash = orderHashUtils.getOrderHashHex(signedOrder); const signerAddress = signedOrder.makerAddress; - let isPreSigned = await contractWrappers.exchange.isPreSignedAsync(hash, signerAddress); + let isPreSigned = await contractWrappers.exchange.preSigned.callAsync(hash, signerAddress); expect(isPreSigned).to.be.false(); - txHash = await contractWrappers.exchange.preSignAsync( + await contractWrappers.exchange.preSign.awaitTransactionSuccessAsync( hash, signerAddress, signedOrder.signature, - senderAddress, + { from: senderAddress }, ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - isPreSigned = await contractWrappers.exchange.isPreSignedAsync(hash, signerAddress); + isPreSigned = await contractWrappers.exchange.preSigned.callAsync(hash, signerAddress); expect(isPreSigned).to.be.true(); const preSignedSignature = '0x06'; - const isValidSignature = await contractWrappers.exchange.isValidSignatureAsync( + const isValidSignature = await contractWrappers.exchange.isValidSignature.callAsync( hash, signerAddress, preSignedSignature, @@ -508,10 +410,11 @@ describe('ExchangeWrapper', () => { }, ); contractWrappers.exchange.subscribe(ExchangeEvents.Fill, indexFilterValues, callback); - await contractWrappers.exchange.fillOrderAsync( + await contractWrappers.exchange.fillOrder.awaitTransactionSuccessAsync( signedOrder, takerTokenFillAmountInBaseUnits, - takerAddress, + signedOrder.signature, + { from: takerAddress }, ); })().catch(done); }); @@ -523,7 +426,9 @@ describe('ExchangeWrapper', () => { }, ); contractWrappers.exchange.subscribe(ExchangeEvents.Cancel, indexFilterValues, callback); - await contractWrappers.exchange.cancelOrderAsync(signedOrder); + await contractWrappers.exchange.cancelOrder.awaitTransactionSuccessAsync(signedOrder, { + from: makerAddress, + }); })().catch(done); }); it('Outstanding subscriptions are cancelled when contractWrappers.unsubscribeAll called', (done: DoneCallback) => { @@ -543,10 +448,11 @@ describe('ExchangeWrapper', () => { }, ); contractWrappers.exchange.subscribe(ExchangeEvents.Fill, indexFilterValues, callback); - await contractWrappers.exchange.fillOrderAsync( + await contractWrappers.exchange.fillOrder.awaitTransactionSuccessAsync( signedOrder, takerTokenFillAmountInBaseUnits, - takerAddress, + signedOrder.signature, + { from: takerAddress }, ); })().catch(done); }); @@ -563,10 +469,11 @@ describe('ExchangeWrapper', () => { callbackNeverToBeCalled, ); contractWrappers.exchange.unsubscribe(subscriptionToken); - await contractWrappers.exchange.fillOrderAsync( + await contractWrappers.exchange.fillOrder.awaitTransactionSuccessAsync( signedOrder, takerTokenFillAmountInBaseUnits, - takerAddress, + signedOrder.signature, + { from: takerAddress }, ); done(); })().catch(done); @@ -578,7 +485,12 @@ describe('ExchangeWrapper', () => { toBlock: BlockParamLiteral.Latest, }; it('should get logs with decoded args emitted by Fill', async () => { - txHash = await contractWrappers.exchange.fillOrderAsync(signedOrder, takerTokenFillAmount, takerAddress); + await contractWrappers.exchange.fillOrder.awaitTransactionSuccessAsync( + signedOrder, + takerTokenFillAmount, + signedOrder.signature, + { from: takerAddress }, + ); const eventName = ExchangeEvents.Fill; const indexFilterValues = {}; const logs = await contractWrappers.exchange.getLogsAsync(eventName, blockRange, indexFilterValues); @@ -586,8 +498,12 @@ describe('ExchangeWrapper', () => { expect(logs[0].event).to.be.equal(eventName); }); it('should only get the logs with the correct event name', async () => { - txHash = await contractWrappers.exchange.fillOrderAsync(signedOrder, takerTokenFillAmount, takerAddress); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + await contractWrappers.exchange.fillOrder.awaitTransactionSuccessAsync( + signedOrder, + takerTokenFillAmount, + signedOrder.signature, + { from: takerAddress }, + ); const differentEventName = ExchangeEvents.Cancel; const indexFilterValues = {}; const logs = await contractWrappers.exchange.getLogsAsync( @@ -598,8 +514,12 @@ describe('ExchangeWrapper', () => { expect(logs).to.have.length(0); }); it('should only get the logs with the correct indexed fields', async () => { - txHash = await contractWrappers.exchange.fillOrderAsync(signedOrder, takerTokenFillAmount, takerAddress); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); + await contractWrappers.exchange.fillOrder.awaitTransactionSuccessAsync( + signedOrder, + takerTokenFillAmount, + signedOrder.signature, + { from: takerAddress }, + ); const signedOrderWithAnotherMakerAddress = await fillScenarios.createFillableSignedOrderAsync( makerAssetData, takerAssetData, @@ -607,13 +527,12 @@ describe('ExchangeWrapper', () => { takerAddress, fillableAmount, ); - txHash = await contractWrappers.exchange.fillOrderAsync( + await contractWrappers.exchange.fillOrder.awaitTransactionSuccessAsync( signedOrderWithAnotherMakerAddress, takerTokenFillAmount, - takerAddress, + signedOrderWithAnotherMakerAddress.signature, + { from: takerAddress }, ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const eventName = ExchangeEvents.Fill; const indexFilterValues = { makerAddress: anotherMakerAddress, diff --git a/packages/contract-wrappers/test/forwarder_wrapper_test.ts b/packages/contract-wrappers/test/forwarder_wrapper_test.ts deleted file mode 100644 index 0d197eced8..0000000000 --- a/packages/contract-wrappers/test/forwarder_wrapper_test.ts +++ /dev/null @@ -1,167 +0,0 @@ -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { FillScenarios } from '@0x/fill-scenarios'; -import { assetDataUtils } from '@0x/order-utils'; -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as chai from 'chai'; -import 'mocha'; - -import { ContractWrappers, OrderStatus } from '../src'; - -import { chaiSetup } from './utils/chai_setup'; -import { constants } from './utils/constants'; -import { migrateOnceAsync } from './utils/migrate'; -import { tokenUtils } from './utils/token_utils'; -import { provider, web3Wrapper } from './utils/web3_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -// tslint:disable:custom-no-magic-numbers -describe('ForwarderWrapper', () => { - const fillableAmount = new BigNumber(5); - let contractWrappers: ContractWrappers; - let fillScenarios: FillScenarios; - let exchangeContractAddress: string; - let zrxTokenAddress: string; - let userAddresses: string[]; - let makerAddress: string; - let takerAddress: string; - let makerTokenAddress: string; - let takerTokenAddress: string; - let makerAssetData: string; - let takerAssetData: string; - let signedOrder: SignedOrder; - let anotherSignedOrder: SignedOrder; - before(async () => { - const contractAddresses = await migrateOnceAsync(); - await blockchainLifecycle.startAsync(); - const config = { - networkId: constants.TESTRPC_NETWORK_ID, - contractAddresses, - blockPollingIntervalMs: 10, - }; - contractWrappers = new ContractWrappers(provider, config); - exchangeContractAddress = contractWrappers.exchange.address; - userAddresses = await web3Wrapper.getAvailableAddressesAsync(); - zrxTokenAddress = contractWrappers.exchange.zrxTokenAddress; - fillScenarios = new FillScenarios( - provider, - userAddresses, - zrxTokenAddress, - exchangeContractAddress, - contractWrappers.erc20Proxy.address, - contractWrappers.erc721Proxy.address, - ); - [, makerAddress, takerAddress] = userAddresses; - [makerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); - takerTokenAddress = contractWrappers.forwarder.etherTokenAddress; - [makerAssetData, takerAssetData] = [ - assetDataUtils.encodeERC20AssetData(makerTokenAddress), - assetDataUtils.encodeERC20AssetData(takerTokenAddress), - ]; - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - constants.NULL_ADDRESS, - fillableAmount, - ); - anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - constants.NULL_ADDRESS, - fillableAmount, - ); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - describe('#marketBuyOrdersWithEthAsync', () => { - it('should market buy orders with eth', async () => { - const signedOrders = [signedOrder, anotherSignedOrder]; - const makerAssetFillAmount = signedOrder.makerAssetAmount.plus(anotherSignedOrder.makerAssetAmount); - const txHash = await contractWrappers.forwarder.marketBuyOrdersWithEthAsync( - signedOrders, - makerAssetFillAmount, - takerAddress, - makerAssetFillAmount, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const ordersInfo = await contractWrappers.exchange.getOrdersInfoAsync([signedOrder, anotherSignedOrder]); - expect(ordersInfo[0].orderStatus).to.be.equal(OrderStatus.FullyFilled); - expect(ordersInfo[1].orderStatus).to.be.equal(OrderStatus.FullyFilled); - }); - it('should throw when invalid transaction and shouldValidate is true', async () => { - const signedOrders = [signedOrder]; - // request more makerAsset than what is available - const makerAssetFillAmount = signedOrder.makerAssetAmount.plus(100); - return expect( - contractWrappers.forwarder.marketBuyOrdersWithEthAsync( - signedOrders, - makerAssetFillAmount, - takerAddress, - makerAssetFillAmount, - [], - 0, - constants.NULL_ADDRESS, - { - shouldValidate: true, - }, - ), - ).to.be.rejectedWith('COMPLETE_FILL_FAILED'); - }); - }); - describe('#marketSellOrdersWithEthAsync', () => { - it('should market sell orders with eth', async () => { - const signedOrders = [signedOrder, anotherSignedOrder]; - const makerAssetFillAmount = signedOrder.makerAssetAmount.plus(anotherSignedOrder.makerAssetAmount); - const txHash = await contractWrappers.forwarder.marketSellOrdersWithEthAsync( - signedOrders, - takerAddress, - makerAssetFillAmount, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const ordersInfo = await contractWrappers.exchange.getOrdersInfoAsync([signedOrder, anotherSignedOrder]); - expect(ordersInfo[0].orderStatus).to.be.equal(OrderStatus.FullyFilled); - expect(ordersInfo[1].orderStatus).to.be.equal(OrderStatus.Fillable); - expect(ordersInfo[1].orderTakerAssetFilledAmount).to.be.bignumber.equal(new BigNumber(4)); // only 95% of ETH is sold - }); - it('should throw when invalid transaction and shouldValidate is true', async () => { - // create an order with fees, we try to fill it but we do not provide enough ETH to cover the fees - const signedOrderWithFee = await fillScenarios.createFillableSignedOrderWithFeesAsync( - makerAssetData, - takerAssetData, - constants.ZERO_AMOUNT, - new BigNumber(100), - makerAddress, - constants.NULL_ADDRESS, - fillableAmount, - constants.NULL_ADDRESS, - ); - const signedOrders = [signedOrderWithFee]; - const makerAssetFillAmount = signedOrder.makerAssetAmount; - return expect( - contractWrappers.forwarder.marketSellOrdersWithEthAsync( - signedOrders, - takerAddress, - makerAssetFillAmount, - [], - 0, - constants.NULL_ADDRESS, - { - shouldValidate: true, - }, - ), - ).to.be.rejectedWith('COMPLETE_FILL_FAILED'); - }); - }); -}); diff --git a/packages/contract-wrappers/test/order_validator_wrapper_test.ts b/packages/contract-wrappers/test/order_validator_wrapper_test.ts deleted file mode 100644 index c61c05d312..0000000000 --- a/packages/contract-wrappers/test/order_validator_wrapper_test.ts +++ /dev/null @@ -1,146 +0,0 @@ -import { ContractAddresses } from '@0x/contract-addresses'; -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { FillScenarios } from '@0x/fill-scenarios'; -import { assetDataUtils } from '@0x/order-utils'; -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as chai from 'chai'; -import * as _ from 'lodash'; -import 'mocha'; - -import { ContractWrappers, OrderStatus } from '../src'; -import { OrderInfo, TraderInfo } from '../src/types'; - -import { chaiSetup } from './utils/chai_setup'; -import { constants } from './utils/constants'; -import { migrateOnceAsync } from './utils/migrate'; -import { tokenUtils } from './utils/token_utils'; -import { provider, web3Wrapper } from './utils/web3_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -describe('OrderValidator', () => { - const fillableAmount = new BigNumber(5); - let contractWrappers: ContractWrappers; - let fillScenarios: FillScenarios; - let exchangeContractAddress: string; - let zrxTokenAddress: string; - let zrxTokenAssetData: string; - let userAddresses: string[]; - let coinbase: string; - let makerAddress: string; - let takerAddress: string; - let feeRecipient: string; - let anotherMakerAddress: string; - let makerTokenAddress: string; - let takerTokenAddress: string; - let makerAssetData: string; - let takerAssetData: string; - let signedOrder: SignedOrder; - let anotherSignedOrder: SignedOrder; - let contractAddresses: ContractAddresses; - - before(async () => { - contractAddresses = await migrateOnceAsync(); - await blockchainLifecycle.startAsync(); - const config = { - networkId: constants.TESTRPC_NETWORK_ID, - contractAddresses, - blockPollingIntervalMs: 10, - }; - contractWrappers = new ContractWrappers(provider, config); - exchangeContractAddress = contractWrappers.exchange.address; - userAddresses = await web3Wrapper.getAvailableAddressesAsync(); - zrxTokenAddress = contractWrappers.exchange.zrxTokenAddress; - zrxTokenAssetData = assetDataUtils.encodeERC20AssetData(zrxTokenAddress); - fillScenarios = new FillScenarios( - provider, - userAddresses, - zrxTokenAddress, - exchangeContractAddress, - contractWrappers.erc20Proxy.address, - contractWrappers.erc721Proxy.address, - ); - [coinbase, makerAddress, takerAddress, feeRecipient, anotherMakerAddress] = userAddresses; - [makerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); - takerTokenAddress = contractAddresses.etherToken; - [makerAssetData, takerAssetData] = [ - assetDataUtils.encodeERC20AssetData(makerTokenAddress), - assetDataUtils.encodeERC20AssetData(takerTokenAddress), - ]; - - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - constants.NULL_ADDRESS, - fillableAmount, - ); - anotherSignedOrder = await fillScenarios.createFillableSignedOrderAsync( - zrxTokenAssetData, - takerAssetData, - makerAddress, - constants.NULL_ADDRESS, - fillableAmount, - ); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - describe('#getOrdersAndTradersInfoAsync', () => { - let signedOrders: SignedOrder[]; - let takerAddresses: string[]; - let ordersInfo: OrderInfo[]; - let tradersInfo: TraderInfo[]; - beforeEach(async () => { - signedOrders = [signedOrder, anotherSignedOrder]; - takerAddresses = [takerAddress, takerAddress]; - const ordersAndTradersInfo = await contractWrappers.orderValidator.getOrdersAndTradersInfoAsync( - signedOrders, - takerAddresses, - ); - ordersInfo = _.map(ordersAndTradersInfo, orderAndTraderInfo => orderAndTraderInfo.orderInfo); - tradersInfo = _.map(ordersAndTradersInfo, orderAndTraderInfo => orderAndTraderInfo.traderInfo); - }); - it('should return the same number of order infos and trader infos as input orders', async () => { - expect(ordersInfo.length).to.be.equal(signedOrders.length); - expect(tradersInfo.length).to.be.equal(takerAddresses.length); - }); - it('should return correct on-chain order info for input orders', async () => { - const firstOrderInfo = ordersInfo[0]; - const secondOrderInfo = ordersInfo[1]; - expect(firstOrderInfo.orderStatus).to.be.equal(OrderStatus.Fillable); - expect(firstOrderInfo.orderTakerAssetFilledAmount).to.bignumber.equal(constants.ZERO_AMOUNT); - expect(secondOrderInfo.orderStatus).to.be.equal(OrderStatus.Fillable); - expect(secondOrderInfo.orderTakerAssetFilledAmount).to.bignumber.equal(constants.ZERO_AMOUNT); - }); - it('should return correct on-chain trader info for input takers', async () => { - const firstTraderInfo = tradersInfo[0]; - const secondTraderInfo = tradersInfo[1]; - expect(firstTraderInfo.makerBalance).to.bignumber.equal(new BigNumber(5)); - expect(firstTraderInfo.makerAllowance).to.bignumber.equal(new BigNumber(5)); - expect(firstTraderInfo.takerBalance).to.bignumber.equal(new BigNumber(0)); - expect(firstTraderInfo.takerAllowance).to.bignumber.equal(new BigNumber(0)); - expect(firstTraderInfo.makerZrxBalance).to.bignumber.equal(new BigNumber(5)); - expect(firstTraderInfo.makerZrxAllowance).to.bignumber.equal(new BigNumber(5)); - expect(firstTraderInfo.takerZrxBalance).to.bignumber.equal(new BigNumber(0)); - expect(firstTraderInfo.takerZrxAllowance).to.bignumber.equal(new BigNumber(0)); - expect(secondTraderInfo.makerBalance).to.bignumber.equal(new BigNumber(5)); - expect(secondTraderInfo.makerAllowance).to.bignumber.equal(new BigNumber(5)); - expect(secondTraderInfo.takerBalance).to.bignumber.equal(new BigNumber(0)); - expect(secondTraderInfo.takerAllowance).to.bignumber.equal(new BigNumber(0)); - expect(secondTraderInfo.makerZrxBalance).to.bignumber.equal(new BigNumber(5)); - expect(secondTraderInfo.makerZrxAllowance).to.bignumber.equal(new BigNumber(5)); - expect(secondTraderInfo.takerZrxBalance).to.bignumber.equal(new BigNumber(0)); - expect(secondTraderInfo.takerZrxAllowance).to.bignumber.equal(new BigNumber(0)); - }); - }); -}); diff --git a/packages/contract-wrappers/test/revert_validation_test.ts b/packages/contract-wrappers/test/revert_validation_test.ts deleted file mode 100644 index 2660e33dc0..0000000000 --- a/packages/contract-wrappers/test/revert_validation_test.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { BlockchainLifecycle, devConstants, web3Factory } from '@0x/dev-utils'; -import { FillScenarios } from '@0x/fill-scenarios'; -import { runMigrationsAsync } from '@0x/migrations'; -import { assetDataUtils } from '@0x/order-utils'; -import { RevertReason, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as chai from 'chai'; -import 'mocha'; - -import { ContractWrappers } from '../src'; - -import { chaiSetup } from './utils/chai_setup'; -import { constants } from './utils/constants'; -import { tokenUtils } from './utils/token_utils'; - -chaiSetup.configure(); -const expect = chai.expect; - -describe('Revert Validation ExchangeWrapper', () => { - let contractWrappers: ContractWrappers; - let userAddresses: string[]; - let fillScenarios: FillScenarios; - let makerTokenAddress: string; - let takerTokenAddress: string; - let makerAddress: string; - let takerAddress: string; - let makerAssetData: string; - let takerAssetData: string; - let txHash: string; - let blockchainLifecycle: BlockchainLifecycle; - let web3Wrapper: Web3Wrapper; - const fillableAmount = new BigNumber(5); - const takerTokenFillAmount = new BigNumber(5); - let signedOrder: SignedOrder; - before(async () => { - // vmErrorsOnRPCResponse is useful for quick feedback and testing during development - // but is not the default behaviour in production. Here we ensure our failure cases - // are handled in an environment which behaves similar to production - const provider = web3Factory.getRpcProvider({ - shouldUseInProcessGanache: true, - shouldThrowErrorsOnGanacheRPCResponse: false, - }); - web3Wrapper = new Web3Wrapper(provider); - blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - // Re-deploy the artifacts in this provider, rather than in the default provider exposed in - // the beforeAll hook. This is due to the fact that the default provider enabled vmErrorsOnRPCResponse - // and we are explicity testing with vmErrorsOnRPCResponse disabled. - const txDefaults = { - gas: devConstants.GAS_LIMIT, - from: devConstants.TESTRPC_FIRST_ADDRESS, - }; - await blockchainLifecycle.startAsync(); - const contractAddresses = await runMigrationsAsync(provider, txDefaults); - const config = { - networkId: constants.TESTRPC_NETWORK_ID, - contractAddresses, - blockPollingIntervalMs: 10, - }; - contractWrappers = new ContractWrappers(provider, config); - userAddresses = await web3Wrapper.getAvailableAddressesAsync(); - fillScenarios = new FillScenarios( - provider, - userAddresses, - contractAddresses.zrxToken, - contractAddresses.exchange, - contractAddresses.erc20Proxy, - contractAddresses.erc721Proxy, - ); - [, makerAddress, takerAddress] = userAddresses; - [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); - [makerAssetData, takerAssetData] = [ - assetDataUtils.encodeERC20AssetData(makerTokenAddress), - assetDataUtils.encodeERC20AssetData(takerTokenAddress), - ]; - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - ); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - describe('#fillOrderAsync', () => { - it('should throw the revert reason when shouldValidate is true and a fill would revert', async () => { - // Create a scenario where the fill will revert - const makerTokenBalance = await contractWrappers.erc20Token.getBalanceAsync( - makerTokenAddress, - makerAddress, - ); - // Transfer all of the tokens from maker to create a failure scenario - txHash = await contractWrappers.erc20Token.transferAsync( - makerTokenAddress, - makerAddress, - takerAddress, - makerTokenBalance, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - const tx = contractWrappers.exchange.fillOrderAsync(signedOrder, takerTokenFillAmount, takerAddress, { - shouldValidate: true, - }); - return expect(tx).to.revertWith(RevertReason.TransferFailed); - }); - }); -}); diff --git a/packages/contract-wrappers/test/subscription_test.ts b/packages/contract-wrappers/test/subscription_test.ts deleted file mode 100644 index 0fa6af40d1..0000000000 --- a/packages/contract-wrappers/test/subscription_test.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { DoneCallback } from '@0x/types'; -import * as _ from 'lodash'; -import 'mocha'; -import * as Sinon from 'sinon'; - -import { - ContractWrappers, - ContractWrappersConfig, - DecodedLogEvent, - ERC20TokenApprovalEventArgs, - ERC20TokenEvents, -} from '../src'; - -import { chaiSetup } from './utils/chai_setup'; -import { constants } from './utils/constants'; -import { migrateOnceAsync } from './utils/migrate'; -import { tokenUtils } from './utils/token_utils'; -import { provider, web3Wrapper } from './utils/web3_wrapper'; - -chaiSetup.configure(); -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -describe('SubscriptionTest', () => { - let contractWrappers: ContractWrappers; - let config: ContractWrappersConfig; - - before(async () => { - const contractAddresses = await migrateOnceAsync(); - config = { - networkId: constants.TESTRPC_NETWORK_ID, - contractAddresses, - }; - contractWrappers = new ContractWrappers(provider, config); - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - describe('#subscribe', () => { - const indexFilterValues = {}; - let tokenAddress: string; - let stubs: Sinon.SinonStub[] = []; - before(() => { - const tokenAddresses = tokenUtils.getDummyERC20TokenAddresses(); - tokenAddress = tokenAddresses[0]; - }); - afterEach(() => { - contractWrappers.erc20Token.unsubscribeAll(); - _.each(stubs, s => s.restore()); - stubs = []; - }); - it('Should allow unsubscribeAll to be called successfully after an error', (done: DoneCallback) => { - (async () => { - const callback = (err: Error | null, _logEvent?: DecodedLogEvent) => - _.noop.bind(_); - contractWrappers.erc20Token.subscribe( - tokenAddress, - ERC20TokenEvents.Approval, - indexFilterValues, - callback, - ); - stubs = [ - Sinon.stub((contractWrappers as any)._web3Wrapper, 'getBlockIfExistsAsync').throws( - new Error('JSON RPC error'), - ), - ]; - contractWrappers.erc20Token.unsubscribeAll(); - done(); - })().catch(done); - }); - }); -}); diff --git a/packages/contract-wrappers/test/transaction_encoder_test.ts b/packages/contract-wrappers/test/transaction_encoder_test.ts deleted file mode 100644 index a996b9f088..0000000000 --- a/packages/contract-wrappers/test/transaction_encoder_test.ts +++ /dev/null @@ -1,210 +0,0 @@ -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { FillScenarios } from '@0x/fill-scenarios'; -import { assetDataUtils, generatePseudoRandomSalt, orderHashUtils, signatureUtils } from '@0x/order-utils'; -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import 'mocha'; - -import { ContractWrappers } from '../src'; -import { TransactionEncoder } from '../src/utils/transaction_encoder'; - -import { constants } from './utils/constants'; -import { migrateOnceAsync } from './utils/migrate'; -import { tokenUtils } from './utils/token_utils'; -import { provider, web3Wrapper } from './utils/web3_wrapper'; - -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -describe('TransactionEncoder', () => { - let contractWrappers: ContractWrappers; - let userAddresses: string[]; - let fillScenarios: FillScenarios; - let exchangeContractAddress: string; - let makerTokenAddress: string; - let takerTokenAddress: string; - let coinbase: string; - let makerAddress: string; - let senderAddress: string; - let takerAddress: string; - let makerAssetData: string; - let takerAssetData: string; - let txHash: string; - const fillableAmount = new BigNumber(5); - const takerTokenFillAmount = new BigNumber(5); - let signedOrder: SignedOrder; - - before(async () => { - const contractAddresses = await migrateOnceAsync(); - await blockchainLifecycle.startAsync(); - const config = { - networkId: constants.TESTRPC_NETWORK_ID, - contractAddresses, - blockPollingIntervalMs: 10, - }; - contractWrappers = new ContractWrappers(provider, config); - exchangeContractAddress = contractWrappers.exchange.address; - userAddresses = await web3Wrapper.getAvailableAddressesAsync(); - const zrxTokenAddress = contractWrappers.exchange.zrxTokenAddress; - fillScenarios = new FillScenarios( - provider, - userAddresses, - zrxTokenAddress, - exchangeContractAddress, - contractWrappers.erc20Proxy.address, - contractWrappers.erc721Proxy.address, - ); - [coinbase, makerAddress, takerAddress, senderAddress] = userAddresses; - [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); - [makerAssetData, takerAssetData] = [ - assetDataUtils.encodeERC20AssetData(makerTokenAddress), - assetDataUtils.encodeERC20AssetData(takerTokenAddress), - ]; - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - ); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - describe('encode and executeTransaction', () => { - const executeTransactionOrThrowAsync = async ( - encoder: TransactionEncoder, - data: string, - signerAddress: string = takerAddress, - ): Promise => { - const salt = generatePseudoRandomSalt(); - const transactionHash = encoder.getTransactionHashHex(data, salt, signerAddress); - const signature = await signatureUtils.ecSignHashAsync(provider, transactionHash, signerAddress); - txHash = await contractWrappers.exchange.executeTransactionAsync( - salt, - signerAddress, - data, - signature, - senderAddress, - ); - await web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - }; - describe('#fillOrderTx', () => { - it('should successfully execute the transaction', async () => { - const encoder = await contractWrappers.exchange.transactionEncoderAsync(); - const data = encoder.fillOrderTx(signedOrder, takerTokenFillAmount); - await executeTransactionOrThrowAsync(encoder, data); - }); - }); - describe('#fillOrderNoThrowTx', () => { - it('should successfully execute the transaction', async () => { - const encoder = await contractWrappers.exchange.transactionEncoderAsync(); - const data = encoder.fillOrderNoThrowTx(signedOrder, takerTokenFillAmount); - await executeTransactionOrThrowAsync(encoder, data); - }); - }); - describe('#fillOrKillOrderTx', () => { - it('should successfully execute the transaction', async () => { - const encoder = await contractWrappers.exchange.transactionEncoderAsync(); - const data = encoder.fillOrKillOrderTx(signedOrder, takerTokenFillAmount); - await executeTransactionOrThrowAsync(encoder, data); - }); - }); - describe('#marketSellOrdersTx', () => { - it('should successfully execute the transaction', async () => { - const encoder = await contractWrappers.exchange.transactionEncoderAsync(); - const data = encoder.marketSellOrdersTx([signedOrder], takerTokenFillAmount); - await executeTransactionOrThrowAsync(encoder, data); - }); - }); - describe('#marketSellOrdersNoThrowTx', () => { - it('should successfully execute the transaction', async () => { - const encoder = await contractWrappers.exchange.transactionEncoderAsync(); - const data = encoder.marketSellOrdersNoThrowTx([signedOrder], takerTokenFillAmount); - await executeTransactionOrThrowAsync(encoder, data); - }); - }); - describe('#marketBuyOrdersTx', () => { - it('should successfully execute the transaction', async () => { - const encoder = await contractWrappers.exchange.transactionEncoderAsync(); - const data = encoder.marketBuyOrdersTx([signedOrder], fillableAmount); - await executeTransactionOrThrowAsync(encoder, data); - }); - }); - describe('#marketBuyOrdersNoThrowTx', () => { - it('should successfully execute the transaction', async () => { - const encoder = await contractWrappers.exchange.transactionEncoderAsync(); - const data = encoder.marketBuyOrdersNoThrowTx([signedOrder], fillableAmount); - await executeTransactionOrThrowAsync(encoder, data); - }); - }); - describe('#preSignTx', () => { - it('should successfully execute the transaction', async () => { - const encoder = await contractWrappers.exchange.transactionEncoderAsync(); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - const signature = signedOrder.signature; - const data = encoder.preSignTx(orderHash, makerAddress, signature); - await executeTransactionOrThrowAsync(encoder, data); - }); - }); - describe('#setSignatureValidatorApprovalTx', () => { - it('should successfully execute the transaction', async () => { - const encoder = await contractWrappers.exchange.transactionEncoderAsync(); - const isApproved = true; - const data = encoder.setSignatureValidatorApprovalTx(senderAddress, isApproved); - await executeTransactionOrThrowAsync(encoder, data); - }); - }); - describe('#batchFillOrdersTx', () => { - it('should successfully execute the transaction', async () => { - const encoder = await contractWrappers.exchange.transactionEncoderAsync(); - const data = encoder.batchFillOrdersTx([signedOrder], [takerTokenFillAmount]); - await executeTransactionOrThrowAsync(encoder, data); - }); - }); - describe('#batchFillOrKillOrdersTx', () => { - it('should successfully execute the transaction', async () => { - const encoder = await contractWrappers.exchange.transactionEncoderAsync(); - const data = encoder.batchFillOrKillOrdersTx([signedOrder], [takerTokenFillAmount]); - await executeTransactionOrThrowAsync(encoder, data); - }); - }); - describe('#batchFillOrdersNoThrowTx', () => { - it('should successfully execute the transaction', async () => { - const encoder = await contractWrappers.exchange.transactionEncoderAsync(); - const data = encoder.batchFillOrdersNoThrowTx([signedOrder], [takerTokenFillAmount]); - await executeTransactionOrThrowAsync(encoder, data); - }); - }); - describe('#batchCancelOrdersTx', () => { - it('should successfully execute the transaction', async () => { - const encoder = await contractWrappers.exchange.transactionEncoderAsync(); - const data = encoder.batchCancelOrdersTx([signedOrder]); - const signerAddress = makerAddress; - await executeTransactionOrThrowAsync(encoder, data, signerAddress); - }); - }); - describe('#cancelOrderTx', () => { - it('should successfully execute the transaction', async () => { - const encoder = await contractWrappers.exchange.transactionEncoderAsync(); - const data = encoder.cancelOrderTx(signedOrder); - const signerAddress = makerAddress; - await executeTransactionOrThrowAsync(encoder, data, signerAddress); - }); - }); - describe('#cancelOrdersUpToTx', () => { - it('should successfully execute the transaction', async () => { - const encoder = await contractWrappers.exchange.transactionEncoderAsync(); - const targetEpoch = signedOrder.salt; - const data = encoder.cancelOrdersUpToTx(targetEpoch); - const signerAddress = makerAddress; - await executeTransactionOrThrowAsync(encoder, data, signerAddress); - }); - }); - }); -}); diff --git a/packages/contract-wrappers/test/utils/dutch_auction_utils.ts b/packages/contract-wrappers/test/utils/dutch_auction_utils.ts deleted file mode 100644 index 26de76bcda..0000000000 --- a/packages/contract-wrappers/test/utils/dutch_auction_utils.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { DummyERC20TokenContract } from '@0x/abi-gen-wrappers'; -import { assetDataUtils } from '@0x/order-utils'; -import { orderFactory } from '@0x/order-utils/lib/src/order_factory'; -import { SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; - -import { DutchAuctionWrapper } from '../../src/contract_wrappers/dutch_auction_wrapper'; - -import { constants } from './constants'; - -export class DutchAuctionUtils { - private readonly _web3Wrapper: Web3Wrapper; - private readonly _coinbase: string; - private readonly _exchangeAddress: string; - private readonly _erc20ProxyAddress: string; - - constructor(web3Wrapper: Web3Wrapper, coinbase: string, exchangeAddress: string, erc20ProxyAddress: string) { - this._web3Wrapper = web3Wrapper; - this._coinbase = coinbase; - this._exchangeAddress = exchangeAddress; - this._erc20ProxyAddress = erc20ProxyAddress; - } - public async createSignedSellOrderAsync( - auctionBeginTimeSections: BigNumber, - acutionEndTimeSeconds: BigNumber, - auctionBeginTakerAssetAmount: BigNumber, - auctionEndTakerAssetAmount: BigNumber, - makerAssetAmount: BigNumber, - makerAssetData: string, - takerAssetData: string, - makerAddress: string, - takerAddress: string, - senderAddress?: string, - makerFee?: BigNumber, - takerFee?: BigNumber, - feeRecipientAddress?: string, - ): Promise { - // Notes on sell order: - // - The `takerAssetAmount` is set to the `auctionEndTakerAssetAmount`, which is the lowest amount the - // the seller can expect to receive - // - The `makerAssetData` is overloaded to include the auction begin time and begin taker asset amount - const makerAssetDataWithAuctionDetails = DutchAuctionWrapper.encodeDutchAuctionAssetData( - makerAssetData, - auctionBeginTimeSections, - auctionBeginTakerAssetAmount, - ); - const signedOrder = await orderFactory.createSignedOrderAsync( - this._web3Wrapper.getProvider(), - makerAddress, - makerAssetAmount, - makerAssetDataWithAuctionDetails, - auctionEndTakerAssetAmount, - takerAssetData, - this._exchangeAddress, - { - takerAddress, - senderAddress, - makerFee, - takerFee, - feeRecipientAddress, - expirationTimeSeconds: acutionEndTimeSeconds, - }, - ); - const erc20AssetData = assetDataUtils.decodeERC20AssetData(makerAssetData); - await this._increaseERC20BalanceAndAllowanceAsync(erc20AssetData.tokenAddress, makerAddress, makerAssetAmount); - return signedOrder; - } - public async createSignedBuyOrderAsync( - sellOrder: SignedOrder, - buyerAddress: string, - senderAddress?: string, - makerFee?: BigNumber, - takerFee?: BigNumber, - feeRecipientAddress?: string, - expirationTimeSeconds?: BigNumber, - ): Promise { - const dutchAuctionData = DutchAuctionWrapper.decodeDutchAuctionData(sellOrder.makerAssetData); - // Notes on buy order: - // - The `makerAssetAmount` is set to `dutchAuctionData.beginAmount`, which is - // the highest amount the buyer would have to pay out at any point during the auction. - // - The `takerAssetAmount` is set to the seller's `makerAssetAmount`, as the buyer - // receives the entire amount being sold by the seller. - // - The `makerAssetData`/`takerAssetData` are reversed from the sell order - const signedOrder = await orderFactory.createSignedOrderAsync( - this._web3Wrapper.getProvider(), - buyerAddress, - dutchAuctionData.beginAmount, - sellOrder.takerAssetData, - sellOrder.makerAssetAmount, - sellOrder.makerAssetData, - sellOrder.domain.verifyingContractAddress, - { - senderAddress, - makerFee, - takerFee, - feeRecipientAddress, - expirationTimeSeconds, - }, - ); - const buyerERC20AssetData = assetDataUtils.decodeERC20AssetData(sellOrder.takerAssetData); - await this._increaseERC20BalanceAndAllowanceAsync( - buyerERC20AssetData.tokenAddress, - buyerAddress, - dutchAuctionData.beginAmount, - ); - return signedOrder; - } - private async _increaseERC20BalanceAndAllowanceAsync( - tokenAddress: string, - address: string, - amount: BigNumber, - ): Promise { - if (amount.isZero() || address === constants.NULL_ADDRESS) { - return; // noop - } - await Promise.all([ - this._increaseERC20BalanceAsync(tokenAddress, address, amount), - this._increaseERC20AllowanceAsync(tokenAddress, address, amount), - ]); - } - private async _increaseERC20BalanceAsync(tokenAddress: string, address: string, amount: BigNumber): Promise { - const erc20Token = new DummyERC20TokenContract( - tokenAddress, - this._web3Wrapper.getProvider(), - this._web3Wrapper.getContractDefaults(), - ); - const txHash = await erc20Token.transfer.sendTransactionAsync(address, amount, { - from: this._coinbase, - }); - await this._web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - } - private async _increaseERC20AllowanceAsync( - tokenAddress: string, - address: string, - amount: BigNumber, - ): Promise { - const erc20Token = new DummyERC20TokenContract( - tokenAddress, - this._web3Wrapper.getProvider(), - this._web3Wrapper.getContractDefaults(), - ); - const oldMakerAllowance = await erc20Token.allowance.callAsync(address, this._erc20ProxyAddress); - const newMakerAllowance = oldMakerAllowance.plus(amount); - const txHash = await erc20Token.approve.sendTransactionAsync(this._erc20ProxyAddress, newMakerAllowance, { - from: address, - }); - await this._web3Wrapper.awaitTransactionSuccessAsync(txHash, constants.AWAIT_TRANSACTION_MINED_MS); - } -} diff --git a/packages/contract-wrappers/test/utils/token_utils.ts b/packages/contract-wrappers/test/utils/token_utils.ts index 187a935b1b..903fa5b09d 100644 --- a/packages/contract-wrappers/test/utils/token_utils.ts +++ b/packages/contract-wrappers/test/utils/token_utils.ts @@ -1,7 +1,8 @@ -import { DummyERC721TokenContract } from '@0x/abi-gen-wrappers'; import { generatePseudoRandomSalt } from '@0x/order-utils'; import { BigNumber } from '@0x/utils'; +import { DummyERC721TokenContract } from '../../src/index'; + import { provider, txDefaults, web3Wrapper } from './web3_wrapper'; // Those addresses come from migrations. They're deterministic so it's relatively safe to hard-code them here. diff --git a/packages/contract-wrappers/tsconfig.json b/packages/contract-wrappers/tsconfig.json index 2ee711adcc..03390d35cc 100644 --- a/packages/contract-wrappers/tsconfig.json +++ b/packages/contract-wrappers/tsconfig.json @@ -4,5 +4,6 @@ "outDir": "lib", "rootDir": "." }, - "include": ["./src/**/*", "./test/**/*"] + "include": ["./src/**/*", "./test/**/*"], + "exclude": ["node_modules"] } diff --git a/packages/contract-wrappers/typedoc-tsconfig.json b/packages/contract-wrappers/typedoc-tsconfig.json index c9b0af1ae6..a4c669cb6d 100644 --- a/packages/contract-wrappers/typedoc-tsconfig.json +++ b/packages/contract-wrappers/typedoc-tsconfig.json @@ -3,5 +3,5 @@ "compilerOptions": { "outDir": "lib" }, - "include": ["./src/**/*", "./test/**/*"] + "include": ["./src/**/*"] } diff --git a/packages/contracts-gen/CHANGELOG.json b/packages/contracts-gen/CHANGELOG.json index 6d77252e41..21ca5fda87 100644 --- a/packages/contracts-gen/CHANGELOG.json +++ b/packages/contracts-gen/CHANGELOG.json @@ -8,6 +8,33 @@ } ] }, + { + "timestamp": 1565296576, + "version": "1.0.13", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1564604963, + "version": "1.0.12", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1563957393, + "version": "1.0.11", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563006338, "version": "1.0.10", diff --git a/packages/contracts-gen/CHANGELOG.md b/packages/contracts-gen/CHANGELOG.md index fb0d2c20fb..f537f0b6fc 100644 --- a/packages/contracts-gen/CHANGELOG.md +++ b/packages/contracts-gen/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v1.0.13 - _August 8, 2019_ + + * Dependencies updated + +## v1.0.12 - _July 31, 2019_ + + * Dependencies updated + +## v1.0.11 - _July 24, 2019_ + + * Dependencies updated + ## v1.0.10 - _July 13, 2019_ * Dependencies updated diff --git a/packages/contracts-gen/package.json b/packages/contracts-gen/package.json index 7d4036b906..c25cf93924 100644 --- a/packages/contracts-gen/package.json +++ b/packages/contracts-gen/package.json @@ -1,6 +1,6 @@ { "name": "@0x/contracts-gen", - "version": "1.0.10", + "version": "1.0.13", "engines": { "node": ">=6.12" }, @@ -27,12 +27,12 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/contracts-gen/README.md", "dependencies": { - "@0x/sol-resolver": "^2.0.8", - "@0x/sol-compiler": "^3.1.9", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "ethereum-types": "^2.1.3", + "@0x/sol-compiler": "^3.1.12", + "@0x/sol-resolver": "^2.0.9", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "ethereum-types": "^2.1.4", "lodash": "^4.17.11", "prettier": "^1.16.3", "to-snake-case": "^1.0.0" diff --git a/packages/dev-tools-pages/package.json b/packages/dev-tools-pages/package.json index 5bbfed010b..03f093b874 100644 --- a/packages/dev-tools-pages/package.json +++ b/packages/dev-tools-pages/package.json @@ -27,7 +27,6 @@ }, "license": "Apache-2.0", "dependencies": { - "@0x/react-shared": "^2.0.14", "basscss": "^8.0.3", "bowser": "^1.9.4", "highlight.js": "^9.13.1", diff --git a/packages/dev-utils/CHANGELOG.json b/packages/dev-utils/CHANGELOG.json index c420baa714..700134dc2c 100644 --- a/packages/dev-utils/CHANGELOG.json +++ b/packages/dev-utils/CHANGELOG.json @@ -1,6 +1,6 @@ [ { - "version": "2.3.1", + "version": "2.3.2", "changes": [ { "note": "`revertWith` mocha extensions now accept Promise-like objects instead of just Promises", @@ -9,7 +9,7 @@ ] }, { - "version": "2.3.0", + "version": "2.3.1", "changes": [ { "note": "Add `chaiSetup` function with `RevertError` testing support", @@ -21,6 +21,34 @@ } ] }, + { + "version": "2.3.0", + "changes": [ + { + "note": "Move `tokenUtils` here from `@0x/contract-wrappers`", + "pr": 2037 + } + ], + "timestamp": 1565296576 + }, + { + "timestamp": 1564604963, + "version": "2.2.6", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1563957393, + "version": "2.2.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563006338, "version": "2.2.4", diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index a9b091fd49..ecfbfc062f 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.3.0 - _August 8, 2019_ + + * Move `tokenUtils` here from `@0x/contract-wrappers` (#2037) + +## v2.2.6 - _July 31, 2019_ + + * Dependencies updated + +## v2.2.5 - _July 24, 2019_ + + * Dependencies updated + ## v2.2.4 - _July 13, 2019_ * Dependencies updated diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 451f094f9a..61e6954142 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,6 +1,6 @@ { "name": "@0x/dev-utils", - "version": "2.2.4", + "version": "2.3.0", "engines": { "node": ">=6.12" }, @@ -32,9 +32,9 @@ "devDependencies": { "@0x/tslint-config": "^3.0.1", "@types/lodash": "4.14.104", - "@types/mocha": "^2.2.42", + "@types/mocha": "^5.2.7", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "shx": "^0.2.2", @@ -42,17 +42,17 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/subproviders": "^4.1.1", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", + "@0x/subproviders": "^5.0.1", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", "@types/web3-provider-engine": "^14.0.0", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^3.0.0", "dirty-chai": "^2.0.1", - "ethereum-types": "^2.1.3", + "ethereum-types": "^2.1.4", "lodash": "^4.17.11" }, "publishConfig": { diff --git a/packages/dev-utils/src/index.ts b/packages/dev-utils/src/index.ts index 3872bc5a30..d3ef1cfe5f 100644 --- a/packages/dev-utils/src/index.ts +++ b/packages/dev-utils/src/index.ts @@ -4,3 +4,4 @@ export { constants as devConstants } from './constants'; export { env, EnvVars } from './env'; export { callbackErrorReporter } from './callback_error_reporter'; export { chaiSetup } from './chai_setup'; +export { tokenUtils } from './token_utils'; diff --git a/packages/dev-utils/src/token_utils.ts b/packages/dev-utils/src/token_utils.ts new file mode 100644 index 0000000000..1d4ee6b2ca --- /dev/null +++ b/packages/dev-utils/src/token_utils.ts @@ -0,0 +1,21 @@ +// Those addresses come from migrations. They're deterministic so it's relatively safe to hard-code them here. +// Before we were fetching them from the TokenRegistry but now we can't as it's deprecated and removed. +// TODO(albrow): Import these from the migrations package instead of hard-coding them. +const DUMMY_ERC_20_ADRESSES = [ + '0x34d402f14d58e001d8efbe6585051bf9706aa064', + '0x25b8fe1de9daf8ba351890744ff28cf7dfa8f5e3', + '0xcdb594a32b1cc3479d8746279712c39d18a07fc0', + '0x1e2f9e10d02a6b8f8f69fcbf515e75039d2ea30d', + '0xbe0037eaf2d64fe5529bca93c18c9702d3930376', +]; + +const DUMMY_ERC_721_ADRESSES = ['0x07f96aa816c1f244cbc6ef114bb2b023ba54a2eb']; + +export const tokenUtils = { + getDummyERC20TokenAddresses(): string[] { + return DUMMY_ERC_20_ADRESSES; + }, + getDummyERC721TokenAddresses(): string[] { + return DUMMY_ERC_721_ADRESSES; + }, +}; diff --git a/packages/ethereum-types/CHANGELOG.json b/packages/ethereum-types/CHANGELOG.json index 31669a353a..04403e9292 100644 --- a/packages/ethereum-types/CHANGELOG.json +++ b/packages/ethereum-types/CHANGELOG.json @@ -15,7 +15,8 @@ "note": "new interface TupleDataItem, a DataItem that definitely has a `components` field", "pr": 1919 } - ] + ], + "timestamp": 1563957393 }, { "version": "2.1.3", diff --git a/packages/ethereum-types/CHANGELOG.md b/packages/ethereum-types/CHANGELOG.md index d9a5d4d65a..5bf5ea771a 100644 --- a/packages/ethereum-types/CHANGELOG.md +++ b/packages/ethereum-types/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.1.4 - _July 24, 2019_ + + * new interface TupleDataItem, a DataItem that definitely has a `components` field (#1919) + ## v2.1.3 - _July 13, 2019_ * Made most fields in DevdocOutput optional, as they may not all be present just because devdoc is (#1878) diff --git a/packages/ethereum-types/package.json b/packages/ethereum-types/package.json index 3cbfd76001..b3e0acf1d0 100644 --- a/packages/ethereum-types/package.json +++ b/packages/ethereum-types/package.json @@ -1,6 +1,6 @@ { "name": "ethereum-types", - "version": "2.1.3", + "version": "2.1.4", "engines": { "node": ">=6.12" }, diff --git a/packages/fill-scenarios/CHANGELOG.json b/packages/fill-scenarios/CHANGELOG.json index 2ae93fb17b..d275d68346 100644 --- a/packages/fill-scenarios/CHANGELOG.json +++ b/packages/fill-scenarios/CHANGELOG.json @@ -12,6 +12,33 @@ } ] }, + { + "timestamp": 1565296576, + "version": "3.0.16", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1564604963, + "version": "3.0.15", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1563957393, + "version": "3.0.14", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563193019, "version": "3.0.13", diff --git a/packages/fill-scenarios/CHANGELOG.md b/packages/fill-scenarios/CHANGELOG.md index 7d4ffdda28..9387942baa 100644 --- a/packages/fill-scenarios/CHANGELOG.md +++ b/packages/fill-scenarios/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.0.16 - _August 8, 2019_ + + * Dependencies updated + +## v3.0.15 - _July 31, 2019_ + + * Dependencies updated + +## v3.0.14 - _July 24, 2019_ + + * Dependencies updated + ## v3.0.13 - _July 15, 2019_ * Dependencies updated diff --git a/packages/fill-scenarios/package.json b/packages/fill-scenarios/package.json index 9fa1733832..3f16671a14 100644 --- a/packages/fill-scenarios/package.json +++ b/packages/fill-scenarios/package.json @@ -1,6 +1,6 @@ { "name": "@0x/fill-scenarios", - "version": "3.0.13", + "version": "3.0.16", "description": "0x order fill scenario generator", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -29,14 +29,14 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/abi-gen-wrappers": "^5.0.2", - "@0x/base-contract": "^5.1.1", - "@0x/order-utils": "^8.2.2", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", - "ethereum-types": "^2.1.3", + "@0x/abi-gen-wrappers": "^5.2.0", + "@0x/base-contract": "^5.3.1", + "@0x/order-utils": "^8.2.5", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", + "ethereum-types": "^2.1.4", "ethers": "~4.0.4", "lodash": "^4.17.11" }, diff --git a/packages/instant/package.json b/packages/instant/package.json index 159cdd999b..4dc1ccc5c0 100644 --- a/packages/instant/package.json +++ b/packages/instant/package.json @@ -1,6 +1,6 @@ { "name": "@0x/instant", - "version": "1.0.27", + "version": "1.0.28", "engines": { "node": ">=6.12" }, @@ -43,19 +43,19 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/instant/README.md", "dependencies": { - "@0x/assert": "^2.1.0", - "@0x/asset-buyer": "6.1.4", - "@0x/json-schemas": "^3.0.11", - "@0x/order-utils": "^8.2.2", - "@0x/subproviders": "^4.1.1", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", + "@0x/assert": "^2.1.3", + "@0x/asset-buyer": "6.1.8", + "@0x/json-schemas": "^3.1.13", + "@0x/order-utils": "^8.2.5", + "@0x/subproviders": "^5.0.1", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", "babel-runtime": "^6.26.0", "bowser": "^1.9.4", "copy-to-clipboard": "^3.0.8", - "ethereum-types": "^2.1.3", + "ethereum-types": "^2.1.4", "lodash": "^4.17.11", "polished": "^1.9.2", "react": "^16.5.2", diff --git a/packages/json-schemas/CHANGELOG.json b/packages/json-schemas/CHANGELOG.json index 02a958223d..61a3462543 100644 --- a/packages/json-schemas/CHANGELOG.json +++ b/packages/json-schemas/CHANGELOG.json @@ -1,6 +1,6 @@ [ { - "version": "3.2.0", + "version": "4.0.1", "changes": [ { "note": "Add `eip712DomainSchema` schema", @@ -20,13 +20,40 @@ } ] }, + { + "version": "4.0.0", + "changes": [ + { + "note": "Removed @0x/order-watcher" + } + ] + }, + { + "timestamp": 1565296576, + "version": "3.1.13", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1564604963, + "version": "3.1.12", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "3.1.11", "changes": [ { "note": "permit mixed-case addresses" } - ] + ], + "timestamp": 1563957393 }, { "timestamp": 1563006338, diff --git a/packages/json-schemas/CHANGELOG.md b/packages/json-schemas/CHANGELOG.md index f57fb5257f..84e3b26bcf 100644 --- a/packages/json-schemas/CHANGELOG.md +++ b/packages/json-schemas/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.1.13 - _August 8, 2019_ + + * Dependencies updated + +## v3.1.12 - _July 31, 2019_ + + * Dependencies updated + +## v3.1.11 - _July 24, 2019_ + + * permit mixed-case addresses + ## v3.0.11 - _July 13, 2019_ * Dependencies updated diff --git a/packages/json-schemas/package.json b/packages/json-schemas/package.json index 0b67ce56aa..f44bdcee2d 100644 --- a/packages/json-schemas/package.json +++ b/packages/json-schemas/package.json @@ -1,6 +1,6 @@ { "name": "@0x/json-schemas", - "version": "3.0.11", + "version": "3.1.13", "engines": { "node": ">=6.12" }, @@ -40,22 +40,22 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/json-schemas/README.md", "dependencies": { - "@0x/typescript-typings": "^4.2.3", + "@0x/typescript-typings": "^4.2.4", "@types/node": "*", "jsonschema": "^1.2.0", "lodash.values": "^4.3.0" }, "devDependencies": { "@0x/tslint-config": "^3.0.1", - "@0x/utils": "^4.4.0", + "@0x/utils": "^4.5.0", "@types/lodash.foreach": "^4.5.3", "@types/lodash.values": "^4.3.3", - "@types/mocha": "^2.2.42", + "@types/mocha": "^5.2.7", "chai": "^4.0.1", "dirty-chai": "^2.0.1", "lodash.foreach": "^4.5.0", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "shx": "^0.2.2", diff --git a/packages/json-schemas/schemas/order_watcher_web_socket_request_schema.json b/packages/json-schemas/schemas/order_watcher_web_socket_request_schema.json deleted file mode 100644 index b0c419f94f..0000000000 --- a/packages/json-schemas/schemas/order_watcher_web_socket_request_schema.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "id": "/orderWatcherWebSocketRequestSchema", - "type": "object", - "definitions": { - "signedOrderParam": { - "type": "object", - "properties": { - "signedOrder": { "$ref": "/signedOrderSchema" } - }, - "required": ["signedOrder"] - }, - "orderHashParam": { - "type": "object", - "properties": { - "orderHash": { "$ref": "/hexSchema" } - }, - "required": ["orderHash"] - } - }, - "oneOf": [ - { - "type": "object", - "properties": { - "id": { "type": "number" }, - "jsonrpc": { "type": "string" }, - "method": { "enum": ["ADD_ORDER"] }, - "params": { "$ref": "#/definitions/signedOrderParam" } - }, - "required": ["id", "jsonrpc", "method", "params"] - }, - { - "type": "object", - "properties": { - "id": { "type": "number" }, - "jsonrpc": { "type": "string" }, - "method": { "enum": ["REMOVE_ORDER"] }, - "params": { "$ref": "#/definitions/orderHashParam" } - }, - "required": ["id", "jsonrpc", "method", "params"] - }, - { - "type": "object", - "properties": { - "id": { "type": "number" }, - "jsonrpc": { "type": "string" }, - "method": { "enum": ["GET_STATS"] }, - "params": {} - }, - "required": ["id", "jsonrpc", "method"] - } - ] -} \ No newline at end of file diff --git a/packages/json-schemas/schemas/order_watcher_web_socket_utf8_message_schema.json b/packages/json-schemas/schemas/order_watcher_web_socket_utf8_message_schema.json deleted file mode 100644 index 154d6d754d..0000000000 --- a/packages/json-schemas/schemas/order_watcher_web_socket_utf8_message_schema.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "id": "/orderWatcherWebSocketUtf8MessageSchema", - "properties": { - "utf8Data": { "type": "string" } - }, - "required": [ - "utf8Data" - ], - "type": "object" -} diff --git a/packages/json-schemas/src/schemas.ts b/packages/json-schemas/src/schemas.ts index a79bcfc7e4..7c05322fd9 100644 --- a/packages/json-schemas/src/schemas.ts +++ b/packages/json-schemas/src/schemas.ts @@ -17,8 +17,6 @@ import * as orderFillOrKillRequestsSchema from '../schemas/order_fill_or_kill_re import * as orderFillRequestsSchema from '../schemas/order_fill_requests_schema.json'; import * as orderHashSchema from '../schemas/order_hash_schema.json'; import * as orderSchema from '../schemas/order_schema.json'; -import * as orderWatcherWebSocketRequestSchema from '../schemas/order_watcher_web_socket_request_schema.json'; -import * as orderWatcherWebSocketUtf8MessageSchema from '../schemas/order_watcher_web_socket_utf8_message_schema.json'; import * as orderBookRequestSchema from '../schemas/orderbook_request_schema.json'; import * as ordersRequestOptsSchema from '../schemas/orders_request_opts_schema.json'; import * as ordersSchema from '../schemas/orders_schema.json'; @@ -70,8 +68,6 @@ export const schemas = { jsNumber, requestOptsSchema, pagedRequestOptsSchema, - orderWatcherWebSocketRequestSchema, - orderWatcherWebSocketUtf8MessageSchema, ordersRequestOptsSchema, orderBookRequestSchema, orderConfigRequestSchema, diff --git a/packages/json-schemas/tsconfig.json b/packages/json-schemas/tsconfig.json index 25d5f306fb..84cd571ffb 100644 --- a/packages/json-schemas/tsconfig.json +++ b/packages/json-schemas/tsconfig.json @@ -24,8 +24,6 @@ "./schemas/order_schema.json", "./schemas/signed_order_schema.json", "./schemas/orders_schema.json", - "./schemas/order_watcher_web_socket_request_schema.json", - "./schemas/order_watcher_web_socket_utf8_message_schema.json", "./schemas/paginated_collection_schema.json", "./schemas/relayer_api_asset_data_pairs_response_schema.json", "./schemas/relayer_api_asset_data_pairs_schema.json", diff --git a/packages/migrations/CHANGELOG.json b/packages/migrations/CHANGELOG.json index e9ba387f3a..09862d5de8 100644 --- a/packages/migrations/CHANGELOG.json +++ b/packages/migrations/CHANGELOG.json @@ -1,6 +1,6 @@ [ { - "version": "4.2.0", + "version": "4.4.0", "changes": [ { "note": "Update Coordinator and Exchange deployments to pass `chainId`", @@ -8,6 +8,44 @@ } ] }, + { + "version": "4.3.0", + "changes": [ + { + "note": "Added DevUtils to migration script", + "pr": 2060 + } + ] + }, + { + "version": "4.2.0", + "changes": [ + { + "note": "Added StaticCallAssetProxy and ERC1155AssetProxy", + "pr": 2021 + } + ], + "timestamp": 1565296576 + }, + { + "version": "4.1.11", + "changes": [ + { + "note": "Updated calls to .deploy0xArtifactAsync to include log decode dependencies.", + "pr": 1995 + } + ], + "timestamp": 1564604963 + }, + { + "timestamp": 1563957393, + "version": "4.1.10", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563193019, "version": "4.1.9", diff --git a/packages/migrations/CHANGELOG.md b/packages/migrations/CHANGELOG.md index 4e829a8aed..93ae690c5f 100644 --- a/packages/migrations/CHANGELOG.md +++ b/packages/migrations/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v4.2.0 - _August 8, 2019_ + + * Added StaticCallAssetProxy and ERC1155AssetProxy (#2021) + +## v4.1.11 - _July 31, 2019_ + + * Updated calls to .deploy0xArtifactAsync to include log decode dependencies. (#1995) + +## v4.1.10 - _July 24, 2019_ + + * Dependencies updated + ## v4.1.9 - _July 15, 2019_ * Dependencies updated diff --git a/packages/migrations/package.json b/packages/migrations/package.json index 6534fc2a93..13d13390b6 100644 --- a/packages/migrations/package.json +++ b/packages/migrations/package.json @@ -1,6 +1,6 @@ { "name": "@0x/migrations", - "version": "4.1.9", + "version": "4.2.0", "engines": { "node": ">=6.12" }, @@ -21,7 +21,8 @@ "build:snapshot": "rm -rf ${npm_package_config_snapshot_name} && yarn migrate:v2:snapshot && zip -r \"${npm_package_config_snapshot_name}-${npm_package_version}.zip\" ${npm_package_config_snapshot_name}", "build:snapshot:docker": "docker build --tag ${npm_package_config_docker_snapshot_name}:${npm_package_version} --tag ${npm_package_config_docker_snapshot_name}:latest .", "publish:snapshot": "aws s3 cp ${npm_package_config_snapshot_name}-${npm_package_version}.zip ${npm_package_config_s3_snapshot_bucket} && aws s3 cp ${npm_package_config_s3_snapshot_bucket}/${npm_package_config_snapshot_name}-${npm_package_version}.zip ${npm_package_config_s3_snapshot_bucket}/${npm_package_config_snapshot_name}-latest.zip", - "publish:snapshot:docker": "docker push ${npm_package_config_docker_snapshot_name}:latest" + "publish:snapshot:docker": "docker push ${npm_package_config_docker_snapshot_name}:latest", + "test_contract_configs": "node ./lib/test_contract_configs.js" }, "config": { "s3_snapshot_bucket": "s3://ganache-snapshots.0x.org", @@ -36,9 +37,9 @@ }, "license": "Apache-2.0", "devDependencies": { - "@0x/dev-utils": "^2.2.4", + "@0x/dev-utils": "^2.3.0", "@0x/tslint-config": "^3.0.1", - "@0x/types": "^2.4.0", + "@0x/types": "^2.4.1", "@types/yargs": "^11.0.0", "make-promises-safe": "^1.1.0", "npm-run-all": "^4.1.2", @@ -50,19 +51,19 @@ "yargs": "^10.0.3" }, "dependencies": { - "@0x/abi-gen-wrappers": "^5.0.2", - "@0x/base-contract": "^5.1.1", - "@0x/contract-addresses": "^3.0.2", - "@0x/contract-artifacts": "^2.0.1", - "@0x/order-utils": "^8.2.2", - "@0x/sol-compiler": "^3.1.9", - "@0x/subproviders": "^4.1.1", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", + "@0x/abi-gen-wrappers": "^5.2.0", + "@0x/base-contract": "^5.3.1", + "@0x/contract-addresses": "^3.0.3", + "@0x/contract-artifacts": "^2.0.4", + "@0x/order-utils": "^8.2.5", + "@0x/sol-compiler": "^3.1.12", + "@0x/subproviders": "^5.0.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", "@ledgerhq/hw-app-eth": "^4.3.0", "@types/web3-provider-engine": "^14.0.0", - "ethereum-types": "^2.1.3", + "ethereum-types": "^2.1.4", "ethers": "~4.0.4", "lodash": "^4.17.11" }, diff --git a/packages/migrations/src/migration.ts b/packages/migrations/src/migration.ts index ecb9fb5b17..b6ca254959 100644 --- a/packages/migrations/src/migration.ts +++ b/packages/migrations/src/migration.ts @@ -29,11 +29,13 @@ export async function runMigrationsAsync( artifacts.ERC20Proxy, provider, txDefaults, + artifacts, ); const erc721Proxy = await wrappers.ERC721ProxyContract.deployFrom0xArtifactAsync( artifacts.ERC721Proxy, provider, txDefaults, + artifacts, ); // ZRX @@ -41,10 +43,16 @@ export async function runMigrationsAsync( artifacts.ZRXToken, provider, txDefaults, + artifacts, ); // Ether token - const etherToken = await wrappers.WETH9Contract.deployFrom0xArtifactAsync(artifacts.WETH9, provider, txDefaults); + const etherToken = await wrappers.WETH9Contract.deployFrom0xArtifactAsync( + artifacts.WETH9, + provider, + txDefaults, + artifacts, + ); // Exchange const zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address); @@ -52,6 +60,7 @@ export async function runMigrationsAsync( artifacts.Exchange, provider, txDefaults, + artifacts, zrxAssetData, ); @@ -63,6 +72,7 @@ export async function runMigrationsAsync( artifacts.DummyERC20Token, provider, txDefaults, + artifacts, token.name, token.symbol, token.decimals, @@ -76,14 +86,31 @@ export async function runMigrationsAsync( artifacts.DummyERC721Token, provider, txDefaults, + artifacts, erc721TokenInfo[0].name, erc721TokenInfo[0].symbol, ); + // 1155 Asset Proxy + const erc1155Proxy = await wrappers.ERC1155ProxyContract.deployFrom0xArtifactAsync( + artifacts.ERC1155Proxy, + provider, + txDefaults, + artifacts, + ); + + const staticCallProxy = await wrappers.StaticCallProxyContract.deployFrom0xArtifactAsync( + artifacts.StaticCallProxy, + provider, + txDefaults, + artifacts, + ); + const multiAssetProxy = await wrappers.MultiAssetProxyContract.deployFrom0xArtifactAsync( artifacts.MultiAssetProxy, provider, txDefaults, + artifacts, ); await web3Wrapper.awaitTransactionSuccessAsync( @@ -92,6 +119,9 @@ export async function runMigrationsAsync( await web3Wrapper.awaitTransactionSuccessAsync( await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, txDefaults), ); + await web3Wrapper.awaitTransactionSuccessAsync( + await erc1155Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, txDefaults), + ); await web3Wrapper.awaitTransactionSuccessAsync( await multiAssetProxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, txDefaults), ); @@ -103,12 +133,21 @@ export async function runMigrationsAsync( await web3Wrapper.awaitTransactionSuccessAsync( await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, txDefaults), ); + await web3Wrapper.awaitTransactionSuccessAsync( + await erc1155Proxy.addAuthorizedAddress.sendTransactionAsync(multiAssetProxy.address, txDefaults), + ); await web3Wrapper.awaitTransactionSuccessAsync( await multiAssetProxy.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, txDefaults), ); await web3Wrapper.awaitTransactionSuccessAsync( await multiAssetProxy.registerAssetProxy.sendTransactionAsync(erc721Proxy.address, txDefaults), ); + await web3Wrapper.awaitTransactionSuccessAsync( + await multiAssetProxy.registerAssetProxy.sendTransactionAsync(erc1155Proxy.address, txDefaults), + ); + await web3Wrapper.awaitTransactionSuccessAsync( + await multiAssetProxy.registerAssetProxy.sendTransactionAsync(staticCallProxy.address, txDefaults), + ); // Register the Asset Proxies to the Exchange await web3Wrapper.awaitTransactionSuccessAsync( @@ -117,15 +156,22 @@ export async function runMigrationsAsync( await web3Wrapper.awaitTransactionSuccessAsync( await exchange.registerAssetProxy.sendTransactionAsync(erc721Proxy.address, txDefaults), ); + await web3Wrapper.awaitTransactionSuccessAsync( + await exchange.registerAssetProxy.sendTransactionAsync(erc1155Proxy.address, txDefaults), + ); await web3Wrapper.awaitTransactionSuccessAsync( await exchange.registerAssetProxy.sendTransactionAsync(multiAssetProxy.address, txDefaults), ); + await web3Wrapper.awaitTransactionSuccessAsync( + await exchange.registerAssetProxy.sendTransactionAsync(staticCallProxy.address, txDefaults), + ); // Forwarder const forwarder = await wrappers.ForwarderContract.deployFrom0xArtifactAsync( artifacts.Forwarder, provider, txDefaults, + artifacts, exchange.address, assetDataUtils.encodeERC20AssetData(zrxToken.address), assetDataUtils.encodeERC20AssetData(etherToken.address), @@ -136,6 +182,7 @@ export async function runMigrationsAsync( artifacts.OrderValidator, provider, txDefaults, + artifacts, exchange.address, zrxAssetData, ); @@ -145,6 +192,7 @@ export async function runMigrationsAsync( artifacts.DutchAuction, provider, txDefaults, + artifacts, exchange.address, ); @@ -159,6 +207,7 @@ export async function runMigrationsAsync( artifacts.AssetProxyOwner, provider, txDefaults, + artifacts, owners, [erc20Proxy.address, erc721Proxy.address, multiAssetProxy.address], confirmationsRequired, @@ -172,6 +221,9 @@ export async function runMigrationsAsync( await web3Wrapper.awaitTransactionSuccessAsync( await erc721Proxy.transferOwnership.sendTransactionAsync(assetProxyOwner.address, txDefaults), ); + await web3Wrapper.awaitTransactionSuccessAsync( + await erc1155Proxy.transferOwnership.sendTransactionAsync(assetProxyOwner.address, txDefaults), + ); await web3Wrapper.awaitTransactionSuccessAsync( await multiAssetProxy.transferOwnership.sendTransactionAsync(assetProxyOwner.address, txDefaults), ); @@ -188,6 +240,7 @@ export async function runMigrationsAsync( artifacts.CoordinatorRegistry, provider, txDefaults, + artifacts, ); // Coordinator @@ -195,12 +248,24 @@ export async function runMigrationsAsync( artifacts.Coordinator, provider, txDefaults, + artifacts, exchange.address, ); + // Dev Utils + const devUtils = await wrappers.DevUtilsContract.deployFrom0xArtifactAsync( + artifacts.DevUtils, + provider, + txDefaults, + artifacts, + exchange.address, + zrxAssetData, + ); + const contractAddresses = { erc20Proxy: erc20Proxy.address, erc721Proxy: erc721Proxy.address, + erc1155Proxy: erc1155Proxy.address, zrxToken: zrxToken.address, etherToken: etherToken.address, exchange: exchange.address, @@ -210,6 +275,9 @@ export async function runMigrationsAsync( dutchAuction: dutchAuction.address, coordinatorRegistry: coordinatorRegistry.address, coordinator: coordinator.address, + multiAssetProxy: multiAssetProxy.address, + staticCallProxy: staticCallProxy.address, + devUtils: devUtils.address, }; return contractAddresses; diff --git a/packages/migrations/src/test_contract_configs.ts b/packages/migrations/src/test_contract_configs.ts new file mode 100644 index 0000000000..33e15090a9 --- /dev/null +++ b/packages/migrations/src/test_contract_configs.ts @@ -0,0 +1,175 @@ +#!/usr/bin/env node +import * as wrappers from '@0x/abi-gen-wrappers'; +import { getContractAddressesForNetworkOrThrow } from '@0x/contract-addresses'; +import { EmptyWalletSubprovider, RPCSubprovider, Web3ProviderEngine } from '@0x/subproviders'; +import { AssetProxyId } from '@0x/types'; +import { logUtils, providerUtils } from '@0x/utils'; +import { Web3Wrapper } from '@0x/web3-wrapper'; +import { SupportedProvider } from 'ethereum-types'; + +// NOTE: add your own Infura Project ID to RPC urls before running +const networkIdToRpcUrl = { + 1: 'https://mainnet.infura.io/v3/', + 3: 'https://ropsten.infura.io/v3/', + 4: 'https://rinkeby.infura.io/v3/', + 42: 'https://kovan.infura.io/v3/', +}; + +async function testContractConfigsAsync(provider: SupportedProvider): Promise { + const web3Wrapper = new Web3Wrapper(provider); + const networkId = await web3Wrapper.getNetworkIdAsync(); + const addresses = getContractAddressesForNetworkOrThrow(networkId); + + function warnIfMismatch(actual: any, expected: any, message: string): void { + if (actual !== expected) { + logUtils.warn(`${message}: actual: ${actual}, expected: ${expected}, networkId: ${networkId}`); + } + } + + const exchange = new wrappers.ExchangeContract(addresses.exchange, provider); + const erc20Proxy = new wrappers.ERC20ProxyContract(addresses.erc20Proxy, provider); + const erc721Proxy = new wrappers.ERC721ProxyContract(addresses.erc721Proxy, provider); + const erc1155Proxy = new wrappers.ERC1155ProxyContract(addresses.erc1155Proxy, provider); + const multiAssetProxy = new wrappers.MultiAssetProxyContract(addresses.multiAssetProxy, provider); + const assetProxyOwner = new wrappers.AssetProxyOwnerContract(addresses.assetProxyOwner, provider); + + // Verify Exchange configs + const exchangeOwner = await exchange.owner.callAsync(); + warnIfMismatch(exchangeOwner, assetProxyOwner.address, 'Unexpected Exchange owner'); + + const registeredERC20Proxy = await exchange.getAssetProxy.callAsync(AssetProxyId.ERC20); + warnIfMismatch(registeredERC20Proxy, erc20Proxy.address, 'Unexpected ERC20Proxy registered in Exchange'); + + const registeredERC721Proxy = await exchange.getAssetProxy.callAsync(AssetProxyId.ERC721); + warnIfMismatch(registeredERC721Proxy, erc721Proxy.address, 'Unexpected ERC721Proxy registered in Exchange'); + + const registeredERC1155Proxy = await exchange.getAssetProxy.callAsync(AssetProxyId.ERC1155); + warnIfMismatch(registeredERC1155Proxy, erc1155Proxy.address, 'Unexpected ERC1155Proxy registered in Exchange'); + + const registeredMultiAssetProxy = await exchange.getAssetProxy.callAsync(AssetProxyId.MultiAsset); + warnIfMismatch( + registeredMultiAssetProxy, + multiAssetProxy.address, + 'Unexpected MultiAssetProxy registered in Exchange', + ); + + const registeredStaticCallProxy = await exchange.getAssetProxy.callAsync(AssetProxyId.StaticCall); + warnIfMismatch( + registeredStaticCallProxy, + addresses.staticCallProxy, + 'Unexpected StaticCallProxy registered in Exchange', + ); + + // Verify ERC20Proxy configs + const erc20ProxyOwner = await erc20Proxy.owner.callAsync(); + warnIfMismatch(erc20ProxyOwner, assetProxyOwner.address, 'Unexpected ERC20Proxy owner'); + + const erc20AuthorizedAddresses = await erc20Proxy.getAuthorizedAddresses.callAsync(); + warnIfMismatch(erc20AuthorizedAddresses.length, 2, 'Unexpected number of authorized addresses in ERC20Proxy'); + + const isExchangeAuthorizedInERC20Proxy = await erc20Proxy.authorized.callAsync(exchange.address); + warnIfMismatch(isExchangeAuthorizedInERC20Proxy, true, 'Exchange not authorized in ERC20Proxy'); + + const isMAPAuthorizedInER20Proxy = await erc20Proxy.authorized.callAsync(multiAssetProxy.address); + warnIfMismatch(isMAPAuthorizedInER20Proxy, true, 'MultiAssetProxy not authorized in ERC20Proxy'); + + // Verify ERC721Proxy configs + const erc721ProxyOwner = await erc721Proxy.owner.callAsync(); + warnIfMismatch(erc721ProxyOwner, assetProxyOwner.address, 'Unexpected ERC721Proxy owner'); + + const erc721AuthorizedAddresses = await erc721Proxy.getAuthorizedAddresses.callAsync(); + warnIfMismatch(erc721AuthorizedAddresses.length, 2, 'Unexpected number of authorized addresses in ERC721Proxy'); + + const isExchangeAuthorizedInERC721Proxy = await erc721Proxy.authorized.callAsync(exchange.address); + warnIfMismatch(isExchangeAuthorizedInERC721Proxy, true, 'Exchange not authorized in ERC721Proxy'); + + const isMAPAuthorizedInER721Proxy = await erc721Proxy.authorized.callAsync(multiAssetProxy.address); + warnIfMismatch(isMAPAuthorizedInER721Proxy, true, 'MultiAssetProxy not authorized in ERC721Proxy'); + + // Verify ERC1155Proxy configs + const erc1155ProxyOwner = await erc1155Proxy.owner.callAsync(); + warnIfMismatch(erc1155ProxyOwner, assetProxyOwner.address, 'Unexpected ERC1155Proxy owner'); + + const erc1155AuthorizedAddresses = await erc1155Proxy.getAuthorizedAddresses.callAsync(); + warnIfMismatch(erc1155AuthorizedAddresses.length, 2, 'Unexpected number of authorized addresses in ERC1155Proxy'); + + const isExchangeAuthorizedInERC1155Proxy = await erc1155Proxy.authorized.callAsync(exchange.address); + warnIfMismatch(isExchangeAuthorizedInERC1155Proxy, true, 'Exchange not authorized in ERC1155Proxy'); + + const isMAPAuthorizedInER1155Proxy = await erc1155Proxy.authorized.callAsync(multiAssetProxy.address); + warnIfMismatch(isMAPAuthorizedInER1155Proxy, true, 'MultiAssetProxy not authorized in ERC1155Proxy'); + + // Verify MultiAssetProxy configs + const multiAssetProxyOwner = await multiAssetProxy.owner.callAsync(); + warnIfMismatch(multiAssetProxyOwner, assetProxyOwner.address, 'Unexpected MultiAssetProxy owner'); + + const multiAssetProxyAuthorizedAddresses = await multiAssetProxy.getAuthorizedAddresses.callAsync(); + warnIfMismatch( + multiAssetProxyAuthorizedAddresses.length, + 1, + 'Unexpected number of authorized addresses in MultiAssetProxy', + ); + + const isExchangeAuthorizedInMultiAssetProxy = await multiAssetProxy.authorized.callAsync(exchange.address); + warnIfMismatch(isExchangeAuthorizedInMultiAssetProxy, true, 'Exchange not authorized in MultiAssetProxy'); + + const registeredERC20ProxyInMAP = await exchange.getAssetProxy.callAsync(AssetProxyId.ERC20); + warnIfMismatch( + registeredERC20ProxyInMAP, + erc20Proxy.address, + 'Unexpected ERC20Proxy registered in MultiAssetProxy', + ); + + const registeredERC721ProxyInMAP = await exchange.getAssetProxy.callAsync(AssetProxyId.ERC721); + warnIfMismatch( + registeredERC721ProxyInMAP, + erc721Proxy.address, + 'Unexpected ERC721Proxy registered in MultiAssetProxy', + ); + + const registeredERC1155ProxyInMAP = await exchange.getAssetProxy.callAsync(AssetProxyId.ERC1155); + warnIfMismatch( + registeredERC1155ProxyInMAP, + erc1155Proxy.address, + 'Unexpected ERC1155Proxy registered in MultiAssetProxy', + ); + + const registeredStaticCallProxyInMAP = await exchange.getAssetProxy.callAsync(AssetProxyId.StaticCall); + warnIfMismatch( + registeredStaticCallProxyInMAP, + addresses.staticCallProxy, + 'Unexpected StaticCallProxy registered in MultiAssetProxy', + ); + + // Verify AssetProxyOwner configs + const isERC20ProxyRegisteredInAPOwner = await assetProxyOwner.isAssetProxyRegistered.callAsync(erc20Proxy.address); + warnIfMismatch(isERC20ProxyRegisteredInAPOwner, true, 'ERC20Proxy not registered in AssetProxyOwner'); + + const isERC721ProxyRegisteredInAPOwner = await assetProxyOwner.isAssetProxyRegistered.callAsync( + erc721Proxy.address, + ); + warnIfMismatch(isERC721ProxyRegisteredInAPOwner, true, 'ERC721Proxy not registered in AssetProxyOwner'); + + const isERC1155ProxyRegisteredInAPOwner = await assetProxyOwner.isAssetProxyRegistered.callAsync( + erc1155Proxy.address, + ); + warnIfMismatch(isERC1155ProxyRegisteredInAPOwner, true, 'ERC1155Proxy not registered in AssetProxyOwner'); + + const isMultiAssetProxyRegisteredInAPOwner = await assetProxyOwner.isAssetProxyRegistered.callAsync( + multiAssetProxy.address, + ); + warnIfMismatch(isMultiAssetProxyRegisteredInAPOwner, true, 'MultiAssetProxy not registered in AssetProxyOwner'); +} + +(async () => { + for (const rpcUrl of Object.values(networkIdToRpcUrl)) { + const provider = new Web3ProviderEngine(); + provider.addProvider(new EmptyWalletSubprovider()); + provider.addProvider(new RPCSubprovider(rpcUrl)); + providerUtils.startProviderEngine(provider); + await testContractConfigsAsync(provider); + } +})().catch(err => { + logUtils.log(err); + process.exit(1); +}); diff --git a/packages/monorepo-scripts/package.json b/packages/monorepo-scripts/package.json index ee5f647ad6..bc6357426b 100644 --- a/packages/monorepo-scripts/package.json +++ b/packages/monorepo-scripts/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@0x/monorepo-scripts", - "version": "1.0.33", + "version": "1.0.34", "engines": { "node": ">=6.12" }, @@ -48,8 +48,8 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/types": "^2.4.0", - "@0x/utils": "^4.4.0", + "@0x/types": "^2.4.1", + "@0x/utils": "^4.5.0", "@lerna/batch-packages": "^3.0.0-beta.18", "@types/depcheck": "^0.6.0", "async-child-process": "^1.1.1", @@ -63,7 +63,7 @@ "opn": "^5.3.0", "promisify-child-process": "^1.0.5", "prompt": "^1.0.0", - "publish-release": "0xproject/publish-release", + "publish-release": "https://github.com/0xProject/publish-release.git#3f8be1105a356527f4b362ff456d94bf9a82f2ed", "rimraf": "^2.6.2", "semver": "5.5.0", "semver-diff": "^2.1.0", diff --git a/packages/monorepo-scripts/src/doc_gen_configs.ts b/packages/monorepo-scripts/src/doc_gen_configs.ts index c209d1f588..d3e1fd25d6 100644 --- a/packages/monorepo-scripts/src/doc_gen_configs.ts +++ b/packages/monorepo-scripts/src/doc_gen_configs.ts @@ -25,6 +25,9 @@ export const docGenConfigs: DocGenConfigs = { 'https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/ganache-core/index.d.ts#L8', 'lightwallet.keystore': 'https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/eth-lightwallet/index.d.ts#L36', + // HACK: Asset-swapper specifies marketSell and marketBuy quotes with a descriminant MarketOperation Type to ignore the error, linking Buy and Sell to MarketOperation + Buy: 'https://github.com/0xProject/0x-monorepo/blob/development/packages/types/src/index.ts', + Sell: 'https://github.com/0xProject/0x-monorepo/blob/development/packages/types/src/index.ts', }, // If a 0x package re-exports an external package, we should add a link to it's exported items here EXTERNAL_EXPORT_TO_LINK: { @@ -57,14 +60,19 @@ export const docGenConfigs: DocGenConfigs = { 'NonceSubproviderErrors', 'Web3WrapperErrors', 'AssetBuyerError', - 'ContractWrappersError', + 'ContractError', 'TypedDataError', 'SwapQuoterError', 'SwapQuoteGetOutputOpts', 'SwapQuoteExecutionOpts', - 'ForwarderWrapperError', + 'ForwarderError', 'CoordinatorServerError', 'CoordinatorServerCancellationResponse', + 'EventCallback', + 'IndexedFilterValues', + 'OrderInfo', + 'TransactionOpts', + 'EventCallback ', ], // Some libraries only export types. In those cases, we cannot check if the exported types are part of the // "exported public interface". Thus we add them here and skip those checks. diff --git a/packages/monorepo-scripts/src/publish.ts b/packages/monorepo-scripts/src/publish.ts index a2eedc7d3a..d5ca4fa284 100644 --- a/packages/monorepo-scripts/src/publish.ts +++ b/packages/monorepo-scripts/src/publish.ts @@ -2,10 +2,13 @@ import { PackageJSON } from '@0x/types'; import { logUtils } from '@0x/utils'; +import { spawn } from 'child_process'; import * as promisify from 'es6-promisify'; +import * as fs from 'fs'; import * as _ from 'lodash'; import * as moment from 'moment'; import opn = require('opn'); +import * as path from 'path'; import { exec as execAsync, spawn as spawnAsync } from 'promisify-child-process'; import * as prompt from 'prompt'; import semver = require('semver'); @@ -254,19 +257,59 @@ async function updateChangeLogsAsync(updatedPublicPackages: Package[]): Promise< } async function lernaPublishAsync(packageToNextVersion: { [name: string]: string }): Promise { - const packageVersionString = _.map(packageToNextVersion, (nextVersion: string, packageName: string) => { - return `${packageName}@${nextVersion}`; - }).join(','); - let lernaPublishCmd = `node ${constants.lernaExecutable} publish --cdVersions=${packageVersionString} --registry=${ - configs.NPM_REGISTRY_URL - } --yes`; - if (configs.IS_LOCAL_PUBLISH) { - lernaPublishCmd += ` --no-git-tag-version --no-push`; - } - utils.log('Lerna is publishing...'); - await execAsync(lernaPublishCmd, { - cwd: constants.monorepoRootPath, - maxBuffer: 102400000, // 500 * 1024 * 200 + return new Promise((resolve, reject) => { + const packageVersionString = _.map(packageToNextVersion, (nextVersion: string, packageName: string) => { + return `${packageName}|${nextVersion}`; + }).join(','); + // HACK(fabio): Previously we would pass the packageVersionString directly to `lerna publish` using the + // `--cdVersions` flag. Since we now need to use `spawn` instead of `exec` when calling Lerna, passing + // them as a string arg is causing `spawn` to error with `ENAMETOOLONG`. In order to shorten the args + // passed to `spawn` we now write the new version to a file and pass the filepath to the `cdVersions` arg. + const cdVersionsFilepath = path.join(__dirname, 'cd_versions.txt'); + fs.writeFileSync(cdVersionsFilepath, packageVersionString); + const lernaPublishCmd = `node`; + const lernaPublishArgs = [ + `${constants.lernaExecutable}`, + 'publish', + `--cdVersions=${cdVersionsFilepath}`, + `--registry=${configs.NPM_REGISTRY_URL}`, + `--yes`, + ]; + if (configs.IS_LOCAL_PUBLISH) { + lernaPublishArgs.push('--no-git-tag-version'); + lernaPublishArgs.push('--no-push'); + } + utils.log('Lerna is publishing...'); + try { + const child = spawn(lernaPublishCmd, lernaPublishArgs, { + cwd: constants.monorepoRootPath, + }); + child.stdout.on('data', async (data: Buffer) => { + const output = data.toString('utf8'); + utils.log('Lerna publish cmd: ', output); + const isOTPPrompt = _.includes(output, 'Enter OTP:'); + if (isOTPPrompt) { + // Prompt for OTP + prompt.start(); + const result = await promisify(prompt.get)(['OTP']); + child.stdin.write(`${result.OTP}\n`); + } + const didFinishPublishing = _.includes(output, 'Successfully published:'); + if (didFinishPublishing) { + // Remove temporary cdVersions file + fs.unlinkSync(cdVersionsFilepath); + resolve(); + } + }); + child.stderr.on('data', (data: Buffer) => { + const output = data.toString('utf8'); + utils.log('Lerna publish cmd: ', output); + }); + } catch (err) { + // Remove temporary cdVersions file + fs.unlinkSync(cdVersionsFilepath); + reject(err); + } }); } diff --git a/packages/monorepo-scripts/src/test_installation.ts b/packages/monorepo-scripts/src/test_installation.ts index 64d60e0103..4ad135996a 100644 --- a/packages/monorepo-scripts/src/test_installation.ts +++ b/packages/monorepo-scripts/src/test_installation.ts @@ -12,7 +12,7 @@ import { Changelog, Package } from './types'; import { utils } from './utils/utils'; // Packages might not be runnable if they are command-line tools or only run in browsers. -const UNRUNNABLE_PACKAGES = ['@0x/abi-gen', '@0x/react-shared', '@0x/react-docs']; +const UNRUNNABLE_PACKAGES = ['@0x/abi-gen']; const mkdirpAsync = promisify(mkdirp); const rimrafAsync = promisify(rimraf); diff --git a/packages/monorepo-scripts/src/utils/utils.ts b/packages/monorepo-scripts/src/utils/utils.ts index c2969a3ba4..0850060fcd 100644 --- a/packages/monorepo-scripts/src/utils/utils.ts +++ b/packages/monorepo-scripts/src/utils/utils.ts @@ -76,15 +76,21 @@ export const utils = { return updatedPackages; }, async getLernaUpdatedPackagesAsync(shouldIncludePrivate: boolean): Promise { - const result = await execAsync(`${constants.lernaExecutable} updated --json`, { - cwd: constants.monorepoRootPath, - }); - const updatedPackages = JSON.parse(result.stdout); - if (!shouldIncludePrivate) { - const updatedPublicPackages = _.filter(updatedPackages, updatedPackage => !updatedPackage.private); - return updatedPublicPackages; + try { + const result = await execAsync( + `${constants.lernaExecutable} changed --json ${shouldIncludePrivate ? '--all' : ''}`, + { + cwd: constants.monorepoRootPath, + }, + ); + if (result.stdout === '') { + return []; + } + const updatedPackages = JSON.parse(result.stdout); + return updatedPackages; + } catch (err) { + return []; } - return updatedPackages; }, async getNextPackageVersionAsync( currentVersion: string, diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json index 808dd22563..847a7e4af4 100644 --- a/packages/order-utils/CHANGELOG.json +++ b/packages/order-utils/CHANGELOG.json @@ -60,6 +60,25 @@ } ] }, + { + "timestamp": 1565296576, + "version": "8.2.5", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "version": "8.2.4", + "changes": [ + { + "note": "Updated calls to .deploy0xArtifactAsync to include log decode dependencies.", + "pr": 1995 + } + ], + "timestamp": 1564604963 + }, { "version": "8.2.3", "changes": [ @@ -67,7 +86,8 @@ "note": "Ensure `assetData` is word aligned", "pr": 1964 } - ] + ], + "timestamp": 1563957393 }, { "timestamp": 1563193019, diff --git a/packages/order-utils/CHANGELOG.md b/packages/order-utils/CHANGELOG.md index 5845627db2..f8cc6c0262 100644 --- a/packages/order-utils/CHANGELOG.md +++ b/packages/order-utils/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v8.2.5 - _August 8, 2019_ + + * Dependencies updated + +## v8.2.4 - _July 31, 2019_ + + * Updated calls to .deploy0xArtifactAsync to include log decode dependencies. (#1995) + +## v8.2.3 - _July 24, 2019_ + + * Ensure `assetData` is word aligned (#1964) + ## v8.2.2 - _July 15, 2019_ * Dependencies updated diff --git a/packages/order-utils/package.json b/packages/order-utils/package.json index f65e026524..4b8d9270d5 100644 --- a/packages/order-utils/package.json +++ b/packages/order-utils/package.json @@ -1,6 +1,6 @@ { "name": "@0x/order-utils", - "version": "8.2.2", + "version": "8.2.5", "engines": { "node": ">=6.12" }, @@ -36,14 +36,15 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/order-utils/README.md", "devDependencies": { - "@0x/dev-utils": "^2.2.4", + "@0x/dev-utils": "^2.3.0", "@0x/tslint-config": "^3.0.1", "@types/bn.js": "^4.11.0", "@types/lodash": "4.14.104", + "@types/mocha": "^5.2.7", "@types/web3-provider-engine": "^14.0.0", "chai": "^4.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", "sinon": "^4.0.0", @@ -53,19 +54,19 @@ "web3-provider-engine": "14.0.6" }, "dependencies": { - "@0x/abi-gen-wrappers": "^5.0.2", - "@0x/assert": "^2.1.0", - "@0x/base-contract": "^5.1.1", - "@0x/contract-addresses": "^3.0.2", - "@0x/contract-artifacts": "^2.0.1", - "@0x/json-schemas": "^3.0.11", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", + "@0x/abi-gen-wrappers": "^5.2.0", + "@0x/assert": "^2.1.3", + "@0x/base-contract": "^5.3.1", + "@0x/contract-addresses": "^3.0.3", + "@0x/contract-artifacts": "^2.0.4", + "@0x/json-schemas": "^3.1.13", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", "@types/node": "*", "bn.js": "^4.11.8", - "ethereum-types": "^2.1.3", + "ethereum-types": "^2.1.4", "ethereumjs-abi": "0.6.5", "ethereumjs-util": "^5.1.1", "ethers": "~4.0.4", diff --git a/packages/order-utils/test/exchange_transfer_simulator_test.ts b/packages/order-utils/test/exchange_transfer_simulator_test.ts index c26eb19078..2f3e18dec2 100644 --- a/packages/order-utils/test/exchange_transfer_simulator_test.ts +++ b/packages/order-utils/test/exchange_transfer_simulator_test.ts @@ -46,6 +46,7 @@ describe('ExchangeTransferSimulator', async () => { artifacts.ERC20Proxy, provider, txDefaults, + artifacts, ); erc20ProxyAddress = erc20Proxy.address; @@ -58,6 +59,7 @@ describe('ExchangeTransferSimulator', async () => { artifacts.DummyERC20Token, provider, txDefaults, + artifacts, name, symbol, decimals, diff --git a/packages/order-watcher/.npmignore b/packages/order-watcher/.npmignore deleted file mode 100644 index ea588d4859..0000000000 --- a/packages/order-watcher/.npmignore +++ /dev/null @@ -1,9 +0,0 @@ -# Blacklist all files -.* -* -# Whitelist lib -!lib/**/* -# Blacklist tests and publish scripts -/lib/test/* -/lib/monorepo_scripts/ -# Package specific ignore diff --git a/packages/order-watcher/CHANGELOG.json b/packages/order-watcher/CHANGELOG.json deleted file mode 100644 index 50debf42b6..0000000000 --- a/packages/order-watcher/CHANGELOG.json +++ /dev/null @@ -1,571 +0,0 @@ -[ - { - "timestamp": 1563193019, - "version": "4.0.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563047529, - "version": "4.0.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563006338, - "version": "4.0.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1558712885, - "version": "4.0.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557961111, - "version": "4.0.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "4.0.9", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1557799313 - }, - { - "version": "4.0.7", - "changes": [ - { - "note": "Fix race-condition bug due to async callback modifying shared state", - "pr": 1789 - }, - { - "note": "Fix bug where WETH deposit/withdrawal events would not trigger an order state update", - "pr": 1809 - } - ], - "timestamp": 1557507213 - }, - { - "version": "4.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1554997931 - }, - { - "timestamp": 1553183790, - "version": "4.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "4.0.4", - "changes": [ - { - "note": "Update websocket from ^1.0.25 to ^1.0.26", - "pr": 1685 - }, - { - "note": "Fix issue where ERC721 Approval events could cause a lookup on undefined object", - "pr": 1692 - }, - { - "note": "Fix race-condition bugs due to async event callbacks modifying shared state", - "pr": 1718 - }, - { - "note": "Run Web3ProviderEngine without excess block polling", - "pr": 1695 - } - ], - "timestamp": 1553091633 - }, - { - "timestamp": 1551479279, - "version": "4.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551299797, - "version": "4.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551220833, - "version": "4.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "4.0.0", - "changes": [ - { - "note": "Add support for EIP1193 providers & Web3.js providers >= 1.0-beta.38", - "pr": 1627 - }, - { - "note": "Update provider params to type SupportedProvider which outlines all supported providers", - "pr": 1627 - } - ], - "timestamp": 1551130135 - }, - { - "timestamp": 1549733923, - "version": "3.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1549547375 - }, - { - "timestamp": 1549504360, - "version": "3.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1549452781, - "version": "3.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "3.0.0", - "changes": [ - { - "note": "Upgrade the bignumber.js to v8.0.2", - "pr": 1517 - } - ], - "timestamp": 1549373905 - }, - { - "timestamp": 1547747677, - "version": "2.4.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1547561734, - "version": "2.4.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1547225310, - "version": "2.4.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.4.0", - "changes": [ - { - "note": "Add support for `MultiAssetProxy`", - "pr": 1363 - } - ], - "timestamp": 1547040760 - }, - { - "version": "2.3.0", - "changes": [ - { - "note": "Added a WebSocket interface to OrderWatcher so that it can be used by a client written in any language", - "pr": 1427 - } - ] - }, - { - "version": "2.2.8", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1544739608 - }, - { - "version": "2.2.7", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1544570656 - }, - { - "timestamp": 1543401373, - "version": "2.2.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1542821676, - "version": "2.2.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.2.4", - "changes": [ - { - "note": "Fix the bug when order watcher was throwing an error on order removal when maker token was ZRX", - "pr": 1259 - } - ], - "timestamp": 1542208198 - }, - { - "version": "2.2.3", - "changes": [ - { - "note": "Start jsonRpcRequestId at 1, not 0 as 0 breaks the web3.js websocket RPC provider", - "pr": 1227 - }, - { - "note": "Fix the bug when order watcher was trying to convert undefined to an object in case of CancelUpTo event" - } - ], - "timestamp": 1542134075 - }, - { - "timestamp": 1542028948, - "version": "2.2.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.2.1", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1541740904 - }, - { - "version": "2.2.0", - "changes": [ - { - "note": "Added getStats function and returns a Stats object", - "pr": 1118 - }, - { - "note": "Updated to use new modularized artifacts and the latest version of @0xproject/contract-wrappers. Constructor has a new optional `contractAddresses` parameter.", - "pr": 1105 - } - ], - "timestamp": 1539871071 - }, - { - "version": "2.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1538693146 - }, - { - "version": "2.1.0", - "changes": [ - { - "note": "Export ExpirationWatcher", - "pr": 1097 - } - ], - "timestamp": 1538157789 - }, - { - "version": "2.0.0", - "changes": [ - { - "note": "Fixes dropped events issue by fetching logs by blockHash instead of blockNumber. Support for fetching by blockHash was added in Geth > v1.8.13 and Parity > v2.1.0. Infura works too.", - "pr": 1080 - }, - { - "note": "Fix misunderstanding about blockstream interface callbacks and pass the raw JSON RPC responses to it", - "pr": 1080 - }, - { - "note": "Add `transactionHash` to `OrderState` emitted by `OrderWatcher` subscriptions if the order's state change originated from a transaction.", - "pr": 1087 - } - ], - "timestamp": 1537907159 - }, - { - "version": "1.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1537875740 - }, - { - "version": "1.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1537541580 - }, - { - "version": "1.0.3", - "changes": [ - { - "note": "Drastically reduce the bundle size by removing unused parts of included contract artifacts." - } - ], - "timestamp": 1537369748 - }, - { - "version": "1.0.2", - "changes": [ - { - "note": "Add ZRX & WETH mainnet contract addresses into the included artifacts" - } - ], - "timestamp": 1537265493 - }, - { - "timestamp": 1536142250, - "version": "1.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.0.1-rc.5", - "changes": [ - { - "note": "Fix missing `BlockParamLiteral` type import issue" - } - ], - "timestamp": 1535377027 - }, - { - "version": "1.0.1-rc.4", - "changes": [ - { - "note": "Export types: `ExchangeContractErrs`, `OrderRelevantState`, `JSONRPCRequestPayload`, `JSONRPCErrorCallback` and `JSONRPCResponsePayload`", - "pr": 924 - }, - { - "note": "Remove exporting types: `BlockParamLiteral`, `BlockParam`, `Order`", - "pr": 924 - } - ], - "timestamp": 1535133899 - }, - { - "version": "1.0.1-rc.3", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1534210131 - }, - { - "version": "1.0.1-rc.2", - "changes": [ - { - "note": "Fixed bug caused by importing non-existent dep" - } - ], - "timestamp": 1532619515 - }, - { - "version": "1.0.1-rc.1", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1532605697 - }, - { - "timestamp": 1532357734, - "version": "1.0.0", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1532043000, - "version": "1.0.0-rc.1", - "changes": [ - { - "note": "Add support for ERC721 event watching and Exchange V2 events", - "pr": 887 - } - ] - }, - { - "timestamp": 1531919263, - "version": "0.0.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "0.0.7", - "changes": [ - { - "note": "Switch out simple getLogs polling with ethereumjs-blockstream", - "pr": 825 - }, - { - "note": "Do not stop subscription if error is encountered", - "pr": 825 - }, - { - "note": "Fixed a bug that caused the incorrect block to be fetched via JSON-RPC within Blockstream", - "pr": 875 - }, - { - "note": "Remove stateLayer config from OrderWatcher. It now always operates on the latest block", - "pr": 875 - } - ], - "timestamp": 1531149657 - }, - { - "timestamp": 1529397769, - "version": "0.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1527617805, - "version": "0.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1527617227, - "version": "0.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1527616612, - "version": "0.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1527008794, - "version": "0.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1527008794, - "version": "0.0.1", - "changes": [ - { - "note": "Moved OrderWatcher out of 0x.js package", - "pr": 579 - } - ] - } -] diff --git a/packages/order-watcher/CHANGELOG.md b/packages/order-watcher/CHANGELOG.md deleted file mode 100644 index d2178bc3e9..0000000000 --- a/packages/order-watcher/CHANGELOG.md +++ /dev/null @@ -1,243 +0,0 @@ - - -CHANGELOG - -## v4.0.14 - _July 15, 2019_ - - * Dependencies updated - -## v4.0.13 - _July 13, 2019_ - - * Dependencies updated - -## v4.0.12 - _July 13, 2019_ - - * Dependencies updated - -## v4.0.11 - _May 24, 2019_ - - * Dependencies updated - -## v4.0.10 - _May 15, 2019_ - - * Dependencies updated - -## v4.0.9 - _May 14, 2019_ - - * Dependencies updated - -## v4.0.7 - _May 10, 2019_ - - * Fix race-condition bug due to async callback modifying shared state (#1789) - * Fix bug where WETH deposit/withdrawal events would not trigger an order state update (#1809) - -## v4.0.6 - _April 11, 2019_ - - * Dependencies updated - -## v4.0.5 - _March 21, 2019_ - - * Dependencies updated - -## v4.0.4 - _March 20, 2019_ - - * Update websocket from ^1.0.25 to ^1.0.26 (#1685) - * Fix issue where ERC721 Approval events could cause a lookup on undefined object (#1692) - * Fix race-condition bugs due to async event callbacks modifying shared state (#1718) - * Run Web3ProviderEngine without excess block polling (#1695) - -## v4.0.3 - _March 1, 2019_ - - * Dependencies updated - -## v4.0.2 - _February 27, 2019_ - - * Dependencies updated - -## v4.0.1 - _February 26, 2019_ - - * Dependencies updated - -## v4.0.0 - _February 25, 2019_ - - * Add support for EIP1193 providers & Web3.js providers >= 1.0-beta.38 (#1627) - * Update provider params to type SupportedProvider which outlines all supported providers (#1627) - -## v3.0.4 - _February 9, 2019_ - - * Dependencies updated - -## v3.0.3 - _February 7, 2019_ - - * Dependencies updated - -## v3.0.2 - _February 7, 2019_ - - * Dependencies updated - -## v3.0.1 - _February 6, 2019_ - - * Dependencies updated - -## v3.0.0 - _February 5, 2019_ - - * Upgrade the bignumber.js to v8.0.2 (#1517) - -## v2.4.3 - _January 17, 2019_ - - * Dependencies updated - -## v2.4.2 - _January 15, 2019_ - - * Dependencies updated - -## v2.4.1 - _January 11, 2019_ - - * Dependencies updated - -## v2.4.0 - _January 9, 2019_ - - * Add support for `MultiAssetProxy` (#1363) - -## v2.3.0 - _Invalid date_ - - * Added a WebSocket interface to OrderWatcher so that it can be used by a client written in any language (#1427) - -## v2.2.8 - _December 13, 2018_ - - * Dependencies updated - -## v2.2.7 - _December 11, 2018_ - - * Dependencies updated - -## v2.2.6 - _November 28, 2018_ - - * Dependencies updated - -## v2.2.5 - _November 21, 2018_ - - * Dependencies updated - -## v2.2.4 - _November 14, 2018_ - - * Fix the bug when order watcher was throwing an error on order removal when maker token was ZRX (#1259) - -## v2.2.3 - _November 13, 2018_ - - * Start jsonRpcRequestId at 1, not 0 as 0 breaks the web3.js websocket RPC provider (#1227) - * Fix the bug when order watcher was trying to convert undefined to an object in case of CancelUpTo event - -## v2.2.2 - _November 12, 2018_ - - * Dependencies updated - -## v2.2.1 - _November 9, 2018_ - - * Dependencies updated - -## v2.2.0 - _October 18, 2018_ - - * Added getStats function and returns a Stats object (#1118) - * Updated to use new modularized artifacts and the latest version of @0xproject/contract-wrappers. Constructor has a new optional `contractAddresses` parameter. (#1105) - -## v2.1.1 - _October 4, 2018_ - - * Dependencies updated - -## v2.1.0 - _September 28, 2018_ - - * Export ExpirationWatcher (#1097) - -## v2.0.0 - _September 25, 2018_ - - * Fixes dropped events issue by fetching logs by blockHash instead of blockNumber. Support for fetching by blockHash was added in Geth > v1.8.13 and Parity > v2.1.0. Infura works too. (#1080) - * Fix misunderstanding about blockstream interface callbacks and pass the raw JSON RPC responses to it (#1080) - * Add `transactionHash` to `OrderState` emitted by `OrderWatcher` subscriptions if the order's state change originated from a transaction. (#1087) - -## v1.0.5 - _September 25, 2018_ - - * Dependencies updated - -## v1.0.4 - _September 21, 2018_ - - * Dependencies updated - -## v1.0.3 - _September 19, 2018_ - - * Drastically reduce the bundle size by removing unused parts of included contract artifacts. - -## v1.0.2 - _September 18, 2018_ - - * Add ZRX & WETH mainnet contract addresses into the included artifacts - -## v1.0.1 - _September 5, 2018_ - - * Dependencies updated - -## v1.0.1-rc.5 - _August 27, 2018_ - - * Fix missing `BlockParamLiteral` type import issue - -## v1.0.1-rc.4 - _August 24, 2018_ - - * Export types: `ExchangeContractErrs`, `OrderRelevantState`, `JSONRPCRequestPayload`, `JSONRPCErrorCallback` and `JSONRPCResponsePayload` (#924) - * Remove exporting types: `BlockParamLiteral`, `BlockParam`, `Order` (#924) - -## v1.0.1-rc.3 - _August 14, 2018_ - - * Dependencies updated - -## v1.0.1-rc.2 - _July 26, 2018_ - - * Fixed bug caused by importing non-existent dep - -## v1.0.1-rc.1 - _July 26, 2018_ - - * Dependencies updated - -## v1.0.0 - _July 23, 2018_ - - * Dependencies updated - -## v1.0.0-rc.1 - _July 19, 2018_ - - * Add support for ERC721 event watching and Exchange V2 events (#887) - -## v0.0.8 - _July 18, 2018_ - - * Dependencies updated - -## v0.0.7 - _July 9, 2018_ - - * Switch out simple getLogs polling with ethereumjs-blockstream (#825) - * Do not stop subscription if error is encountered (#825) - * Fixed a bug that caused the incorrect block to be fetched via JSON-RPC within Blockstream (#875) - * Remove stateLayer config from OrderWatcher. It now always operates on the latest block (#875) - -## v0.0.6 - _June 19, 2018_ - - * Dependencies updated - -## v0.0.5 - _May 29, 2018_ - - * Dependencies updated - -## v0.0.4 - _May 29, 2018_ - - * Dependencies updated - -## v0.0.3 - _May 29, 2018_ - - * Dependencies updated - -## v0.0.2 - _May 22, 2018_ - - * Dependencies updated - -## v0.0.1 - _May 22, 2018_ - - * Moved OrderWatcher out of 0x.js package (#579) diff --git a/packages/order-watcher/Dockerfile b/packages/order-watcher/Dockerfile deleted file mode 100644 index 3ffa1b72fa..0000000000 --- a/packages/order-watcher/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM node - -WORKDIR /order-watcher - -COPY package.json . -RUN npm i -RUN npm install forever -g - -COPY . . - -EXPOSE 8080 - -CMD ["forever", "./lib/src/server.js"] diff --git a/packages/order-watcher/README.md b/packages/order-watcher/README.md deleted file mode 100644 index b2de5450d6..0000000000 --- a/packages/order-watcher/README.md +++ /dev/null @@ -1,169 +0,0 @@ -## OrderWatcher [Deprecated] - -:no_entry: WARNING: This project is deprecated. Please use [0x Mesh](https://github.com/0xProject/0x-mesh) for all your orderbook pruning needs. It can be used with or without order sharing enabled. If you have any questions about how to use Mesh, reach out to us in the [#mesh channel on Discord](https://discordapp.com/invite/d3FTX3M) :no_entry: - -An order watcher daemon that watches for order validity. - -#### Read the wiki [article](https://0xproject.com/wiki#0x-OrderWatcher). - -OrderWatcher also comes with a WebSocket server to provide language-agnostic access -to order watching functionality. We used the [WebSocket Client and Server Implementation for Node](https://www.npmjs.com/package/websocket). The server sends and receives messages that conform to the [JSON RPC specifications](https://www.jsonrpc.org/specification). - -## Installation - -**Install** - -```bash -npm install @0x/order-watcher --save -``` - -**Import** - -```javascript -import { OrderWatcher } from '@0x/order-watcher'; -``` - -If your project is in [TypeScript](https://www.typescriptlang.org/), add the following to your `tsconfig.json`: - -```json -"compilerOptions": { - "typeRoots": ["node_modules/@0x/typescript-typings/types", "node_modules/@types"], -} -``` - -## Using the WebSocket Server - -**Setup** - -**Environmental Variables** -Several environmental variables can be set to configure the server: - -- `ORDER_WATCHER_HTTP_PORT` specifies the port that the http server will listen on - and accept connections from. When this is not set, we default to 8080. - -**Requests** -The server accepts three types of requests: `ADD_ORDER`, `REMOVE_ORDER` and `GET_STATS`. These mirror what the underlying OrderWatcher does. You can read more in the [wiki](https://0xproject.com/wiki#0x-OrderWatcher). Unlike the OrderWatcher, it does not expose any `subscribe` or `unsubscribe` functionality because the WebSocket server keeps a single subscription open for all clients. - -The first step for making a request is establishing a connection with the server. In Javascript: - -``` -var W3CWebSocket = require('websocket').w3cwebsocket; -wsClient = new W3CWebSocket('ws://127.0.0.1:8080'); -``` - -In Python, you could use the [websocket-client library](http://pypi.python.org/pypi/websocket-client/) and run: - -``` -from websocket import create_connection -wsClient = create_connection("ws://127.0.0.1:8080") -``` - -With the connection established, you prepare the payload for your request. The payload is a json object with a format established by the [JSON RPC specification](https://www.jsonrpc.org/specification): - -- `id`: All requests require you to specify a numerical `id`. When the server responds to the request, the response will have the same `id` as the one supplied with your request. -- `jsonrpc`: This is always the string `'2.0'`. -- `method`: This specifies the OrderWatcher method you want to call. I.e., `'ADD_ORDER'`, `'REMOVE_ORDER'` or `'GET_STATS'`. -- `params`: These contain the parameters needed by OrderWatcher to execute the method you called. For `ADD_ORDER`, provide `{ signedOrder: }`. For `REMOVE_ORDER`, provide `{ orderHash: }`. For `GET_STATS`, no parameters are needed, so you may leave this empty. - -Next, convert the payload to a string and send it through the connection. -In Javascript: - -``` -const addOrderPayload = { - id: 1, - jsonrpc: '2.0', - method: 'ADD_ORDER', - params: { signedOrder: }, -}; -wsClient.send(JSON.stringify(addOrderPayload)); -``` - -In Python: - -``` -import json -remove_order_payload = { - 'id': 1, - 'jsonrpc': '2.0', - 'method': 'REMOVE_ORDER', - 'params': {'orderHash': '0x6edc16bf37fde79f5012088c33784c730e2f103d9ab1caf73060c386ad107b7e'}, -} -wsClient.send(json.dumps(remove_order_payload)); -``` - -**Response** -The server responds to all requests in a similar format. In the data field, you'll find another object containing the following fields: - -- `id`: The id corresponding to the request that the server is responding to. `UPDATE` responses are not based on any requests so the `id` field is omitted`. -- `jsonrpc`: Always `'2.0'`. -- `method`: The method the server is responding to. Eg. `ADD_ORDER`. When order states change the server may also initiate a response. In this case, method will be listed as `UPDATE`. -- `result`: This field varies based on the method. `UPDATE` responses contain the new order state. `GET_STATS` responses contain the current order count. When there are errors, this field is omitted. -- `error`: When there is an error executing a request, the [JSON RPC](https://www.jsonrpc.org/specification) error object is listed here. When the server responds successfully, this field is omitted. - -In Javascript, the responses can be parsed using the `onmessage` callback: - -``` -wsClient.onmessage = (msg) => { - const responseData = JSON.parse(msg.data); - const method = responseData.method -}; -``` - -In Python, `recv` is a lightweight way to receive a response: - -``` -result = wsClient.recv() -method = result.method -``` - -## Contributing - -We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository. - -Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. - -### Install dependencies - -If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: - -```bash -yarn config set workspaces-experimental true -``` - -Then install dependencies - -```bash -yarn install -``` - -### Build - -To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory: - -```bash -PKG=@0x/order-watcher yarn build -``` - -Or continuously rebuild on change: - -```bash -PKG=@0x/order-watcher yarn watch -``` - -### Clean - -```bash -yarn clean -``` - -### Lint - -```bash -yarn lint -``` - -### Run Tests - -```bash -yarn test -``` diff --git a/packages/order-watcher/package.json b/packages/order-watcher/package.json deleted file mode 100644 index 8e11224176..0000000000 --- a/packages/order-watcher/package.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "name": "@0x/order-watcher", - "version": "4.0.14", - "description": "An order watcher daemon that watches for order validity", - "keywords": [ - "0x", - "0xproject", - "ethereum", - "exchange", - "orderbook" - ], - "main": "lib/src/index.js", - "types": "lib/src/index.d.ts", - "scripts": { - "build": "yarn tsc -b", - "build:ci": "yarn build", - "lint": "tslint --format stylish --project .", - "fix": "tslint --fix --format stylish --project .", - "test:circleci": "run-s test:coverage", - "test": "yarn run_mocha", - "rebuild_and_test": "run-s build test", - "test:coverage": "nyc npm run test --all && yarn coverage:report:lcov", - "coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info", - "clean": "shx rm -rf _bundles lib test_temp generated_docs", - "run_mocha": "mocha --require source-map-support/register --require make-promises-safe lib/test/**/*_test.js lib/test/global_hooks.js --timeout 10000 --bail --exit", - "docs:json": "typedoc --excludePrivate --excludeExternals --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES" - }, - "repository": { - "type": "git", - "url": "https://github.com/0xProject/0x-monorepo" - }, - "license": "Apache-2.0", - "engines": { - "node": ">=6.0.0" - }, - "devDependencies": { - "@0x/dev-utils": "^2.2.4", - "@0x/migrations": "^4.1.9", - "@0x/subproviders": "^4.1.1", - "@0x/tslint-config": "^3.0.1", - "@types/bintrees": "^1.0.2", - "@types/lodash": "4.14.104", - "@types/mocha": "^2.2.42", - "@types/node": "*", - "@types/sinon": "^2.2.2", - "chai": "^4.0.1", - "chai-as-promised": "^7.1.0", - "chai-bignumber": "^3.0.0", - "dirty-chai": "^2.0.1", - "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", - "npm-run-all": "^4.1.2", - "nyc": "^11.0.1", - "opn-cli": "^3.1.0", - "shx": "^0.2.2", - "sinon": "^4.0.0", - "source-map-support": "^0.5.0", - "tslint": "5.11.0", - "typescript": "3.0.1" - }, - "dependencies": { - "@0x/abi-gen-wrappers": "^5.0.2", - "@0x/assert": "^2.1.0", - "@0x/base-contract": "^5.1.1", - "@0x/contract-addresses": "^3.0.2", - "@0x/contract-artifacts": "^2.0.1", - "@0x/contract-wrappers": "^9.1.7", - "@0x/fill-scenarios": "^3.0.13", - "@0x/json-schemas": "^3.0.11", - "@0x/order-utils": "^8.2.2", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", - "bintrees": "^1.0.2", - "ethereum-types": "^2.1.3", - "ethereumjs-blockstream": "6.0.0", - "ethers": "~4.0.4", - "lodash": "^4.17.11", - "semaphore-async-await": "^1.5.1", - "websocket": "^1.0.26" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/packages/order-watcher/src/index.ts b/packages/order-watcher/src/index.ts deleted file mode 100644 index e9449c5cf0..0000000000 --- a/packages/order-watcher/src/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -export { OrderWatcher } from './order_watcher/order_watcher'; -export { OrderWatcherWebSocketServer } from './order_watcher/order_watcher_web_socket_server'; -export { ExpirationWatcher } from './order_watcher/expiration_watcher'; - -export { - OrderStateValid, - OrderStateInvalid, - OrderState, - ExchangeContractErrs, - ObjectMap, - OrderRelevantState, - Stats, -} from '@0x/types'; - -export { OnOrderStateChangeCallback, OrderWatcherConfig } from './types'; - -export { ContractAddresses } from '@0x/contract-addresses'; -export { SignedOrder } from '@0x/types'; -export { - JSONRPCRequestPayload, - JSONRPCErrorCallback, - SupportedProvider, - JSONRPCResponsePayload, - JSONRPCResponseError, - Web3JsProvider, - GanacheProvider, - EIP1193Provider, - ZeroExProvider, - EIP1193Event, - Web3JsV1Provider, - Web3JsV2Provider, - Web3JsV3Provider, -} from 'ethereum-types'; diff --git a/packages/order-watcher/src/order_watcher/collision_resistant_abi_decoder.ts b/packages/order-watcher/src/order_watcher/collision_resistant_abi_decoder.ts deleted file mode 100644 index 52f28cd4a3..0000000000 --- a/packages/order-watcher/src/order_watcher/collision_resistant_abi_decoder.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { AbiDecoder } from '@0x/utils'; -import { ContractAbi, DecodedLogArgs, LogEntry, LogWithDecodedArgs, RawLog } from 'ethereum-types'; - -const TOKEN_TYPE_COLLISION = `Token can't be marked as ERC20 and ERC721 at the same time`; - -/** - * ERC20 and ERC721 have some events with different args but colliding signature. - * For exmaple: - * Transfer(_from address, _to address, _value uint256) - * Transfer(_from address, _to address, _tokenId uint256) - * Both have the signature: - * Transfer(address,address,uint256) - * - * In order to correctly decode those events we need to know the token type by address in advance. - * You can pass it by calling `this.addERC20Token(address)` or `this.addERC721Token(address)` - */ -export class CollisionResistanceAbiDecoder { - private readonly _erc20AbiDecoder: AbiDecoder; - private readonly _erc721AbiDecoder: AbiDecoder; - private readonly _restAbiDecoder: AbiDecoder; - private readonly _knownERC20Tokens = new Set(); - private readonly _knownERC721Tokens = new Set(); - constructor(erc20Abi: ContractAbi, erc721Abi: ContractAbi, abis: ContractAbi[]) { - this._erc20AbiDecoder = new AbiDecoder([erc20Abi]); - this._erc721AbiDecoder = new AbiDecoder([erc721Abi]); - this._restAbiDecoder = new AbiDecoder(abis); - } - public tryToDecodeLogOrNoop(log: LogEntry): LogWithDecodedArgs | RawLog { - let maybeDecodedLog = log; - if (this._knownERC20Tokens.has(log.address)) { - maybeDecodedLog = this._erc20AbiDecoder.tryToDecodeLogOrNoop(log); - } else if (this._knownERC721Tokens.has(log.address)) { - maybeDecodedLog = this._erc721AbiDecoder.tryToDecodeLogOrNoop(log); - } - // Fall back to the supplied ABIs for decoding if the ERC20/ERC721 decoding fails - // This ensures we hit events like Deposit and Withdraw given WETH can be a known ERC20Token - const isLogDecoded = ((maybeDecodedLog as any) as LogWithDecodedArgs).event !== undefined; - if (!isLogDecoded) { - maybeDecodedLog = this._restAbiDecoder.tryToDecodeLogOrNoop(log); - } - return maybeDecodedLog; - } - // Hints the ABI decoder that a particular token address is ERC20 and events from it should be decoded as ERC20 events - public addERC20Token(address: string): void { - if (this._knownERC721Tokens.has(address)) { - throw new Error(TOKEN_TYPE_COLLISION); - } - this._knownERC20Tokens.add(address); - } - // Hints the ABI decoder that a particular token address is ERC721 and events from it should be decoded as ERC721 events - public addERC721Token(address: string): void { - if (this._knownERC20Tokens.has(address)) { - throw new Error(TOKEN_TYPE_COLLISION); - } - this._knownERC721Tokens.add(address); - } -} diff --git a/packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts b/packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts deleted file mode 100644 index 2f6476dcb3..0000000000 --- a/packages/order-watcher/src/order_watcher/dependent_order_hashes_tracker.ts +++ /dev/null @@ -1,245 +0,0 @@ -import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; -import { AssetProxyId, SignedOrder } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as _ from 'lodash'; - -export interface OrderHashesByMakerAddress { - [makerAddress: string]: Set; -} - -export interface OrderHashesByERC20ByMakerAddress { - [makerAddress: string]: { - [erc20TokenAddress: string]: Set; - }; -} - -export interface OrderHashesByERC721AddressByTokenIdByMakerAddress { - [makerAddress: string]: { - [erc721TokenAddress: string]: { - // Ideally erc721TokenId should be a BigNumber, but it's not a valid index type so we just convert it to a string before using it as an index - [erc721TokenId: string]: Set; - }; - }; -} - -/** - */ -export class DependentOrderHashesTracker { - private readonly _zrxTokenAddress: string; - // `_orderHashesByMakerAddress` is redundant and could be generated from - // `_orderHashesByERC20ByMakerAddress` and `_orderHashesByERC721AddressByTokenIdByMakerAddress` - // on the fly by merging all the entries together but it's more complex and computationally heavy. - // We might change that in future if we're move memory-constrained. - private readonly _orderHashesByMakerAddress: OrderHashesByMakerAddress = {}; - private readonly _orderHashesByERC20ByMakerAddress: OrderHashesByERC20ByMakerAddress = {}; - private readonly _orderHashesByERC721AddressByTokenIdByMakerAddress: OrderHashesByERC721AddressByTokenIdByMakerAddress = {}; - constructor(zrxTokenAddress: string) { - this._zrxTokenAddress = zrxTokenAddress; - } - public getDependentOrderHashesByERC721ByMaker(makerAddress: string, tokenAddress: string): string[] { - if ( - this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress] === undefined || - this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress][tokenAddress] === undefined - ) { - return []; - } - const orderHashSets = _.values( - this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress][tokenAddress], - ); - const orderHashList = _.reduce( - orderHashSets, - (accumulator, orderHashSet) => [...accumulator, ...orderHashSet], - [] as string[], - ); - const uniqueOrderHashList = _.uniq(orderHashList); - return uniqueOrderHashList; - } - public getDependentOrderHashesByMaker(makerAddress: string): string[] { - const dependentOrderHashes = Array.from(this._orderHashesByMakerAddress[makerAddress] || {}); - return dependentOrderHashes; - } - public getDependentOrderHashesByAssetDataByMaker(makerAddress: string, assetData: string): string[] { - const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData); - const dependentOrderHashes = - decodedAssetData.assetProxyId === AssetProxyId.ERC20 - ? this._getDependentOrderHashesByERC20AssetData(makerAddress, assetData) - : this._getDependentOrderHashesByERC721AssetData(makerAddress, assetData); - return dependentOrderHashes; - } - public addToDependentOrderHashes(signedOrder: SignedOrder): void { - this._addAssetDataToDependentOrderHashes(signedOrder, signedOrder.makerAssetData); - this._addToERC20DependentOrderHashes(signedOrder, this._zrxTokenAddress); - this._addToMakerDependentOrderHashes(signedOrder); - } - public removeFromDependentOrderHashes(signedOrder: SignedOrder): void { - this._removeAssetDataFromDependentOrderHashes(signedOrder, signedOrder.makerAssetData); - // If makerToken === ZRX then we already removed it and we don't need to remove it again. - const decodedMakerAssetData = assetDataUtils.decodeAssetDataOrThrow(signedOrder.makerAssetData); - if ( - assetDataUtils.isERC20AssetData(decodedMakerAssetData) && - decodedMakerAssetData.tokenAddress !== this._zrxTokenAddress - ) { - this._removeFromERC20DependentOrderhashes(signedOrder, this._zrxTokenAddress); - } - this._removeFromMakerDependentOrderhashes(signedOrder); - } - private _getDependentOrderHashesByERC20AssetData(makerAddress: string, erc20AssetData: string): string[] { - const tokenAddress = assetDataUtils.decodeERC20AssetData(erc20AssetData).tokenAddress; - let dependentOrderHashes: string[] = []; - if ( - this._orderHashesByERC20ByMakerAddress[makerAddress] !== undefined && - this._orderHashesByERC20ByMakerAddress[makerAddress][tokenAddress] !== undefined - ) { - dependentOrderHashes = Array.from(this._orderHashesByERC20ByMakerAddress[makerAddress][tokenAddress]); - } - return dependentOrderHashes; - } - private _getDependentOrderHashesByERC721AssetData(makerAddress: string, erc721AssetData: string): string[] { - const tokenAddress = assetDataUtils.decodeERC721AssetData(erc721AssetData).tokenAddress; - const tokenId = assetDataUtils.decodeERC721AssetData(erc721AssetData).tokenId; - let dependentOrderHashes: string[] = []; - if ( - this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress] !== undefined && - this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress][tokenAddress] !== undefined && - this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress][tokenAddress][tokenId.toString()] !== - undefined - ) { - dependentOrderHashes = Array.from( - this._orderHashesByERC721AddressByTokenIdByMakerAddress[makerAddress][tokenAddress][tokenId.toString()], - ); - } - return dependentOrderHashes; - } - private _addToERC20DependentOrderHashes(signedOrder: SignedOrder, erc20TokenAddress: string): void { - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - if (this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress] === undefined) { - this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress] = {}; - } - if (this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress][erc20TokenAddress] === undefined) { - this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress][erc20TokenAddress] = new Set(); - } - this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress][erc20TokenAddress].add(orderHash); - } - private _addToERC721DependentOrderHashes( - signedOrder: SignedOrder, - erc721TokenAddress: string, - tokenId: BigNumber, - ): void { - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - if (this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress] === undefined) { - this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress] = {}; - } - - if ( - this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress] === - undefined - ) { - this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress] = {}; - } - - if ( - this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress][ - tokenId.toString() - ] === undefined - ) { - this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress][ - tokenId.toString() - ] = new Set(); - } - - this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress][ - tokenId.toString() - ].add(orderHash); - } - private _addAssetDataToDependentOrderHashes(signedOrder: SignedOrder, assetData: string): void { - const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData); - if (assetDataUtils.isERC20AssetData(decodedAssetData)) { - this._addToERC20DependentOrderHashes(signedOrder, decodedAssetData.tokenAddress); - } else if (assetDataUtils.isERC721AssetData(decodedAssetData)) { - this._addToERC721DependentOrderHashes(signedOrder, decodedAssetData.tokenAddress, decodedAssetData.tokenId); - } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) { - _.each(decodedAssetData.nestedAssetData, nestedAssetDataElement => - this._addAssetDataToDependentOrderHashes(signedOrder, nestedAssetDataElement), - ); - } - } - private _addToMakerDependentOrderHashes(signedOrder: SignedOrder): void { - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - if (this._orderHashesByMakerAddress[signedOrder.makerAddress] === undefined) { - this._orderHashesByMakerAddress[signedOrder.makerAddress] = new Set(); - } - this._orderHashesByMakerAddress[signedOrder.makerAddress].add(orderHash); - } - private _removeFromERC20DependentOrderhashes(signedOrder: SignedOrder, erc20TokenAddress: string): void { - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress][erc20TokenAddress].delete(orderHash); - - if (_.isEmpty(this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress][erc20TokenAddress])) { - delete this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress][erc20TokenAddress]; - } - - if (_.isEmpty(this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress])) { - delete this._orderHashesByERC20ByMakerAddress[signedOrder.makerAddress]; - } - } - private _removeFromERC721DependentOrderhashes( - signedOrder: SignedOrder, - erc721TokenAddress: string, - tokenId: BigNumber, - ): void { - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress][ - tokenId.toString() - ].delete(orderHash); - - if ( - _.isEmpty( - this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress][ - tokenId.toString() - ], - ) - ) { - delete this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][ - erc721TokenAddress - ][tokenId.toString()]; - } - - if ( - _.isEmpty( - this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][erc721TokenAddress], - ) - ) { - delete this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress][ - erc721TokenAddress - ]; - } - - if (_.isEmpty(this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress])) { - delete this._orderHashesByERC721AddressByTokenIdByMakerAddress[signedOrder.makerAddress]; - } - } - private _removeFromMakerDependentOrderhashes(signedOrder: SignedOrder): void { - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - this._orderHashesByMakerAddress[signedOrder.makerAddress].delete(orderHash); - - if (_.isEmpty(this._orderHashesByMakerAddress[signedOrder.makerAddress])) { - delete this._orderHashesByMakerAddress[signedOrder.makerAddress]; - } - } - private _removeAssetDataFromDependentOrderHashes(signedOrder: SignedOrder, assetData: string): void { - const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData); - if (assetDataUtils.isERC20AssetData(decodedAssetData)) { - this._removeFromERC20DependentOrderhashes(signedOrder, decodedAssetData.tokenAddress); - } else if (assetDataUtils.isERC721AssetData(decodedAssetData)) { - this._removeFromERC721DependentOrderhashes( - signedOrder, - decodedAssetData.tokenAddress, - decodedAssetData.tokenId, - ); - } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) { - _.each(decodedAssetData.nestedAssetData, nestedAssetDataElement => - this._removeAssetDataFromDependentOrderHashes(signedOrder, nestedAssetDataElement), - ); - } - } -} diff --git a/packages/order-watcher/src/order_watcher/event_watcher.ts b/packages/order-watcher/src/order_watcher/event_watcher.ts deleted file mode 100644 index 91f18fd187..0000000000 --- a/packages/order-watcher/src/order_watcher/event_watcher.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { intervalUtils, logUtils } from '@0x/utils'; -import { marshaller, Web3Wrapper } from '@0x/web3-wrapper'; -import { BlockParamLiteral, FilterObject, LogEntry, RawLogEntry, SupportedProvider } from 'ethereum-types'; -import { Block, BlockAndLogStreamer, Log } from 'ethereumjs-blockstream'; -import * as _ from 'lodash'; - -import { EventWatcherCallback, OrderWatcherError } from '../types'; -import { assert } from '../utils/assert'; - -const DEFAULT_EVENT_POLLING_INTERVAL_MS = 200; - -enum LogEventState { - Removed, - Added, -} - -/** - * The EventWatcher watches for blockchain events at the specified block confirmation - * depth. - */ -export class EventWatcher { - private readonly _web3Wrapper: Web3Wrapper; - private readonly _isVerbose: boolean; - private _blockAndLogStreamerIfExists: BlockAndLogStreamer | undefined; - private _blockAndLogStreamIntervalIfExists?: NodeJS.Timer; - private _onLogAddedSubscriptionToken: string | undefined; - private _onLogRemovedSubscriptionToken: string | undefined; - private readonly _pollingIntervalMs: number; - constructor( - supportedProvider: SupportedProvider, - pollingIntervalIfExistsMs: undefined | number, - isVerbose: boolean, - ) { - this._isVerbose = isVerbose; - this._web3Wrapper = new Web3Wrapper(supportedProvider); - this._pollingIntervalMs = - pollingIntervalIfExistsMs === undefined ? DEFAULT_EVENT_POLLING_INTERVAL_MS : pollingIntervalIfExistsMs; - this._blockAndLogStreamerIfExists = undefined; - this._blockAndLogStreamIntervalIfExists = undefined; - this._onLogAddedSubscriptionToken = undefined; - this._onLogRemovedSubscriptionToken = undefined; - } - public subscribe(callback: EventWatcherCallback): void { - assert.isFunction('callback', callback); - if (this._blockAndLogStreamIntervalIfExists !== undefined) { - throw new Error(OrderWatcherError.SubscriptionAlreadyPresent); - } - this._startBlockAndLogStream(callback); - } - public unsubscribe(): void { - if (this._blockAndLogStreamIntervalIfExists === undefined) { - throw new Error(OrderWatcherError.SubscriptionNotFound); - } - this._stopBlockAndLogStream(); - } - private _startBlockAndLogStream(callback: EventWatcherCallback): void { - if (this._blockAndLogStreamerIfExists !== undefined) { - throw new Error(OrderWatcherError.SubscriptionAlreadyPresent); - } - this._blockAndLogStreamerIfExists = new BlockAndLogStreamer( - this._blockstreamGetBlockOrNullAsync.bind(this), - this._blockstreamGetLogsAsync.bind(this), - this._onBlockAndLogStreamerError.bind(this), - ); - const catchAllLogFilter = {}; - this._blockAndLogStreamerIfExists.addLogFilter(catchAllLogFilter); - this._blockAndLogStreamIntervalIfExists = intervalUtils.setAsyncExcludingInterval( - this._reconcileBlockAsync.bind(this), - this._pollingIntervalMs, - this._onBlockAndLogStreamerError.bind(this), - ); - let isRemoved = false; - this._onLogAddedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogAdded( - this._onLogStateChangedAsync.bind(this, callback, isRemoved), - ); - isRemoved = true; - this._onLogRemovedSubscriptionToken = this._blockAndLogStreamerIfExists.subscribeToOnLogRemoved( - this._onLogStateChangedAsync.bind(this, callback, isRemoved), - ); - } - // This method only exists in order to comply with the expected interface of Blockstream's constructor - private async _blockstreamGetBlockOrNullAsync(hash: string): Promise { - const shouldIncludeTransactionData = false; - const blockOrNull = await this._web3Wrapper.sendRawPayloadAsync({ - method: 'eth_getBlockByHash', - params: [hash, shouldIncludeTransactionData], - }); - return blockOrNull; - } - // This method only exists in order to comply with the expected interface of Blockstream's constructor - private async _blockstreamGetLatestBlockOrNullAsync(): Promise { - const shouldIncludeTransactionData = false; - const blockOrNull = await this._web3Wrapper.sendRawPayloadAsync({ - method: 'eth_getBlockByNumber', - params: [BlockParamLiteral.Latest, shouldIncludeTransactionData], - }); - return blockOrNull; - } - // This method only exists in order to comply with the expected interface of Blockstream's constructor - private async _blockstreamGetLogsAsync(filterOptions: FilterObject): Promise { - const logs = await this._web3Wrapper.sendRawPayloadAsync({ - method: 'eth_getLogs', - params: [filterOptions], - }); - return logs as RawLogEntry[]; - } - private _stopBlockAndLogStream(): void { - if (this._blockAndLogStreamerIfExists === undefined) { - throw new Error(OrderWatcherError.SubscriptionNotFound); - } - this._blockAndLogStreamerIfExists.unsubscribeFromOnLogAdded(this._onLogAddedSubscriptionToken as string); - this._blockAndLogStreamerIfExists.unsubscribeFromOnLogRemoved(this._onLogRemovedSubscriptionToken as string); - intervalUtils.clearAsyncExcludingInterval(this._blockAndLogStreamIntervalIfExists as NodeJS.Timer); - delete this._blockAndLogStreamerIfExists; - delete this._blockAndLogStreamIntervalIfExists; - } - private async _onLogStateChangedAsync( - callback: EventWatcherCallback, - isRemoved: boolean, - rawLog: RawLogEntry, - ): Promise { - const log: LogEntry = marshaller.unmarshalLog(rawLog); - await this._emitDifferencesAsync(log, isRemoved ? LogEventState.Removed : LogEventState.Added, callback); - } - private async _reconcileBlockAsync(): Promise { - const latestBlockOrNull = await this._blockstreamGetLatestBlockOrNullAsync(); - if (latestBlockOrNull === null) { - return; // noop - } - // We need to coerce to Block type cause Web3.Block includes types for mempool blocks - if (this._blockAndLogStreamerIfExists !== undefined) { - // If we clear the interval while fetching the block - this._blockAndLogStreamer will be undefined - await this._blockAndLogStreamerIfExists.reconcileNewBlock(latestBlockOrNull); - } - } - private async _emitDifferencesAsync( - log: LogEntry, - logEventState: LogEventState, - callback: EventWatcherCallback, - ): Promise { - const logEvent = { - removed: logEventState === LogEventState.Removed, - ...log, - }; - if (this._blockAndLogStreamIntervalIfExists !== undefined) { - callback(null, logEvent); - } - } - private _onBlockAndLogStreamerError(err: Error): void { - // Since Blockstream errors are all recoverable, we simply log them if the verbose - // config is passed in. - if (this._isVerbose) { - logUtils.warn(err); - } - } -} diff --git a/packages/order-watcher/src/order_watcher/expiration_watcher.ts b/packages/order-watcher/src/order_watcher/expiration_watcher.ts deleted file mode 100644 index fd66d628ff..0000000000 --- a/packages/order-watcher/src/order_watcher/expiration_watcher.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { BigNumber, intervalUtils } from '@0x/utils'; -import { RBTree } from 'bintrees'; -import * as _ from 'lodash'; - -import { OrderWatcherError } from '../types'; -import { utils } from '../utils/utils'; - -const DEFAULT_EXPIRATION_MARGIN_MS = 0; -const DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS = 50; - -/** - * This class includes the functionality to detect expired orders. - * It stores them in a min heap by expiration time and checks for expired ones every `orderExpirationCheckingIntervalMs` - */ -export class ExpirationWatcher { - private readonly _orderHashByExpirationRBTree: RBTree; - private readonly _expiration: { [orderHash: string]: BigNumber } = {}; - private readonly _orderExpirationCheckingIntervalMs: number; - private readonly _expirationMarginMs: number; - private _orderExpirationCheckingIntervalIdIfExists?: NodeJS.Timer; - constructor(expirationMarginIfExistsMs?: number, orderExpirationCheckingIntervalIfExistsMs?: number) { - this._orderExpirationCheckingIntervalMs = - orderExpirationCheckingIntervalIfExistsMs || DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS; - this._expirationMarginMs = expirationMarginIfExistsMs || DEFAULT_EXPIRATION_MARGIN_MS; - this._orderExpirationCheckingIntervalMs = - expirationMarginIfExistsMs || DEFAULT_ORDER_EXPIRATION_CHECKING_INTERVAL_MS; - const comparator = (lhsOrderHash: string, rhsOrderHash: string) => { - const lhsExpiration = this._expiration[lhsOrderHash].toNumber(); - const rhsExpiration = this._expiration[rhsOrderHash].toNumber(); - if (lhsExpiration !== rhsExpiration) { - return lhsExpiration - rhsExpiration; - } else { - // HACK: If two orders have identical expirations, the order in which they are emitted by the - // ExpirationWatcher does not matter, so we emit them in alphabetical order by orderHash. - return lhsOrderHash.localeCompare(rhsOrderHash); - } - }; - this._orderHashByExpirationRBTree = new RBTree(comparator); - } - public subscribe(callback: (orderHash: string) => void): void { - if (this._orderExpirationCheckingIntervalIdIfExists !== undefined) { - throw new Error(OrderWatcherError.SubscriptionAlreadyPresent); - } - this._orderExpirationCheckingIntervalIdIfExists = intervalUtils.setInterval( - this._pruneExpiredOrders.bind(this, callback), - this._orderExpirationCheckingIntervalMs, - _.noop.bind(_), // _pruneExpiredOrders never throws - ); - } - public unsubscribe(): void { - if (this._orderExpirationCheckingIntervalIdIfExists === undefined) { - throw new Error(OrderWatcherError.SubscriptionNotFound); - } - intervalUtils.clearInterval(this._orderExpirationCheckingIntervalIdIfExists); - delete this._orderExpirationCheckingIntervalIdIfExists; - } - public addOrder(orderHash: string, expirationUnixTimestampMs: BigNumber): void { - this._expiration[orderHash] = expirationUnixTimestampMs; - this._orderHashByExpirationRBTree.insert(orderHash); - } - public removeOrder(orderHash: string): void { - if (this._expiration[orderHash] === undefined) { - return; // noop since order already removed - } - this._orderHashByExpirationRBTree.remove(orderHash); - delete this._expiration[orderHash]; - } - private _pruneExpiredOrders(callback: (orderHash: string) => void): void { - const currentUnixTimestampMs = utils.getCurrentUnixTimestampMs(); - while (true) { - const hasNoTrackedOrders = this._orderHashByExpirationRBTree.size === 0; - if (hasNoTrackedOrders) { - break; - } - const nextOrderHashToExpire = this._orderHashByExpirationRBTree.min(); - const hasNoExpiredOrders = this._expiration[nextOrderHashToExpire].isGreaterThan( - currentUnixTimestampMs.plus(this._expirationMarginMs), - ); - const isSubscriptionActive = this._orderExpirationCheckingIntervalIdIfExists === undefined; - if (hasNoExpiredOrders || isSubscriptionActive) { - break; - } - const orderHash = this._orderHashByExpirationRBTree.min(); - this._orderHashByExpirationRBTree.remove(orderHash); - delete this._expiration[orderHash]; - callback(orderHash); - } - } -} diff --git a/packages/order-watcher/src/order_watcher/order_watcher.ts b/packages/order-watcher/src/order_watcher/order_watcher.ts deleted file mode 100644 index 78c619859f..0000000000 --- a/packages/order-watcher/src/order_watcher/order_watcher.ts +++ /dev/null @@ -1,514 +0,0 @@ -// tslint:disable:no-unnecessary-type-assertion -import { ContractAddresses } from '@0x/contract-addresses'; -import * as artifacts from '@0x/contract-artifacts'; -import { - AssetBalanceAndProxyAllowanceFetcher, - ContractWrappers, - ERC20TokenApprovalEventArgs, - ERC20TokenEventArgs, - ERC20TokenEvents, - ERC20TokenTransferEventArgs, - ERC721TokenApprovalEventArgs, - ERC721TokenApprovalForAllEventArgs, - ERC721TokenEventArgs, - ERC721TokenEvents, - ERC721TokenTransferEventArgs, - ExchangeCancelEventArgs, - ExchangeCancelUpToEventArgs, - ExchangeEventArgs, - ExchangeEvents, - ExchangeFillEventArgs, - OrderFilledCancelledFetcher, - WETH9DepositEventArgs, - WETH9EventArgs, - WETH9Events, - WETH9WithdrawalEventArgs, -} from '@0x/contract-wrappers'; -import { schemas } from '@0x/json-schemas'; -import { - assetDataUtils, - BalanceAndProxyAllowanceLazyStore, - OrderFilledCancelledLazyStore, - orderHashUtils, - OrderStateUtils, -} from '@0x/order-utils'; -import { AssetProxyId, ExchangeContractErrs, OrderState, SignedOrder, Stats } from '@0x/types'; -import { errorUtils, intervalUtils, providerUtils } from '@0x/utils'; -import { - BlockParamLiteral, - LogEntryEvent, - LogWithDecodedArgs, - SupportedProvider, - ZeroExProvider, -} from 'ethereum-types'; -import * as _ from 'lodash'; -import { Lock } from 'semaphore-async-await'; - -import { orderWatcherPartialConfigSchema } from '../schemas/order_watcher_partial_config_schema'; -import { OnOrderStateChangeCallback, OrderWatcherConfig, OrderWatcherError } from '../types'; -import { assert } from '../utils/assert'; - -import { CollisionResistanceAbiDecoder } from './collision_resistant_abi_decoder'; -import { DependentOrderHashesTracker } from './dependent_order_hashes_tracker'; -import { EventWatcher } from './event_watcher'; -import { ExpirationWatcher } from './expiration_watcher'; - -const MILLISECONDS_IN_A_SECOND = 1000; - -type ContractEventArgs = WETH9EventArgs | ExchangeEventArgs | ERC20TokenEventArgs | ERC721TokenEventArgs; - -interface OrderByOrderHash { - [orderHash: string]: SignedOrder; -} - -interface OrderStateByOrderHash { - [orderHash: string]: OrderState; -} - -const DEFAULT_ORDER_WATCHER_CONFIG: OrderWatcherConfig = { - orderExpirationCheckingIntervalMs: 50, - eventPollingIntervalMs: 200, - expirationMarginMs: 0, - // tslint:disable-next-line:custom-no-magic-numbers - cleanupJobIntervalMs: 1000 * 60 * 60, // 1h - isVerbose: true, -}; -const STATE_LAYER = BlockParamLiteral.Latest; - -/** - * This class includes all the functionality related to watching a set of orders - * for potential changes in order validity/fillability. The orderWatcher notifies - * the subscriber of these changes so that a final decision can be made on whether - * the order should be deemed invalid. - */ -export class OrderWatcher { - private readonly _dependentOrderHashesTracker: DependentOrderHashesTracker; - private readonly _orderStateByOrderHashCache: OrderStateByOrderHash = {}; - private readonly _orderByOrderHash: OrderByOrderHash = {}; - private readonly _lock = new Lock(); - private readonly _eventWatcher: EventWatcher; - private readonly _provider: ZeroExProvider; - private readonly _collisionResistantAbiDecoder: CollisionResistanceAbiDecoder; - private readonly _expirationWatcher: ExpirationWatcher; - private readonly _orderStateUtils: OrderStateUtils; - private readonly _orderFilledCancelledLazyStore: OrderFilledCancelledLazyStore; - private readonly _balanceAndProxyAllowanceLazyStore: BalanceAndProxyAllowanceLazyStore; - private readonly _cleanupJobInterval: number; - private _cleanupJobIntervalIdIfExists?: NodeJS.Timer; - private _callbackIfExists?: OnOrderStateChangeCallback; - /** - * Instantiate a new OrderWatcher - * @param supportedProvider Web3 provider to use for JSON RPC calls - * @param networkId NetworkId to watch orders on - * @param contractAddresses Optional contract addresses. Defaults to known - * addresses based on networkId. - * @param partialConfig Optional configurations - */ - constructor( - supportedProvider: SupportedProvider, - networkId: number, - contractAddresses?: ContractAddresses, - partialConfig: Partial = DEFAULT_ORDER_WATCHER_CONFIG, - ) { - const provider = providerUtils.standardizeOrThrow(supportedProvider); - assert.isNumber('networkId', networkId); - assert.doesConformToSchema('partialConfig', partialConfig, orderWatcherPartialConfigSchema); - const config = { - ...DEFAULT_ORDER_WATCHER_CONFIG, - ...partialConfig, - }; - - this._provider = provider; - this._collisionResistantAbiDecoder = new CollisionResistanceAbiDecoder( - artifacts.ERC20Token.compilerOutput.abi, - artifacts.ERC721Token.compilerOutput.abi, - [artifacts.WETH9.compilerOutput.abi, artifacts.Exchange.compilerOutput.abi], - ); - const contractWrappers = new ContractWrappers(provider, { - networkId, - // Note(albrow): We let the contract-wrappers package handle - // default values for contractAddresses. - contractAddresses, - }); - this._eventWatcher = new EventWatcher(provider, config.eventPollingIntervalMs, config.isVerbose); - const balanceAndProxyAllowanceFetcher = new AssetBalanceAndProxyAllowanceFetcher( - contractWrappers.erc20Token, - contractWrappers.erc721Token, - STATE_LAYER, - ); - this._balanceAndProxyAllowanceLazyStore = new BalanceAndProxyAllowanceLazyStore( - balanceAndProxyAllowanceFetcher, - ); - const orderFilledCancelledFetcher = new OrderFilledCancelledFetcher(contractWrappers.exchange, STATE_LAYER); - this._orderFilledCancelledLazyStore = new OrderFilledCancelledLazyStore(orderFilledCancelledFetcher); - this._orderStateUtils = new OrderStateUtils(balanceAndProxyAllowanceFetcher, orderFilledCancelledFetcher); - const expirationMarginIfExistsMs = config === undefined ? undefined : config.expirationMarginMs; - this._expirationWatcher = new ExpirationWatcher( - expirationMarginIfExistsMs, - config.orderExpirationCheckingIntervalMs, - ); - this._cleanupJobInterval = config.cleanupJobIntervalMs; - const zrxTokenAddress = assetDataUtils.decodeERC20AssetData(orderFilledCancelledFetcher.getZRXAssetData()) - .tokenAddress; - this._dependentOrderHashesTracker = new DependentOrderHashesTracker(zrxTokenAddress); - } - /** - * Add an order to the orderWatcher. Before the order is added, it's - * signature is verified. - * @param signedOrder The order you wish to start watching. - */ - public async addOrderAsync(signedOrder: SignedOrder): Promise { - assert.doesConformToSchema('signedOrder', signedOrder, schemas.signedOrderSchema); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - await assert.isValidSignatureAsync(this._provider, orderHash, signedOrder.signature, signedOrder.makerAddress); - - const expirationUnixTimestampMs = signedOrder.expirationTimeSeconds.times(MILLISECONDS_IN_A_SECOND); - this._expirationWatcher.addOrder(orderHash, expirationUnixTimestampMs); - - this._orderByOrderHash[orderHash] = signedOrder; - this._dependentOrderHashesTracker.addToDependentOrderHashes(signedOrder); - - const orderAssetDatas = [signedOrder.makerAssetData, signedOrder.takerAssetData]; - _.each(orderAssetDatas, assetData => this._addAssetDataToAbiDecoder(assetData)); - } - /** - * Removes an order from the orderWatcher - * @param orderHash The orderHash of the order you wish to stop watching. - */ - public removeOrder(orderHash: string): void { - assert.doesConformToSchema('orderHash', orderHash, schemas.orderHashSchema); - const signedOrder = this._orderByOrderHash[orderHash]; - if (signedOrder === undefined) { - return; // noop - } - this._dependentOrderHashesTracker.removeFromDependentOrderHashes(signedOrder); - delete this._orderByOrderHash[orderHash]; - this._expirationWatcher.removeOrder(orderHash); - delete this._orderStateByOrderHashCache[orderHash]; - } - /** - * Starts an orderWatcher subscription. The callback will be called every time a watched order's - * backing blockchain state has changed. This is a call-to-action for the caller to re-validate the order. - * @param callback Receives the orderHash of the order that should be re-validated, together - * with all the order-relevant blockchain state needed to re-validate the order. - */ - public subscribe(callback: OnOrderStateChangeCallback): void { - assert.isFunction('callback', callback); - if (this._callbackIfExists !== undefined) { - throw new Error(OrderWatcherError.SubscriptionAlreadyPresent); - } - this._callbackIfExists = callback; - this._eventWatcher.subscribe( - this._addLockToCallbackAsync.bind(this, this._onEventWatcherCallbackAsync.bind(this)), - ); - this._expirationWatcher.subscribe(this._addLockToCallbackAsync.bind(this, this._onOrderExpired.bind(this))); - this._cleanupJobIntervalIdIfExists = intervalUtils.setAsyncExcludingInterval( - this._addLockToCallbackAsync.bind(this, this._cleanupAsync.bind(this)), - this._cleanupJobInterval, - (err: Error) => { - this.unsubscribe(); - callback(err); - }, - ); - } - /** - * Ends an orderWatcher subscription. - */ - public unsubscribe(): void { - if (this._callbackIfExists === undefined || this._cleanupJobIntervalIdIfExists === undefined) { - throw new Error(OrderWatcherError.SubscriptionNotFound); - } - this._balanceAndProxyAllowanceLazyStore.deleteAll(); - this._orderFilledCancelledLazyStore.deleteAll(); - delete this._callbackIfExists; - this._eventWatcher.unsubscribe(); - this._expirationWatcher.unsubscribe(); - intervalUtils.clearAsyncExcludingInterval(this._cleanupJobIntervalIdIfExists); - } - /** - * Gets statistics of the OrderWatcher Instance. - */ - public getStats(): Stats { - return { - orderCount: _.size(this._orderByOrderHash), - }; - } - private async _addLockToCallbackAsync(cbAsync: any, ...params: any[]): Promise { - await this._lock.acquire(); - try { - await cbAsync(...params); - await this._lock.release(); - } catch (err) { - // Make sure to releasee the lock if an error is thrown - await this._lock.release(); - throw err; - } - } - private async _cleanupAsync(): Promise { - for (const orderHash of _.keys(this._orderByOrderHash)) { - this._cleanupOrderRelatedState(orderHash); - await this._emitRevalidateOrdersAsync([orderHash]); - } - } - private _addAssetDataToAbiDecoder(assetData: string): void { - const decodedAssetData = assetDataUtils.decodeAssetDataOrThrow(assetData); - if (assetDataUtils.isERC20AssetData(decodedAssetData)) { - this._collisionResistantAbiDecoder.addERC20Token(decodedAssetData.tokenAddress); - } else if (assetDataUtils.isERC721AssetData(decodedAssetData)) { - this._collisionResistantAbiDecoder.addERC721Token(decodedAssetData.tokenAddress); - } else if (assetDataUtils.isMultiAssetData(decodedAssetData)) { - _.each(decodedAssetData.nestedAssetData, nestedAssetDataElement => - this._addAssetDataToAbiDecoder(nestedAssetDataElement), - ); - } - } - private _deleteLazyStoreBalance(assetData: string, userAddress: string): void { - const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData); - switch (assetProxyId) { - case AssetProxyId.ERC20: - case AssetProxyId.ERC721: - this._balanceAndProxyAllowanceLazyStore.deleteBalance(assetData, userAddress); - break; - case AssetProxyId.MultiAsset: - const decodedAssetData = assetDataUtils.decodeMultiAssetData(assetData); - _.each(decodedAssetData.nestedAssetData, nestedAssetDataElement => - this._deleteLazyStoreBalance(nestedAssetDataElement, userAddress), - ); - break; - default: - break; - } - } - private _deleteLazyStoreProxyAllowance(assetData: string, userAddress: string): void { - const assetProxyId = assetDataUtils.decodeAssetProxyId(assetData); - switch (assetProxyId) { - case AssetProxyId.ERC20: - case AssetProxyId.ERC721: - this._balanceAndProxyAllowanceLazyStore.deleteProxyAllowance(assetData, userAddress); - break; - case AssetProxyId.MultiAsset: - const decodedAssetData = assetDataUtils.decodeMultiAssetData(assetData); - _.each(decodedAssetData.nestedAssetData, nestedAssetDataElement => - this._deleteLazyStoreProxyAllowance(nestedAssetDataElement, userAddress), - ); - break; - default: - break; - } - } - private _cleanupOrderRelatedState(orderHash: string): void { - const signedOrder = this._orderByOrderHash[orderHash]; - - this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(orderHash); - this._orderFilledCancelledLazyStore.deleteIsCancelled(orderHash); - - this._deleteLazyStoreBalance(signedOrder.makerAssetData, signedOrder.makerAddress); - this._deleteLazyStoreProxyAllowance(signedOrder.makerAssetData, signedOrder.makerAddress); - this._deleteLazyStoreBalance(signedOrder.takerAssetData, signedOrder.takerAddress); - this._deleteLazyStoreProxyAllowance(signedOrder.takerAssetData, signedOrder.takerAddress); - - const zrxAssetData = this._orderFilledCancelledLazyStore.getZRXAssetData(); - if (!signedOrder.makerFee.isZero()) { - this._deleteLazyStoreBalance(zrxAssetData, signedOrder.makerAddress); - this._deleteLazyStoreProxyAllowance(zrxAssetData, signedOrder.makerAddress); - } - if (!signedOrder.takerFee.isZero()) { - this._deleteLazyStoreBalance(zrxAssetData, signedOrder.takerAddress); - this._deleteLazyStoreProxyAllowance(zrxAssetData, signedOrder.takerAddress); - } - } - private _onOrderExpired(orderHash: string): void { - const orderState: OrderState = { - isValid: false, - orderHash, - error: ExchangeContractErrs.OrderFillExpired, - }; - if (this._orderByOrderHash[orderHash] !== undefined) { - this.removeOrder(orderHash); - if (this._callbackIfExists !== undefined) { - this._callbackIfExists(null, orderState); - } - } - } - private async _onEventWatcherCallbackAsync(err: Error | null, logIfExists?: LogEntryEvent): Promise { - if (err !== null) { - if (this._callbackIfExists !== undefined) { - this._callbackIfExists(err); - } - return; - } - const maybeDecodedLog = this._collisionResistantAbiDecoder.tryToDecodeLogOrNoop( - // At this moment we are sure that no error occured and log is defined. - logIfExists as LogEntryEvent, - ); - const isLogDecoded = ((maybeDecodedLog as any) as LogWithDecodedArgs).event !== undefined; - if (!isLogDecoded) { - return; // noop - } - const decodedLog = (maybeDecodedLog as any) as LogWithDecodedArgs; - const transactionHash = decodedLog.transactionHash; - switch (decodedLog.event) { - case ERC20TokenEvents.Approval: - case ERC721TokenEvents.Approval: { - // ERC20 and ERC721 Transfer events have the same name so we need to distinguish them by args - if (decodedLog.args._value !== undefined) { - // ERC20 - // Invalidate cache - const args = decodedLog.args as ERC20TokenApprovalEventArgs; - const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address); - this._deleteLazyStoreProxyAllowance(tokenAssetData, args._owner); - // Revalidate orders - const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker( - args._owner, - tokenAssetData, - ); - await this._emitRevalidateOrdersAsync(orderHashes, transactionHash); - break; - } else { - // ERC721 - // Invalidate cache - const args = decodedLog.args as ERC721TokenApprovalEventArgs; - const tokenAssetData = assetDataUtils.encodeERC721AssetData(decodedLog.address, args._tokenId); - this._deleteLazyStoreProxyAllowance(tokenAssetData, args._owner); - // Revalidate orders - const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker( - args._owner, - tokenAssetData, - ); - await this._emitRevalidateOrdersAsync(orderHashes, transactionHash); - break; - } - } - case ERC20TokenEvents.Transfer: - case ERC721TokenEvents.Transfer: { - // ERC20 and ERC721 Transfer events have the same name so we need to distinguish them by args - if (decodedLog.args._value !== undefined) { - // ERC20 - // Invalidate cache - const args = decodedLog.args as ERC20TokenTransferEventArgs; - const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address); - this._deleteLazyStoreBalance(tokenAssetData, args._from); - this._deleteLazyStoreBalance(tokenAssetData, args._to); - // Revalidate orders - const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker( - args._from, - tokenAssetData, - ); - await this._emitRevalidateOrdersAsync(orderHashes, transactionHash); - break; - } else { - // ERC721 - // Invalidate cache - const args = decodedLog.args as ERC721TokenTransferEventArgs; - const tokenAssetData = assetDataUtils.encodeERC721AssetData(decodedLog.address, args._tokenId); - this._deleteLazyStoreBalance(tokenAssetData, args._from); - this._deleteLazyStoreBalance(tokenAssetData, args._to); - // Revalidate orders - const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker( - args._from, - tokenAssetData, - ); - await this._emitRevalidateOrdersAsync(orderHashes, transactionHash); - break; - } - } - case ERC721TokenEvents.ApprovalForAll: { - // Invalidate cache - const args = decodedLog.args as ERC721TokenApprovalForAllEventArgs; - const tokenAddress = decodedLog.address; - this._balanceAndProxyAllowanceLazyStore.deleteAllERC721ProxyAllowance(tokenAddress, args._owner); - // Revalidate orders - const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByERC721ByMaker( - args._owner, - tokenAddress, - ); - await this._emitRevalidateOrdersAsync(orderHashes, transactionHash); - break; - } - case WETH9Events.Deposit: { - // Invalidate cache - const args = decodedLog.args as WETH9DepositEventArgs; - const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address); - this._deleteLazyStoreBalance(tokenAssetData, args._owner); - // Revalidate orders - const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker( - args._owner, - tokenAssetData, - ); - await this._emitRevalidateOrdersAsync(orderHashes, transactionHash); - break; - } - case WETH9Events.Withdrawal: { - // Invalidate cache - const args = decodedLog.args as WETH9WithdrawalEventArgs; - const tokenAssetData = assetDataUtils.encodeERC20AssetData(decodedLog.address); - this._deleteLazyStoreBalance(tokenAssetData, args._owner); - // Revalidate orders - const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByAssetDataByMaker( - args._owner, - tokenAssetData, - ); - await this._emitRevalidateOrdersAsync(orderHashes, transactionHash); - break; - } - case ExchangeEvents.Fill: { - // Invalidate cache - const args = decodedLog.args as ExchangeFillEventArgs; - this._orderFilledCancelledLazyStore.deleteFilledTakerAmount(args.orderHash); - // Revalidate orders - const orderHash = args.orderHash; - const isOrderWatched = this._orderByOrderHash[orderHash] !== undefined; - if (isOrderWatched) { - await this._emitRevalidateOrdersAsync([orderHash], transactionHash); - } - break; - } - case ExchangeEvents.Cancel: { - // Invalidate cache - const args = decodedLog.args as ExchangeCancelEventArgs; - this._orderFilledCancelledLazyStore.deleteIsCancelled(args.orderHash); - // Revalidate orders - const orderHash = args.orderHash; - const isOrderWatched = this._orderByOrderHash[orderHash] !== undefined; - if (isOrderWatched) { - await this._emitRevalidateOrdersAsync([orderHash], transactionHash); - } - break; - } - case ExchangeEvents.CancelUpTo: { - // TODO(logvinov): Do it smarter and actually look at the salt and order epoch - // Invalidate cache - const args = decodedLog.args as ExchangeCancelUpToEventArgs; - this._orderFilledCancelledLazyStore.deleteAllIsCancelled(); - // Revalidate orders - const orderHashes = this._dependentOrderHashesTracker.getDependentOrderHashesByMaker(args.makerAddress); - await this._emitRevalidateOrdersAsync(orderHashes, transactionHash); - break; - } - - default: - throw errorUtils.spawnSwitchErr('decodedLog.event', decodedLog.event); - } - } - private async _emitRevalidateOrdersAsync(orderHashes: string[], transactionHash?: string): Promise { - for (const orderHash of orderHashes) { - const signedOrder = this._orderByOrderHash[orderHash]; - if (signedOrder === undefined) { - continue; - } - // Most of these calls will never reach the network because the data is fetched from stores - // and only updated when cache is invalidated - const orderState = await this._orderStateUtils.getOpenOrderStateAsync(signedOrder, transactionHash); - if (this._callbackIfExists === undefined) { - break; // Unsubscribe was called - } - if (_.isEqual(orderState, this._orderStateByOrderHashCache[orderHash])) { - // Actual order state didn't change - continue; - } else { - this._orderStateByOrderHashCache[orderHash] = orderState; - } - this._callbackIfExists(null, orderState); - } - } -} // tslint:disable:max-file-line-count diff --git a/packages/order-watcher/src/order_watcher/order_watcher_web_socket_server.ts b/packages/order-watcher/src/order_watcher/order_watcher_web_socket_server.ts deleted file mode 100644 index f372711a4f..0000000000 --- a/packages/order-watcher/src/order_watcher/order_watcher_web_socket_server.ts +++ /dev/null @@ -1,200 +0,0 @@ -import { ContractAddresses } from '@0x/contract-addresses'; -import { schemas } from '@0x/json-schemas'; -import { OrderStateInvalid, OrderStateValid, SignedOrder } from '@0x/types'; -import { BigNumber, logUtils } from '@0x/utils'; -import { SupportedProvider } from 'ethereum-types'; -import * as http from 'http'; -import * as WebSocket from 'websocket'; - -import { GetStatsResult, OrderWatcherConfig, OrderWatcherMethod, WebSocketRequest, WebSocketResponse } from '../types'; -import { assert } from '../utils/assert'; - -import { OrderWatcher } from './order_watcher'; - -const DEFAULT_HTTP_PORT = 8080; -const JSON_RPC_VERSION = '2.0'; - -// Wraps the OrderWatcher functionality in a WebSocket server. Motivations: -// 1) Users can watch orders via non-typescript programs. -// 2) Better encapsulation so that users can work -export class OrderWatcherWebSocketServer { - private readonly _orderWatcher: OrderWatcher; - private readonly _httpServer: http.Server; - private readonly _connectionStore: Set; - private readonly _wsServer: WebSocket.server; - private readonly _isVerbose: boolean; - /** - * Recover types lost when the payload is stringified. - */ - private static _parseSignedOrder(rawRequest: any): SignedOrder { - const bigNumberFields = [ - 'salt', - 'makerFee', - 'takerFee', - 'makerAssetAmount', - 'takerAssetAmount', - 'expirationTimeSeconds', - ]; - for (const field of bigNumberFields) { - rawRequest[field] = new BigNumber(rawRequest[field]); - } - return rawRequest; - } - - /** - * Instantiate a new WebSocket server which provides OrderWatcher functionality - * @param supportedProvider Web3 provider to use for JSON RPC calls. - * @param networkId NetworkId to watch orders on. - * @param contractAddresses Optional contract addresses. Defaults to known - * addresses based on networkId. - * @param orderWatcherConfig OrderWatcher configurations. isVerbose sets the verbosity for the WebSocket server aswell. - * @param isVerbose Whether to enable verbose logging. Defaults to true. - */ - constructor( - supportedProvider: SupportedProvider, - networkId: number, - contractAddresses?: ContractAddresses, - orderWatcherConfig?: Partial, - ) { - this._isVerbose = - orderWatcherConfig !== undefined && orderWatcherConfig.isVerbose !== undefined - ? orderWatcherConfig.isVerbose - : true; - this._orderWatcher = new OrderWatcher(supportedProvider, networkId, contractAddresses, orderWatcherConfig); - this._connectionStore = new Set(); - this._httpServer = http.createServer(); - this._wsServer = new WebSocket.server({ - httpServer: this._httpServer, - // Avoid setting autoAcceptConnections to true as it defeats all - // standard cross-origin protection facilities built into the protocol - // and the browser. - // Source: https://www.npmjs.com/package/websocket#server-example - // Also ensures that a request event is emitted by - // the server whenever a new WebSocket request is made. - autoAcceptConnections: false, - }); - - this._wsServer.on('request', async (request: any) => { - // Designed for usage pattern where client and server are run on the same - // machine by the same user. As such, no security checks are in place. - const connection: WebSocket.connection = request.accept(null, request.origin); - this._log(`${new Date()} [Server] Accepted connection from origin ${request.origin}.`); - connection.on('message', this._onMessageCallbackAsync.bind(this, connection)); - connection.on('close', this._onCloseCallback.bind(this, connection)); - this._connectionStore.add(connection); - }); - } - - /** - * Activates the WebSocket server by subscribing to the OrderWatcher and - * starting the WebSocket's HTTP server - */ - public start(): void { - // Have the WebSocket server subscribe to the OrderWatcher to receive updates. - // These updates are then broadcast to clients in the _connectionStore. - this._orderWatcher.subscribe(this._broadcastCallback.bind(this)); - - const port = process.env.ORDER_WATCHER_HTTP_PORT || DEFAULT_HTTP_PORT; - this._httpServer.listen(port, () => { - this._log(`${new Date()} [Server] Listening on port ${port}`); - }); - } - - /** - * Deactivates the WebSocket server by stopping the HTTP server from accepting - * new connections and unsubscribing from the OrderWatcher - */ - public stop(): void { - this._httpServer.close(); - this._orderWatcher.unsubscribe(); - } - - private _log(...args: any[]): void { - if (this._isVerbose) { - logUtils.log(...args); - } - } - - private async _onMessageCallbackAsync(connection: WebSocket.connection, message: any): Promise { - let response: WebSocketResponse; - let id: number | null = null; - try { - assert.doesConformToSchema('message', message, schemas.orderWatcherWebSocketUtf8MessageSchema); - const request: WebSocketRequest = JSON.parse(message.utf8Data); - id = request.id; - assert.doesConformToSchema('request', request, schemas.orderWatcherWebSocketRequestSchema); - assert.isString(request.jsonrpc, JSON_RPC_VERSION); - response = { - id, - jsonrpc: JSON_RPC_VERSION, - method: request.method, - result: await this._routeRequestAsync(request), - }; - } catch (err) { - response = { - id, - jsonrpc: JSON_RPC_VERSION, - method: null, - error: err.toString(), - }; - } - this._log(`${new Date()} [Server] OrderWatcher output: ${JSON.stringify(response)}`); - connection.sendUTF(JSON.stringify(response)); - } - - private _onCloseCallback(connection: WebSocket.connection): void { - this._connectionStore.delete(connection); - this._log(`${new Date()} [Server] Client ${connection.remoteAddress} disconnected.`); - } - - private async _routeRequestAsync(request: WebSocketRequest): Promise { - this._log(`${new Date()} [Server] Request received: ${request.method}`); - switch (request.method) { - case OrderWatcherMethod.AddOrder: { - const signedOrder: SignedOrder = OrderWatcherWebSocketServer._parseSignedOrder( - request.params.signedOrder, - ); - await this._orderWatcher.addOrderAsync(signedOrder); - break; - } - case OrderWatcherMethod.RemoveOrder: { - this._orderWatcher.removeOrder(request.params.orderHash || 'undefined'); - break; - } - case OrderWatcherMethod.GetStats: { - return this._orderWatcher.getStats(); - } - default: - // Should never reach here. Should be caught by JSON schema check. - throw new Error(`Unexpected default case hit for request.method`); - } - return undefined; - } - - /** - * Broadcasts OrderState changes to ALL connected clients. At the moment, - * we do not support clients subscribing to only a subset of orders. As such, - * Client B will be notified of changes to an order that Client A added. - */ - private _broadcastCallback(err: Error | null, orderState?: OrderStateValid | OrderStateInvalid | undefined): void { - const method = OrderWatcherMethod.Update; - const response = - err === null - ? { - jsonrpc: JSON_RPC_VERSION, - method, - result: orderState, - } - : { - jsonrpc: JSON_RPC_VERSION, - method, - error: { - code: -32000, - message: err.message, - }, - }; - this._connectionStore.forEach((connection: WebSocket.connection) => { - connection.sendUTF(JSON.stringify(response)); - }); - } -} diff --git a/packages/order-watcher/src/schemas/order_watcher_partial_config_schema.ts b/packages/order-watcher/src/schemas/order_watcher_partial_config_schema.ts deleted file mode 100644 index 8bfced063a..0000000000 --- a/packages/order-watcher/src/schemas/order_watcher_partial_config_schema.ts +++ /dev/null @@ -1,13 +0,0 @@ -export const orderWatcherPartialConfigSchema = { - id: '/OrderWatcherPartialConfigSchema', - properties: { - stateLayer: { $ref: '/blockParamSchema' }, - orderExpirationCheckingIntervalMs: { type: 'number' }, - eventPollingIntervalMs: { type: 'number' }, - expirationMarginMs: { type: 'number' }, - cleanupJobIntervalMs: { type: 'number' }, - isVerbose: { type: 'boolean' }, - }, - type: 'object', - required: [], -}; diff --git a/packages/order-watcher/src/server.ts b/packages/order-watcher/src/server.ts deleted file mode 100644 index 9afb4c65d8..0000000000 --- a/packages/order-watcher/src/server.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { getContractAddressesForNetworkOrThrow } from '@0x/contract-addresses'; -import { RPCSubprovider, Web3ProviderEngine } from '@0x/subproviders'; -import { providerUtils } from '@0x/utils'; -import * as _ from 'lodash'; - -import { OrderWatcherWebSocketServer } from './order_watcher/order_watcher_web_socket_server'; - -const GANACHE_NETWORK_ID = 50; -const DEFAULT_RPC_URL = 'http://localhost:8545'; - -const provider = new Web3ProviderEngine(); -const jsonRpcUrl = process.env.JSON_RPC_URL || DEFAULT_RPC_URL; -const rpcSubprovider = new RPCSubprovider(jsonRpcUrl); -provider.addProvider(rpcSubprovider); -providerUtils.startProviderEngine(provider); - -const networkId = process.env.NETWORK_ID !== undefined ? _.parseInt(process.env.NETWORK_ID) : GANACHE_NETWORK_ID; - -const contractAddressesString = process.env.contractAddresses; -const contractAddressesIfExists = - contractAddressesString === undefined - ? getContractAddressesForNetworkOrThrow(networkId) - : JSON.parse(contractAddressesString); - -const orderWatcherConfig: any = { - isVerbose: process.env.IS_VERBOSE === 'true', -}; -const orderExpirationCheckingIntervalMs = process.env.ORDER_EXPIRATION_CHECKING_INTERVAL_MS; -if (orderExpirationCheckingIntervalMs !== undefined) { - orderWatcherConfig.orderExpirationCheckingIntervalMs = _.parseInt(orderExpirationCheckingIntervalMs); -} -const eventPollingIntervalMs = process.env.EVENT_POLLING_INTERVAL_MS; -if (eventPollingIntervalMs !== undefined) { - orderWatcherConfig.eventPollingIntervalMs = _.parseInt(eventPollingIntervalMs); -} -const expirationMarginMs = process.env.EXPIRATION_MARGIN_MS; -if (expirationMarginMs !== undefined) { - orderWatcherConfig.expirationMarginMs = _.parseInt(expirationMarginMs); -} -const cleanupJobIntervalMs = process.env.CLEANUP_JOB_INTERVAL_MS; -if (cleanupJobIntervalMs !== undefined) { - orderWatcherConfig.cleanupJobIntervalMs = _.parseInt(cleanupJobIntervalMs); -} -const wsServer = new OrderWatcherWebSocketServer(provider, networkId, contractAddressesIfExists, orderWatcherConfig); -wsServer.start(); diff --git a/packages/order-watcher/src/types.ts b/packages/order-watcher/src/types.ts deleted file mode 100644 index 2b529a9391..0000000000 --- a/packages/order-watcher/src/types.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { OrderState, SignedOrder } from '@0x/types'; -import { LogEntryEvent } from 'ethereum-types'; - -export enum OrderWatcherError { - SubscriptionAlreadyPresent = 'SUBSCRIPTION_ALREADY_PRESENT', - SubscriptionNotFound = 'SUBSCRIPTION_NOT_FOUND', -} - -export type EventWatcherCallback = (err: null | Error, log?: LogEntryEvent) => void; - -/** - * orderExpirationCheckingIntervalMs: How often to check for expired orders. Default=50. - * eventPollingIntervalMs: How often to poll the Ethereum node for new events. Default=200. - * expirationMarginMs: Amount of time before order expiry that you'd like to be notified - * of an orders expiration. Default=0. - * cleanupJobIntervalMs: How often to run a cleanup job which revalidates all the orders. Default=1hr. - * isVerbose: Weather the order watcher should be verbose. Default=true. - */ -export interface OrderWatcherConfig { - orderExpirationCheckingIntervalMs: number; - eventPollingIntervalMs: number; - expirationMarginMs: number; - cleanupJobIntervalMs: number; - isVerbose: boolean; -} - -export type OnOrderStateChangeCallback = (err: Error | null, orderState?: OrderState) => void; - -export enum InternalOrderWatcherError { - NoAbiDecoder = 'NO_ABI_DECODER', - ZrxNotInTokenRegistry = 'ZRX_NOT_IN_TOKEN_REGISTRY', - WethNotInTokenRegistry = 'WETH_NOT_IN_TOKEN_REGISTRY', -} - -export enum OrderWatcherMethod { - // Methods initiated by the user. - GetStats = 'GET_STATS', - AddOrder = 'ADD_ORDER', - RemoveOrder = 'REMOVE_ORDER', - // These are spontaneous; they are primarily orderstate changes. - Update = 'UPDATE', - // `subscribe` and `unsubscribe` are methods of OrderWatcher, but we don't - // need to expose them to the WebSocket server user because the user implicitly - // subscribes and unsubscribes by connecting and disconnecting from the server. -} - -// Users have to create a json object of this format and attach it to -// the data field of their WebSocket message to interact with the server. -export type WebSocketRequest = AddOrderRequest | RemoveOrderRequest | GetStatsRequest; - -export interface AddOrderRequest { - id: number; - jsonrpc: string; - method: OrderWatcherMethod.AddOrder; - params: { signedOrder: SignedOrder }; -} - -export interface RemoveOrderRequest { - id: number; - jsonrpc: string; - method: OrderWatcherMethod.RemoveOrder; - params: { orderHash: string }; -} - -export interface GetStatsRequest { - id: number; - jsonrpc: string; - method: OrderWatcherMethod.GetStats; -} - -// Users should expect a json object of this format in the data field -// of the WebSocket messages that the server sends out. -export type WebSocketResponse = SuccessfulWebSocketResponse | ErrorWebSocketResponse; - -export interface SuccessfulWebSocketResponse { - id: number; - jsonrpc: string; - method: OrderWatcherMethod; - result: OrderState | GetStatsResult | undefined; // result is undefined for ADD_ORDER and REMOVE_ORDER -} - -export interface ErrorWebSocketResponse { - id: number | null; - jsonrpc: string; - method: null; - error: JSONRPCError; -} - -export interface JSONRPCError { - code: number; - message: string; - data?: string | object; -} - -export interface GetStatsResult { - orderCount: number; -} diff --git a/packages/order-watcher/src/utils/assert.ts b/packages/order-watcher/src/utils/assert.ts deleted file mode 100644 index ed28aebc6a..0000000000 --- a/packages/order-watcher/src/utils/assert.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { assert as sharedAssert } from '@0x/assert'; -// HACK: We need those two unused imports because they're actually used by sharedAssert which gets injected here -// tslint:disable:no-unused-variable -import { Schema } from '@0x/json-schemas'; -import { ECSignature } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -// tslint:enable:no-unused-variable -import { SupportedProvider } from 'ethereum-types'; - -import { signatureUtils } from '@0x/order-utils'; - -export const assert = { - ...sharedAssert, - async isValidSignatureAsync( - supportedProvider: SupportedProvider, - orderHash: string, - signature: string, - signerAddress: string, - ): Promise { - const isValid = await signatureUtils.isValidSignatureAsync( - supportedProvider, - orderHash, - signature, - signerAddress, - ); - assert.assert(isValid, `Expected order with hash '${orderHash}' to have a valid signature`); - }, -}; diff --git a/packages/order-watcher/src/utils/utils.ts b/packages/order-watcher/src/utils/utils.ts deleted file mode 100644 index 9c3849ff19..0000000000 --- a/packages/order-watcher/src/utils/utils.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { BigNumber } from '@0x/utils'; - -export const utils = { - getCurrentUnixTimestampSec(): BigNumber { - const milisecondsInASecond = 1000; - return new BigNumber(Date.now() / milisecondsInASecond).integerValue(); - }, - getCurrentUnixTimestampMs(): BigNumber { - return new BigNumber(Date.now()); - }, -}; diff --git a/packages/order-watcher/test/expiration_watcher_test.ts b/packages/order-watcher/test/expiration_watcher_test.ts deleted file mode 100644 index fb5ea2a27d..0000000000 --- a/packages/order-watcher/test/expiration_watcher_test.ts +++ /dev/null @@ -1,199 +0,0 @@ -import { tokenUtils } from '@0x/contract-wrappers/lib/test/utils/token_utils'; -import { BlockchainLifecycle, callbackErrorReporter } from '@0x/dev-utils'; -import { FillScenarios } from '@0x/fill-scenarios'; -import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; -import { DoneCallback } from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import * as chai from 'chai'; -import * as _ from 'lodash'; -import 'mocha'; -import * as Sinon from 'sinon'; - -import { ExpirationWatcher } from '../src/order_watcher/expiration_watcher'; -import { utils } from '../src/utils/utils'; - -import { chaiSetup } from './utils/chai_setup'; -import { migrateOnceAsync } from './utils/migrate'; -import { provider, web3Wrapper } from './utils/web3_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); -const MILISECONDS_IN_SECOND = 1000; - -describe('ExpirationWatcher', () => { - let userAddresses: string[]; - let fillScenarios: FillScenarios; - let makerAssetData: string; - let takerAssetData: string; - let coinbase: string; - let makerAddress: string; - let takerAddress: string; - let feeRecipient: string; - const fillableAmount = new BigNumber(5); - let currentUnixTimestampSec: BigNumber; - let timer: Sinon.SinonFakeTimers; - let expirationWatcher: ExpirationWatcher; - before(async () => { - const contractAddresses = await migrateOnceAsync(); - await blockchainLifecycle.startAsync(); - userAddresses = await web3Wrapper.getAvailableAddressesAsync(); - fillScenarios = new FillScenarios( - provider, - userAddresses, - contractAddresses.zrxToken, - contractAddresses.exchange, - contractAddresses.erc20Proxy, - contractAddresses.erc721Proxy, - ); - [coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses; - const [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); - [makerAssetData, takerAssetData] = [ - assetDataUtils.encodeERC20AssetData(makerTokenAddress), - assetDataUtils.encodeERC20AssetData(takerTokenAddress), - ]; - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - const sinonTimerConfig = { shouldAdvanceTime: true } as any; - // This constructor has incorrect types - timer = Sinon.useFakeTimers(sinonTimerConfig); - currentUnixTimestampSec = utils.getCurrentUnixTimestampSec(); - expirationWatcher = new ExpirationWatcher(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - timer.restore(); - expirationWatcher.unsubscribe(); - }); - it('correctly emits events when order expires', (done: DoneCallback) => { - (async () => { - const orderLifetimeSec = 60; - const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec); - const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - expirationUnixTimestampSec, - ); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - expirationWatcher.addOrder(orderHash, signedOrder.expirationTimeSeconds.times(MILISECONDS_IN_SECOND)); - const callbackAsync = callbackErrorReporter.reportNoErrorCallbackErrors(done)((hash: string) => { - expect(hash).to.be.equal(orderHash); - expect(utils.getCurrentUnixTimestampSec()).to.be.bignumber.gte(expirationUnixTimestampSec); - }); - expirationWatcher.subscribe(callbackAsync); - timer.tick(orderLifetimeSec * MILISECONDS_IN_SECOND); - })().catch(done); - }); - it("doesn't emit events before order expires", (done: DoneCallback) => { - (async () => { - const orderLifetimeSec = 60; - const expirationUnixTimestampSec = currentUnixTimestampSec.plus(orderLifetimeSec); - const signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - expirationUnixTimestampSec, - ); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - expirationWatcher.addOrder(orderHash, signedOrder.expirationTimeSeconds.times(MILISECONDS_IN_SECOND)); - const callbackAsync = callbackErrorReporter.reportNoErrorCallbackErrors(done)(async (_hash: string) => { - done(new Error('Emitted expiration went before the order actually expired')); - }); - expirationWatcher.subscribe(callbackAsync); - const notEnoughTime = orderLifetimeSec - 1; - timer.tick(notEnoughTime * MILISECONDS_IN_SECOND); - done(); - })().catch(done); - }); - it('emits events in correct order', (done: DoneCallback) => { - (async () => { - const order1Lifetime = 60; - const order2Lifetime = 120; - const order1ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order1Lifetime); - const order2ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order2Lifetime); - const signedOrder1 = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - order1ExpirationUnixTimestampSec, - ); - const signedOrder2 = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - order2ExpirationUnixTimestampSec, - ); - const orderHash1 = orderHashUtils.getOrderHashHex(signedOrder1); - const orderHash2 = orderHashUtils.getOrderHashHex(signedOrder2); - expirationWatcher.addOrder(orderHash2, signedOrder2.expirationTimeSeconds.times(MILISECONDS_IN_SECOND)); - expirationWatcher.addOrder(orderHash1, signedOrder1.expirationTimeSeconds.times(MILISECONDS_IN_SECOND)); - const expirationOrder = [orderHash1, orderHash2]; - const expectToBeCalledOnce = false; - const callbackAsync = callbackErrorReporter.reportNoErrorCallbackErrors(done, expectToBeCalledOnce)( - (hash: string) => { - const orderHash = expirationOrder.shift(); - expect(hash).to.be.equal(orderHash); - if (_.isEmpty(expirationOrder)) { - done(); - } - }, - ); - expirationWatcher.subscribe(callbackAsync); - timer.tick(order2Lifetime * MILISECONDS_IN_SECOND); - })().catch(done); - }); - it('emits events in correct order when expirations are equal', (done: DoneCallback) => { - (async () => { - const order1Lifetime = 60; - const order2Lifetime = 60; - const order1ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order1Lifetime); - const order2ExpirationUnixTimestampSec = currentUnixTimestampSec.plus(order2Lifetime); - const signedOrder1 = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - order1ExpirationUnixTimestampSec, - ); - const signedOrder2 = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - order2ExpirationUnixTimestampSec, - ); - const orderHash1 = orderHashUtils.getOrderHashHex(signedOrder1); - const orderHash2 = orderHashUtils.getOrderHashHex(signedOrder2); - expirationWatcher.addOrder(orderHash1, signedOrder1.expirationTimeSeconds.times(MILISECONDS_IN_SECOND)); - expirationWatcher.addOrder(orderHash2, signedOrder2.expirationTimeSeconds.times(MILISECONDS_IN_SECOND)); - const expirationOrder = orderHash1 < orderHash2 ? [orderHash1, orderHash2] : [orderHash2, orderHash1]; - const expectToBeCalledOnce = false; - const callbackAsync = callbackErrorReporter.reportNoErrorCallbackErrors(done, expectToBeCalledOnce)( - (hash: string) => { - const orderHash = expirationOrder.shift(); - expect(hash).to.be.equal(orderHash); - if (_.isEmpty(expirationOrder)) { - done(); - } - }, - ); - expirationWatcher.subscribe(callbackAsync); - timer.tick(order2Lifetime * MILISECONDS_IN_SECOND); - })().catch(done); - }); -}); diff --git a/packages/order-watcher/test/global_hooks.ts b/packages/order-watcher/test/global_hooks.ts deleted file mode 100644 index 26c37158f7..0000000000 --- a/packages/order-watcher/test/global_hooks.ts +++ /dev/null @@ -1,6 +0,0 @@ -before('set up mocha', async function(): Promise { - // HACK: Since the migrations take longer then our global mocha timeout limit - // we manually increase it for this before hook. - const mochaTestTimeoutMs = 25000; - this.timeout(mochaTestTimeoutMs); // tslint:disable-line:no-invalid-this -}); diff --git a/packages/order-watcher/test/order_watcher_test.ts b/packages/order-watcher/test/order_watcher_test.ts deleted file mode 100644 index 22bc666554..0000000000 --- a/packages/order-watcher/test/order_watcher_test.ts +++ /dev/null @@ -1,939 +0,0 @@ -// tslint:disable:no-unnecessary-type-assertion -import { ContractAddresses, ContractWrappers } from '@0x/contract-wrappers'; -import { tokenUtils } from '@0x/contract-wrappers/lib/test/utils/token_utils'; -import { BlockchainLifecycle, callbackErrorReporter } from '@0x/dev-utils'; -import { FillScenarios } from '@0x/fill-scenarios'; -import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; -import { orderFactory } from '@0x/order-utils/lib/src/order_factory'; -import { - DoneCallback, - ExchangeContractErrs, - OrderState, - OrderStateInvalid, - OrderStateValid, - SignedOrder, -} from '@0x/types'; -import { BigNumber } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as chai from 'chai'; -import * as _ from 'lodash'; -import 'mocha'; - -import { - DependentOrderHashesTracker, - OrderHashesByERC20ByMakerAddress, -} from '../src/order_watcher/dependent_order_hashes_tracker'; -import { OrderWatcher } from '../src/order_watcher/order_watcher'; -import { OrderWatcherError } from '../src/types'; - -import { chaiSetup } from './utils/chai_setup'; -import { constants } from './utils/constants'; -import { migrateOnceAsync } from './utils/migrate'; -import { provider, web3Wrapper } from './utils/web3_wrapper'; - -const TIMEOUT_MS = 150; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -describe('OrderWatcher', () => { - let contractWrappers: ContractWrappers; - let fillScenarios: FillScenarios; - let userAddresses: string[]; - let zrxTokenAddress: string; - let makerAssetData: string; - let takerAssetData: string; - let makerTokenAddress: string; - let takerTokenAddress: string; - let makerAddress: string; - let takerAddress: string; - let coinbase: string; - let feeRecipient: string; - let signedOrder: SignedOrder; - let orderWatcher: OrderWatcher; - let contractAddresses: ContractAddresses; - const decimals = constants.ZRX_DECIMALS; - const fillableAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(5), decimals); - before(async () => { - contractAddresses = await migrateOnceAsync(); - await blockchainLifecycle.startAsync(); - const networkId = constants.TESTRPC_NETWORK_ID; - const config = { - networkId, - contractAddresses, - }; - contractWrappers = new ContractWrappers(provider, config); - userAddresses = await web3Wrapper.getAvailableAddressesAsync(); - zrxTokenAddress = contractAddresses.zrxToken; - fillScenarios = new FillScenarios( - provider, - userAddresses, - zrxTokenAddress, - contractAddresses.exchange, - contractAddresses.erc20Proxy, - contractAddresses.erc721Proxy, - ); - [coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses; - [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); - [makerAssetData, takerAssetData] = [ - assetDataUtils.encodeERC20AssetData(makerTokenAddress), - assetDataUtils.encodeERC20AssetData(takerTokenAddress), - ]; - const orderWatcherConfig = {}; - orderWatcher = new OrderWatcher(provider, networkId, contractAddresses, orderWatcherConfig); - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - await blockchainLifecycle.revertAsync(); - }); - describe('DependentOrderHashesTracker', async () => { - let makerErc721TokenAddress: string; - [makerErc721TokenAddress] = tokenUtils.getDummyERC721TokenAddresses(); - it('should handle lookups on unknown addresses', async () => { - // Regression test - // ApprovalForAll events on a token from an untracked address could cause - // nested lookups on undefined object - // #1550 - const dependentOrderHashesTracker = (orderWatcher as any) - ._dependentOrderHashesTracker as DependentOrderHashesTracker; - dependentOrderHashesTracker.getDependentOrderHashesByERC721ByMaker(takerAddress, makerErc721TokenAddress); - }); - }); - describe('#removeOrder', async () => { - it('should successfully remove existing order', async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - ); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - await orderWatcher.addOrderAsync(signedOrder); - expect((orderWatcher as any)._orderByOrderHash).to.include({ - [orderHash]: signedOrder, - }); - const dependentOrderHashesTracker = (orderWatcher as any) - ._dependentOrderHashesTracker as DependentOrderHashesTracker; - let orderHashesByERC20ByMakerAddress: OrderHashesByERC20ByMakerAddress = (dependentOrderHashesTracker as any) - ._orderHashesByERC20ByMakerAddress; - expect(orderHashesByERC20ByMakerAddress[signedOrder.makerAddress][makerTokenAddress]).to.have.keys( - orderHash, - ); - orderWatcher.removeOrder(orderHash); - expect((orderWatcher as any)._orderByOrderHash).to.not.include({ - [orderHash]: signedOrder, - }); - orderHashesByERC20ByMakerAddress = (dependentOrderHashesTracker as any)._orderHashesByERC20ByMakerAddress; - expect(orderHashesByERC20ByMakerAddress[signedOrder.makerAddress]).to.be.undefined(); - }); - it('should no-op when removing a non-existing order', async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - ); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - const nonExistentOrderHash = `0x${orderHash - .substr(2) - .split('') - .reverse() - .join('')}`; - orderWatcher.removeOrder(nonExistentOrderHash); - }); - }); - describe('#subscribe', async () => { - afterEach(async () => { - orderWatcher.unsubscribe(); - }); - it('should fail when trying to subscribe twice', async () => { - orderWatcher.subscribe(_.noop.bind(_)); - expect(() => orderWatcher.subscribe(_.noop.bind(_))).to.throw(OrderWatcherError.SubscriptionAlreadyPresent); - }); - }); - describe('#getStats', async () => { - it('orderCount should increment and decrement with order additions and removals', async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - ); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - expect(orderWatcher.getStats().orderCount).to.be.eq(0); - await orderWatcher.addOrderAsync(signedOrder); - expect(orderWatcher.getStats().orderCount).to.be.eq(1); - orderWatcher.removeOrder(orderHash); - expect(orderWatcher.getStats().orderCount).to.be.eq(0); - }); - }); - describe('tests with cleanup', async () => { - beforeEach(async () => { - await blockchainLifecycle.startAsync(); - }); - afterEach(async () => { - orderWatcher.unsubscribe(); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - orderWatcher.removeOrder(orderHash); - await blockchainLifecycle.revertAsync(); - }); - it('should emit orderStateInvalid when makerAddress allowance set to 0 for watched order', (done: DoneCallback) => { - (async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - ); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - await orderWatcher.addOrderAsync(signedOrder); - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - expect(orderState.isValid).to.be.false(); - const invalidOrderState = orderState as OrderStateInvalid; - expect(invalidOrderState.orderHash).to.be.equal(orderHash); - expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance); - }); - orderWatcher.subscribe(callback); - await contractWrappers.erc20Token.setProxyAllowanceAsync( - makerTokenAddress, - makerAddress, - new BigNumber(0), - ); - })().catch(done); - }); - it('should not emit an orderState event when irrelevant Transfer event received', (done: DoneCallback) => { - (async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - ); - await orderWatcher.addOrderAsync(signedOrder); - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((_orderState: OrderState) => { - throw new Error('OrderState callback fired for irrelevant order'); - }); - orderWatcher.subscribe(callback); - const notTheMaker = userAddresses[0]; - const anyRecipient = takerAddress; - const transferAmount = new BigNumber(2); - await contractWrappers.erc20Token.transferAsync( - makerTokenAddress, - notTheMaker, - anyRecipient, - transferAmount, - ); - setTimeout(() => { - done(); - }, TIMEOUT_MS); - })().catch(done); - }); - it('should emit orderStateInvalid when makerAddress moves balance backing watched order', (done: DoneCallback) => { - (async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - ); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - await orderWatcher.addOrderAsync(signedOrder); - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - expect(orderState.isValid).to.be.false(); - const invalidOrderState = orderState as OrderStateInvalid; - expect(invalidOrderState.orderHash).to.be.equal(orderHash); - expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerBalance); - }); - orderWatcher.subscribe(callback); - const anyRecipient = takerAddress; - const makerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, makerAddress); - await contractWrappers.erc20Token.transferAsync( - makerTokenAddress, - makerAddress, - anyRecipient, - makerBalance, - ); - })().catch(done); - }); - it('should emit orderStateInvalid when watched order fully filled', (done: DoneCallback) => { - (async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - ); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - await orderWatcher.addOrderAsync(signedOrder); - - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - expect(orderState.isValid).to.be.false(); - const invalidOrderState = orderState as OrderStateInvalid; - expect(invalidOrderState.orderHash).to.be.equal(orderHash); - expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderRemainingFillAmountZero); - }); - orderWatcher.subscribe(callback); - - await contractWrappers.exchange.fillOrderAsync(signedOrder, fillableAmount, takerAddress); - })().catch(done); - }); - it('should include transactionHash in emitted orderStateInvalid when watched order fully filled', (done: DoneCallback) => { - (async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - ); - await orderWatcher.addOrderAsync(signedOrder); - - let transactionHash: string; - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - expect(orderState.isValid).to.be.false(); - const invalidOrderState = orderState as OrderStateInvalid; - expect(invalidOrderState.transactionHash).to.be.equal(transactionHash); - }); - orderWatcher.subscribe(callback); - - transactionHash = await contractWrappers.exchange.fillOrderAsync( - signedOrder, - fillableAmount, - takerAddress, - ); - })().catch(done); - }); - it('should emit orderStateValid when watched order partially filled', (done: DoneCallback) => { - (async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - ); - - const makerBalance = await contractWrappers.erc20Token.getBalanceAsync(makerTokenAddress, makerAddress); - const fillAmountInBaseUnits = new BigNumber(2); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - await orderWatcher.addOrderAsync(signedOrder); - - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - expect(orderState.isValid).to.be.true(); - const validOrderState = orderState as OrderStateValid; - expect(validOrderState.orderHash).to.be.equal(orderHash); - const orderRelevantState = validOrderState.orderRelevantState; - const remainingMakerBalance = makerBalance.minus(fillAmountInBaseUnits); - const remainingFillable = fillableAmount.minus(fillAmountInBaseUnits); - expect(orderRelevantState.remainingFillableMakerAssetAmount).to.be.bignumber.equal( - remainingFillable, - ); - expect(orderRelevantState.remainingFillableTakerAssetAmount).to.be.bignumber.equal( - remainingFillable, - ); - expect(orderRelevantState.makerBalance).to.be.bignumber.equal(remainingMakerBalance); - }); - orderWatcher.subscribe(callback); - await contractWrappers.exchange.fillOrderAsync(signedOrder, fillAmountInBaseUnits, takerAddress); - })().catch(done); - }); - it('should trigger the callback when orders backing ZRX allowance changes', (done: DoneCallback) => { - (async () => { - const makerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(2), decimals); - const takerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(0), decimals); - signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( - makerAssetData, - takerAssetData, - makerFee, - takerFee, - makerAddress, - takerAddress, - fillableAmount, - takerAddress, - ); - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)(); - await orderWatcher.addOrderAsync(signedOrder); - orderWatcher.subscribe(callback); - await contractWrappers.erc20Token.setProxyAllowanceAsync( - zrxTokenAddress, - makerAddress, - new BigNumber(0), - ); - })().catch(done); - }); - describe('remainingFillable(M|T)akerTokenAmount', () => { - it('should calculate correct remaining fillable', (done: DoneCallback) => { - (async () => { - const takerFillableAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(10), decimals); - const makerFillableAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(20), decimals); - signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - makerFillableAmount, - takerFillableAmount, - ); - const fillAmountInBaseUnits = Web3Wrapper.toBaseUnitAmount(new BigNumber(2), decimals); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - await orderWatcher.addOrderAsync(signedOrder); - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - expect(orderState.isValid).to.be.true(); - const validOrderState = orderState as OrderStateValid; - expect(validOrderState.orderHash).to.be.equal(orderHash); - const orderRelevantState = validOrderState.orderRelevantState; - expect(orderRelevantState.remainingFillableMakerAssetAmount).to.be.bignumber.equal( - Web3Wrapper.toBaseUnitAmount(new BigNumber(16), decimals), - ); - expect(orderRelevantState.remainingFillableTakerAssetAmount).to.be.bignumber.equal( - Web3Wrapper.toBaseUnitAmount(new BigNumber(8), decimals), - ); - }); - orderWatcher.subscribe(callback); - await contractWrappers.exchange.fillOrderAsync(signedOrder, fillAmountInBaseUnits, takerAddress); - })().catch(done); - }); - it('should equal approved amount when approved amount is lowest', (done: DoneCallback) => { - (async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - ); - - const changedMakerApprovalAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(3), decimals); - await orderWatcher.addOrderAsync(signedOrder); - - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - const validOrderState = orderState as OrderStateValid; - const orderRelevantState = validOrderState.orderRelevantState; - expect(orderRelevantState.remainingFillableMakerAssetAmount).to.be.bignumber.equal( - changedMakerApprovalAmount, - ); - expect(orderRelevantState.remainingFillableTakerAssetAmount).to.be.bignumber.equal( - changedMakerApprovalAmount, - ); - }); - orderWatcher.subscribe(callback); - await contractWrappers.erc20Token.setProxyAllowanceAsync( - makerTokenAddress, - makerAddress, - changedMakerApprovalAmount, - ); - })().catch(done); - }); - it('should equal balance amount when balance amount is lowest', (done: DoneCallback) => { - (async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - ); - - const makerBalance = await contractWrappers.erc20Token.getBalanceAsync( - makerTokenAddress, - makerAddress, - ); - - const remainingAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), decimals); - const transferAmount = makerBalance.minus(remainingAmount); - await orderWatcher.addOrderAsync(signedOrder); - - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - expect(orderState.isValid).to.be.true(); - const validOrderState = orderState as OrderStateValid; - const orderRelevantState = validOrderState.orderRelevantState; - expect(orderRelevantState.remainingFillableMakerAssetAmount).to.be.bignumber.equal( - remainingAmount, - ); - expect(orderRelevantState.remainingFillableTakerAssetAmount).to.be.bignumber.equal( - remainingAmount, - ); - }); - orderWatcher.subscribe(callback); - await contractWrappers.erc20Token.transferAsync( - makerTokenAddress, - makerAddress, - constants.NULL_ADDRESS, - transferAmount, - ); - })().catch(done); - }); - it('should equal ratio amount when fee balance is lowered', (done: DoneCallback) => { - (async () => { - const takerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(0), decimals); - const makerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(5), decimals); - signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( - makerAssetData, - takerAssetData, - makerFee, - takerFee, - makerAddress, - takerAddress, - fillableAmount, - feeRecipient, - ); - - const remainingFeeAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(3), decimals); - - const remainingTokenAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(4), decimals); - const transferTokenAmount = makerFee.minus(remainingTokenAmount); - await orderWatcher.addOrderAsync(signedOrder); - - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - const validOrderState = orderState as OrderStateValid; - const orderRelevantState = validOrderState.orderRelevantState; - expect(orderRelevantState.remainingFillableMakerAssetAmount).to.be.bignumber.equal( - remainingFeeAmount, - ); - }); - orderWatcher.subscribe(callback); - await contractWrappers.erc20Token.setProxyAllowanceAsync( - zrxTokenAddress, - makerAddress, - remainingFeeAmount, - ); - await contractWrappers.erc20Token.transferAsync( - makerTokenAddress, - makerAddress, - constants.NULL_ADDRESS, - transferTokenAmount, - ); - })().catch(done); - }); - it('should calculate full amount when all available and non-divisible', (done: DoneCallback) => { - (async () => { - const takerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(0), decimals); - const makerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(2), decimals); - signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( - makerAssetData, - takerAssetData, - makerFee, - takerFee, - makerAddress, - takerAddress, - fillableAmount, - feeRecipient, - ); - - await orderWatcher.addOrderAsync(signedOrder); - - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - const validOrderState = orderState as OrderStateValid; - const orderRelevantState = validOrderState.orderRelevantState; - expect(orderRelevantState.remainingFillableMakerAssetAmount).to.be.bignumber.equal( - fillableAmount, - ); - }); - orderWatcher.subscribe(callback); - await contractWrappers.erc20Token.setProxyAllowanceAsync( - makerTokenAddress, - makerAddress, - Web3Wrapper.toBaseUnitAmount(new BigNumber(100), decimals), - ); - })().catch(done); - }); - }); - it('should emit orderStateInvalid when watched order cancelled', (done: DoneCallback) => { - (async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - ); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - await orderWatcher.addOrderAsync(signedOrder); - - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - expect(orderState.isValid).to.be.false(); - const invalidOrderState = orderState as OrderStateInvalid; - expect(invalidOrderState.orderHash).to.be.equal(orderHash); - expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderCancelled); - }); - orderWatcher.subscribe(callback); - await contractWrappers.exchange.cancelOrderAsync(signedOrder); - })().catch(done); - }); - it('should emit orderStateInvalid when within rounding error range after a partial fill', (done: DoneCallback) => { - (async () => { - const fillAmountInBaseUnits = new BigNumber(2); - const makerAssetAmount = new BigNumber(1001); - const takerAssetAmount = new BigNumber(3); - signedOrder = await fillScenarios.createAsymmetricFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - makerAssetAmount, - takerAssetAmount, - ); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - await orderWatcher.addOrderAsync(signedOrder); - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - expect(orderState.isValid).to.be.false(); - const invalidOrderState = orderState as OrderStateInvalid; - expect(invalidOrderState.orderHash).to.be.equal(orderHash); - expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderFillRoundingError); - }); - orderWatcher.subscribe(callback); - await contractWrappers.exchange.fillOrderAsync(signedOrder, fillAmountInBaseUnits, takerAddress); - })().catch(done); - }); - it('should emit orderStateInvalid when makerAddress is unfunded by withdrawing WETH', (done: DoneCallback) => { - (async () => { - const etherTokenAddress = contractAddresses.etherToken; - const wethAssetData = assetDataUtils.encodeERC20AssetData(etherTokenAddress); - await contractWrappers.erc20Token.setUnlimitedProxyAllowanceAsync(etherTokenAddress, makerAddress); - const depositAmount = fillableAmount.times(2); - await contractWrappers.etherToken.depositAsync(etherTokenAddress, depositAmount, makerAddress); - // WETH for ZRX order - signedOrder = await orderFactory.createSignedOrderAsync( - web3Wrapper.getProvider(), - makerAddress, - fillableAmount, - wethAssetData, - fillableAmount, - takerAssetData, - contractAddresses.exchange, - ); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - await orderWatcher.addOrderAsync(signedOrder); - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - expect(orderState.isValid).to.be.false(); - const invalidOrderState = orderState as OrderStateInvalid; - expect(invalidOrderState.orderHash).to.be.equal(orderHash); - expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerBalance); - }); - orderWatcher.subscribe(callback); - await contractWrappers.etherToken.withdrawAsync( - contractAddresses.etherToken, - depositAmount, - makerAddress, - ); - })().catch(done); - }); - describe('erc721', () => { - let makerErc721AssetData: string; - let makerErc721TokenAddress: string; - const tokenId = new BigNumber(42); - [makerErc721TokenAddress] = tokenUtils.getDummyERC721TokenAddresses(); - makerErc721AssetData = assetDataUtils.encodeERC721AssetData(makerErc721TokenAddress, tokenId); - const fillableErc721Amount = new BigNumber(1); - it('should emit orderStateInvalid when maker allowance set to 0 for watched order', (done: DoneCallback) => { - (async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerErc721AssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableErc721Amount, - ); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - await orderWatcher.addOrderAsync(signedOrder); - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - expect(orderState.isValid).to.be.false(); - const invalidOrderState = orderState as OrderStateInvalid; - expect(invalidOrderState.orderHash).to.be.equal(orderHash); - expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance); - }); - orderWatcher.subscribe(callback); - await contractWrappers.erc721Token.setApprovalAsync( - makerErc721TokenAddress, - constants.NULL_ADDRESS, - tokenId, - ); - })().catch(done); - }); - it('should emit orderStateInvalid when maker allowance for all set to 0 for watched order', (done: DoneCallback) => { - (async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerErc721AssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableErc721Amount, - ); - await contractWrappers.erc721Token.setApprovalAsync( - makerErc721TokenAddress, - constants.NULL_ADDRESS, - tokenId, - ); - let isApproved = true; - await contractWrappers.erc721Token.setProxyApprovalForAllAsync( - makerErc721TokenAddress, - makerAddress, - isApproved, - ); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - await orderWatcher.addOrderAsync(signedOrder); - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - expect(orderState.isValid).to.be.false(); - const invalidOrderState = orderState as OrderStateInvalid; - expect(invalidOrderState.orderHash).to.be.equal(orderHash); - expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance); - }); - orderWatcher.subscribe(callback); - isApproved = false; - await contractWrappers.erc721Token.setProxyApprovalForAllAsync( - makerErc721TokenAddress, - makerAddress, - isApproved, - ); - })().catch(done); - }); - it('should emit orderStateInvalid when maker moves NFT backing watched order', (done: DoneCallback) => { - (async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerErc721AssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableErc721Amount, - ); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - await orderWatcher.addOrderAsync(signedOrder); - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - expect(orderState.isValid).to.be.false(); - const invalidOrderState = orderState as OrderStateInvalid; - expect(invalidOrderState.orderHash).to.be.equal(orderHash); - expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerBalance); - }); - orderWatcher.subscribe(callback); - await contractWrappers.erc721Token.transferFromAsync( - makerErc721TokenAddress, - coinbase, - makerAddress, - tokenId, - ); - })().catch(done); - }); - }); - describe('multiAsset', async () => { - const tokenId = new BigNumber(42); - const [makerErc721TokenAddress] = tokenUtils.getDummyERC721TokenAddresses(); - const makerErc721AssetData = assetDataUtils.encodeERC721AssetData(makerErc721TokenAddress, tokenId); - const fillableErc721Amount = new BigNumber(1); - const [makerErc20TokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); - const makerErc20AssetData = assetDataUtils.encodeERC20AssetData(makerErc20TokenAddress); - const fillableErc20Amount = new BigNumber(2); - const multiAssetAmounts = [fillableErc721Amount, fillableErc20Amount]; - const nestedAssetData = [makerErc721AssetData, makerErc20AssetData]; - const makerMultiAssetData = assetDataUtils.encodeMultiAssetData(multiAssetAmounts, nestedAssetData); - it('should emit orderStateInvalid when maker allowance of ERC721 token set to 0 for watched order', (done: DoneCallback) => { - (async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerMultiAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableErc721Amount, - ); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - await orderWatcher.addOrderAsync(signedOrder); - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - expect(orderState.isValid).to.be.false(); - const invalidOrderState = orderState as OrderStateInvalid; - expect(invalidOrderState.orderHash).to.be.equal(orderHash); - expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance); - }); - orderWatcher.subscribe(callback); - await contractWrappers.erc721Token.setApprovalAsync( - makerErc721TokenAddress, - constants.NULL_ADDRESS, - tokenId, - ); - })().catch(done); - }); - it('should emit orderStateInvalid when maker allowance for all of ERC721 token set to 0 for watched order', (done: DoneCallback) => { - (async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerMultiAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableErc721Amount, - ); - await contractWrappers.erc721Token.setApprovalAsync( - makerErc721TokenAddress, - constants.NULL_ADDRESS, - tokenId, - ); - let isApproved = true; - await contractWrappers.erc721Token.setProxyApprovalForAllAsync( - makerErc721TokenAddress, - makerAddress, - isApproved, - ); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - await orderWatcher.addOrderAsync(signedOrder); - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - expect(orderState.isValid).to.be.false(); - const invalidOrderState = orderState as OrderStateInvalid; - expect(invalidOrderState.orderHash).to.be.equal(orderHash); - expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance); - }); - orderWatcher.subscribe(callback); - isApproved = false; - await contractWrappers.erc721Token.setProxyApprovalForAllAsync( - makerErc721TokenAddress, - makerAddress, - isApproved, - ); - })().catch(done); - }); - it('should emit orderStateInvalid when maker moves ERC721 backing watched order', (done: DoneCallback) => { - (async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerMultiAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableErc721Amount, - ); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - await orderWatcher.addOrderAsync(signedOrder); - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - expect(orderState.isValid).to.be.false(); - const invalidOrderState = orderState as OrderStateInvalid; - expect(invalidOrderState.orderHash).to.be.equal(orderHash); - expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerBalance); - }); - orderWatcher.subscribe(callback); - await contractWrappers.erc721Token.transferFromAsync( - makerErc721TokenAddress, - coinbase, - makerAddress, - tokenId, - ); - })().catch(done); - }); - it('should emit orderStateInvalid when maker allowance of ERC20 token set to 0 for watched order', (done: DoneCallback) => { - (async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerMultiAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableErc721Amount, - ); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - await orderWatcher.addOrderAsync(signedOrder); - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - expect(orderState.isValid).to.be.false(); - const invalidOrderState = orderState as OrderStateInvalid; - expect(invalidOrderState.orderHash).to.be.equal(orderHash); - expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerAllowance); - }); - orderWatcher.subscribe(callback); - await contractWrappers.erc20Token.setProxyAllowanceAsync( - makerErc20TokenAddress, - makerAddress, - new BigNumber(0), - ); - })().catch(done); - }); - it('should not emit an orderState event when irrelevant ERC20 Transfer event received', (done: DoneCallback) => { - (async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerMultiAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - ); - await orderWatcher.addOrderAsync(signedOrder); - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((_orderState: OrderState) => { - throw new Error('OrderState callback fired for irrelevant order'); - }); - orderWatcher.subscribe(callback); - const notTheMaker = userAddresses[0]; - const anyRecipient = takerAddress; - const transferAmount = new BigNumber(2); - await contractWrappers.erc20Token.transferAsync( - makerTokenAddress, - notTheMaker, - anyRecipient, - transferAmount, - ); - setTimeout(() => { - done(); - }, TIMEOUT_MS); - })().catch(done); - }); - it('should emit orderStateInvalid when makerAddress moves ERC20 balance backing watched order', (done: DoneCallback) => { - (async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerMultiAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - ); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - await orderWatcher.addOrderAsync(signedOrder); - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - expect(orderState.isValid).to.be.false(); - const invalidOrderState = orderState as OrderStateInvalid; - expect(invalidOrderState.orderHash).to.be.equal(orderHash); - expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.InsufficientMakerBalance); - }); - orderWatcher.subscribe(callback); - const anyRecipient = takerAddress; - const makerBalance = await contractWrappers.erc20Token.getBalanceAsync( - makerTokenAddress, - makerAddress, - ); - await contractWrappers.erc20Token.transferAsync( - makerTokenAddress, - makerAddress, - anyRecipient, - makerBalance, - ); - })().catch(done); - }); - // TODO(abandeali1): The following test will fail until the MAP has been deployed and activated. - it.skip('should emit orderStateInvalid when watched order fully filled', (done: DoneCallback) => { - (async () => { - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerMultiAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - ); - const orderHash = orderHashUtils.getOrderHashHex(signedOrder); - await orderWatcher.addOrderAsync(signedOrder); - - const callback = callbackErrorReporter.reportNodeCallbackErrors(done)((orderState: OrderState) => { - expect(orderState.isValid).to.be.false(); - const invalidOrderState = orderState as OrderStateInvalid; - expect(invalidOrderState.orderHash).to.be.equal(orderHash); - expect(invalidOrderState.error).to.be.equal(ExchangeContractErrs.OrderRemainingFillAmountZero); - }); - orderWatcher.subscribe(callback); - - await contractWrappers.exchange.fillOrderAsync(signedOrder, fillableAmount, takerAddress); - })().catch(done); - }); - }); - }); -}); // tslint:disable:max-file-line-count diff --git a/packages/order-watcher/test/order_watcher_web_socket_server_test.ts b/packages/order-watcher/test/order_watcher_web_socket_server_test.ts deleted file mode 100644 index 36135f65c3..0000000000 --- a/packages/order-watcher/test/order_watcher_web_socket_server_test.ts +++ /dev/null @@ -1,312 +0,0 @@ -import { ContractAddresses } from '@0x/contract-addresses'; -import { ContractWrappers } from '@0x/contract-wrappers'; -import { tokenUtils } from '@0x/contract-wrappers/lib/test/utils/token_utils'; -import { BlockchainLifecycle } from '@0x/dev-utils'; -import { FillScenarios } from '@0x/fill-scenarios'; -import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; -import { ExchangeContractErrs, OrderStateInvalid, SignedOrder } from '@0x/types'; -import { BigNumber, logUtils } from '@0x/utils'; -import { Web3Wrapper } from '@0x/web3-wrapper'; -import * as chai from 'chai'; -import 'mocha'; -import * as WebSocket from 'websocket'; - -import { OrderWatcherWebSocketServer } from '../src/order_watcher/order_watcher_web_socket_server'; -import { AddOrderRequest, OrderWatcherMethod, RemoveOrderRequest } from '../src/types'; - -import { chaiSetup } from './utils/chai_setup'; -import { constants } from './utils/constants'; -import { migrateOnceAsync } from './utils/migrate'; -import { provider, web3Wrapper } from './utils/web3_wrapper'; - -chaiSetup.configure(); -const expect = chai.expect; -const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); - -interface WsMessage { - data: string; -} - -describe('OrderWatcherWebSocketServer', async () => { - let contractWrappers: ContractWrappers; - let wsServer: OrderWatcherWebSocketServer; - let wsClient: WebSocket.w3cwebsocket; - let wsClientTwo: WebSocket.w3cwebsocket; - let fillScenarios: FillScenarios; - let userAddresses: string[]; - let makerAssetData: string; - let takerAssetData: string; - let makerTokenAddress: string; - let takerTokenAddress: string; - let makerAddress: string; - let takerAddress: string; - let zrxTokenAddress: string; - let signedOrder: SignedOrder; - let orderHash: string; - let addOrderPayload: AddOrderRequest; - let removeOrderPayload: RemoveOrderRequest; - let networkId: number; - let contractAddresses: ContractAddresses; - const decimals = constants.ZRX_DECIMALS; - const fillableAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(5), decimals); - - before(async () => { - // Set up constants - contractAddresses = await migrateOnceAsync(); - await blockchainLifecycle.startAsync(); - networkId = constants.TESTRPC_NETWORK_ID; - const config = { - networkId, - contractAddresses, - }; - contractWrappers = new ContractWrappers(provider, config); - userAddresses = await web3Wrapper.getAvailableAddressesAsync(); - zrxTokenAddress = contractAddresses.zrxToken; - [makerAddress, takerAddress] = userAddresses; - [makerTokenAddress, takerTokenAddress] = tokenUtils.getDummyERC20TokenAddresses(); - [makerAssetData, takerAssetData] = [ - assetDataUtils.encodeERC20AssetData(makerTokenAddress), - assetDataUtils.encodeERC20AssetData(takerTokenAddress), - ]; - fillScenarios = new FillScenarios( - provider, - userAddresses, - zrxTokenAddress, - contractAddresses.exchange, - contractAddresses.erc20Proxy, - contractAddresses.erc721Proxy, - ); - signedOrder = await fillScenarios.createFillableSignedOrderAsync( - makerAssetData, - takerAssetData, - makerAddress, - takerAddress, - fillableAmount, - ); - orderHash = orderHashUtils.getOrderHashHex(signedOrder); - addOrderPayload = { - id: 1, - jsonrpc: '2.0', - method: OrderWatcherMethod.AddOrder, - params: { signedOrder }, - }; - removeOrderPayload = { - id: 1, - jsonrpc: '2.0', - method: OrderWatcherMethod.RemoveOrder, - params: { orderHash }, - }; - }); - after(async () => { - await blockchainLifecycle.revertAsync(); - }); - beforeEach(async () => { - // Prepare OrderWatcher WebSocket server - const orderWatcherConfig = { - isVerbose: true, - }; - wsServer = new OrderWatcherWebSocketServer(provider, networkId, contractAddresses, orderWatcherConfig); - wsServer.start(); - await blockchainLifecycle.startAsync(); - wsClient = new WebSocket.w3cwebsocket('ws://127.0.0.1:8080/'); - logUtils.log(`${new Date()} [Client] Connected.`); - }); - afterEach(async () => { - wsClient.close(); - await blockchainLifecycle.revertAsync(); - wsServer.stop(); - logUtils.log(`${new Date()} [Client] Closed.`); - }); - - it('responds to getStats requests correctly', (done: any) => { - const payload = { - id: 1, - jsonrpc: '2.0', - method: 'GET_STATS', - }; - wsClient.onopen = () => wsClient.send(JSON.stringify(payload)); - wsClient.onmessage = (msg: any) => { - const responseData = JSON.parse(msg.data); - expect(responseData.id).to.be.eq(1); - expect(responseData.jsonrpc).to.be.eq('2.0'); - expect(responseData.method).to.be.eq('GET_STATS'); - expect(responseData.result.orderCount).to.be.eq(0); - done(); - }; - }); - - it('throws an error when an invalid method is attempted', async () => { - const invalidMethodPayload = { - id: 1, - jsonrpc: '2.0', - method: 'BAD_METHOD', - }; - wsClient.onopen = () => wsClient.send(JSON.stringify(invalidMethodPayload)); - const errorMsg = await onMessageAsync(wsClient, null); - const errorData = JSON.parse(errorMsg.data); - // tslint:disable-next-line:no-unused-expression - expect(errorData.id).to.be.null; - // tslint:disable-next-line:no-unused-expression - expect(errorData.method).to.be.null; - expect(errorData.jsonrpc).to.be.eq('2.0'); - expect(errorData.error).to.match(/^Error: Expected request to conform to schema/); - }); - - it('throws an error when jsonrpc field missing from request', async () => { - const noJsonRpcPayload = { - id: 1, - method: 'GET_STATS', - }; - wsClient.onopen = () => wsClient.send(JSON.stringify(noJsonRpcPayload)); - const errorMsg = await onMessageAsync(wsClient, null); - const errorData = JSON.parse(errorMsg.data); - // tslint:disable-next-line:no-unused-expression - expect(errorData.method).to.be.null; - expect(errorData.jsonrpc).to.be.eq('2.0'); - expect(errorData.error).to.match(/^Error: Expected request to conform to schema/); - }); - - it('throws an error when we try to add an order without a signedOrder', async () => { - const noSignedOrderAddOrderPayload = { - id: 1, - jsonrpc: '2.0', - method: 'ADD_ORDER', - orderHash: '0x7337e2f2a9aa2ed6afe26edc2df7ad79c3ffa9cf9b81a964f707ea63f5272355', - }; - wsClient.onopen = () => wsClient.send(JSON.stringify(noSignedOrderAddOrderPayload)); - const errorMsg = await onMessageAsync(wsClient, null); - const errorData = JSON.parse(errorMsg.data); - // tslint:disable-next-line:no-unused-expression - expect(errorData.id).to.be.null; - // tslint:disable-next-line:no-unused-expression - expect(errorData.method).to.be.null; - expect(errorData.jsonrpc).to.be.eq('2.0'); - expect(errorData.error).to.match(/^Error: Expected request to conform to schema/); - }); - - it('throws an error when we try to add a bad signedOrder', async () => { - const invalidAddOrderPayload = { - id: 1, - jsonrpc: '2.0', - method: 'ADD_ORDER', - signedOrder: { - makerAddress: '0x0', - }, - }; - wsClient.onopen = () => wsClient.send(JSON.stringify(invalidAddOrderPayload)); - const errorMsg = await onMessageAsync(wsClient, null); - const errorData = JSON.parse(errorMsg.data); - // tslint:disable-next-line:no-unused-expression - expect(errorData.id).to.be.null; - // tslint:disable-next-line:no-unused-expression - expect(errorData.method).to.be.null; - expect(errorData.error).to.match(/^Error: Expected request to conform to schema/); - }); - - it('executes addOrder and removeOrder requests correctly', async () => { - wsClient.onopen = () => wsClient.send(JSON.stringify(addOrderPayload)); - const addOrderMsg = await onMessageAsync(wsClient, OrderWatcherMethod.AddOrder); - const addOrderData = JSON.parse(addOrderMsg.data); - expect(addOrderData.method).to.be.eq('ADD_ORDER'); - expect((wsServer as any)._orderWatcher._orderByOrderHash).to.deep.include({ - [orderHash]: signedOrder, - }); - - const clientOnMessagePromise = onMessageAsync(wsClient, OrderWatcherMethod.RemoveOrder); - wsClient.send(JSON.stringify(removeOrderPayload)); - const removeOrderMsg = await clientOnMessagePromise; - const removeOrderData = JSON.parse(removeOrderMsg.data); - expect(removeOrderData.method).to.be.eq('REMOVE_ORDER'); - expect((wsServer as any)._orderWatcher._orderByOrderHash).to.not.deep.include({ - [orderHash]: signedOrder, - }); - }); - - it('broadcasts orderStateInvalid message when makerAddress allowance set to 0 for watched order', async () => { - // Add the regular order - wsClient.onopen = () => wsClient.send(JSON.stringify(addOrderPayload)); - - // We register the onMessage callback before calling `setProxyAllowanceAsync` which we - // expect will cause a message to be emitted. We do now "await" here, since we want to - // check for messages _after_ calling `setProxyAllowanceAsync` - const clientOnMessagePromise = onMessageAsync(wsClient, OrderWatcherMethod.Update); - - // Set the allowance to 0 - await contractWrappers.erc20Token.setProxyAllowanceAsync(makerTokenAddress, makerAddress, new BigNumber(0)); - - // We now await the `onMessage` promise to check for the message - const orderWatcherUpdateMsg = await clientOnMessagePromise; - const orderWatcherUpdateData = JSON.parse(orderWatcherUpdateMsg.data); - expect(orderWatcherUpdateData.method).to.be.eq('UPDATE'); - const invalidOrderState = orderWatcherUpdateData.result as OrderStateInvalid; - expect(invalidOrderState.isValid).to.be.false(); - expect(invalidOrderState.orderHash).to.be.eq(orderHash); - expect(invalidOrderState.error).to.be.eq(ExchangeContractErrs.InsufficientMakerAllowance); - }); - - it('broadcasts to multiple clients when an order backing ZRX allowance changes', async () => { - // Prepare order - const makerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(2), decimals); - const takerFee = Web3Wrapper.toBaseUnitAmount(new BigNumber(0), decimals); - const nonZeroMakerFeeSignedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( - makerAssetData, - takerAssetData, - makerFee, - takerFee, - makerAddress, - takerAddress, - fillableAmount, - takerAddress, - ); - const nonZeroMakerFeeOrderPayload = { - id: 1, - jsonrpc: '2.0', - method: 'ADD_ORDER', - params: { - signedOrder: nonZeroMakerFeeSignedOrder, - }, - }; - - // Set up a second client and have it add the order - wsClientTwo = new WebSocket.w3cwebsocket('ws://127.0.0.1:8080/'); - logUtils.log(`${new Date()} [Client] Connected.`); - wsClientTwo.onopen = () => wsClientTwo.send(JSON.stringify(nonZeroMakerFeeOrderPayload)); - - // Setup the onMessage callbacks, but don't await them yet - const clientOneOnMessagePromise = onMessageAsync(wsClient, OrderWatcherMethod.Update); - const clientTwoOnMessagePromise = onMessageAsync(wsClientTwo, OrderWatcherMethod.Update); - - // Change the allowance - await contractWrappers.erc20Token.setProxyAllowanceAsync(zrxTokenAddress, makerAddress, new BigNumber(0)); - - // Check that both clients receive the emitted event by awaiting the onMessageAsync promises - let updateMsg = await clientOneOnMessagePromise; - let updateData = JSON.parse(updateMsg.data); - let orderState = updateData.result as OrderStateInvalid; - expect(orderState.isValid).to.be.false(); - expect(orderState.error).to.be.eq('INSUFFICIENT_MAKER_FEE_ALLOWANCE'); - - updateMsg = await clientTwoOnMessagePromise; - updateData = JSON.parse(updateMsg.data); - orderState = updateData.result as OrderStateInvalid; - expect(orderState.isValid).to.be.false(); - expect(orderState.error).to.be.eq('INSUFFICIENT_MAKER_FEE_ALLOWANCE'); - - wsClientTwo.close(); - logUtils.log(`${new Date()} [Client] Closed.`); - }); -}); - -// HACK: createFillableSignedOrderAsync is Promise-based, which forces us -// to use Promises instead of the done() callbacks for tests. -// onmessage callback must thus be wrapped as a Promise. -async function onMessageAsync(client: WebSocket.w3cwebsocket, method: string | null): Promise { - return new Promise(resolve => { - client.onmessage = (msg: WsMessage) => { - const data = JSON.parse(msg.data); - if (data.method === method) { - resolve(msg); - } - }; - }); -} diff --git a/packages/order-watcher/test/utils/chai_setup.ts b/packages/order-watcher/test/utils/chai_setup.ts deleted file mode 100644 index 1a87330932..0000000000 --- a/packages/order-watcher/test/utils/chai_setup.ts +++ /dev/null @@ -1,13 +0,0 @@ -import * as chai from 'chai'; -import chaiAsPromised = require('chai-as-promised'); -import ChaiBigNumber = require('chai-bignumber'); -import * as dirtyChai from 'dirty-chai'; - -export const chaiSetup = { - configure(): void { - chai.config.includeStack = true; - chai.use(ChaiBigNumber()); - chai.use(dirtyChai); - chai.use(chaiAsPromised); - }, -}; diff --git a/packages/order-watcher/test/utils/constants.ts b/packages/order-watcher/test/utils/constants.ts deleted file mode 100644 index 78037647cb..0000000000 --- a/packages/order-watcher/test/utils/constants.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const constants = { - NULL_ADDRESS: '0x0000000000000000000000000000000000000000', - TESTRPC_NETWORK_ID: 50, - ZRX_DECIMALS: 18, -}; diff --git a/packages/order-watcher/test/utils/migrate.ts b/packages/order-watcher/test/utils/migrate.ts deleted file mode 100644 index 665ce0faaa..0000000000 --- a/packages/order-watcher/test/utils/migrate.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ContractAddresses } from '@0x/contract-addresses'; -import { devConstants } from '@0x/dev-utils'; -import { runMigrationsOnceAsync } from '@0x/migrations'; - -import { provider } from './web3_wrapper'; - -/** - * Configures and runs the migrations exactly once. Any subsequent times this is - * called, it returns the cached addresses. - * @returns The addresses of contracts that were deployed during the migrations. - */ -export async function migrateOnceAsync(): Promise { - const txDefaults = { - gas: devConstants.GAS_LIMIT, - from: devConstants.TESTRPC_FIRST_ADDRESS, - }; - return runMigrationsOnceAsync(provider, txDefaults); -} diff --git a/packages/order-watcher/test/utils/web3_wrapper.ts b/packages/order-watcher/test/utils/web3_wrapper.ts deleted file mode 100644 index 32f8543267..0000000000 --- a/packages/order-watcher/test/utils/web3_wrapper.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { web3Factory } from '@0x/dev-utils'; -import { Web3ProviderEngine } from '@0x/subproviders'; -import { Web3Wrapper } from '@0x/web3-wrapper'; - -const provider: Web3ProviderEngine = web3Factory.getRpcProvider({ shouldUseInProcessGanache: true }); -const web3Wrapper = new Web3Wrapper(provider); - -export { provider, web3Wrapper }; diff --git a/packages/order-watcher/tsconfig.json b/packages/order-watcher/tsconfig.json deleted file mode 100644 index 2ee711adcc..0000000000 --- a/packages/order-watcher/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../../tsconfig", - "compilerOptions": { - "outDir": "lib", - "rootDir": "." - }, - "include": ["./src/**/*", "./test/**/*"] -} diff --git a/packages/order-watcher/tslint.json b/packages/order-watcher/tslint.json deleted file mode 100644 index 4ade3b924a..0000000000 --- a/packages/order-watcher/tslint.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "rules": { - "prefer-readonly": true - }, - "extends": ["@0x/tslint-config"] -} diff --git a/packages/python-contract-wrappers/package.json b/packages/python-contract-wrappers/package.json index 0aaef82252..c2540dee19 100644 --- a/packages/python-contract-wrappers/package.json +++ b/packages/python-contract-wrappers/package.json @@ -1,6 +1,6 @@ { "name": "@0x/python-contract-wrappers", - "version": "1.0.2", + "version": "1.0.3", "engines": { "node": ">=6.12" }, @@ -13,7 +13,7 @@ "clean": "shx rm -rf generated" }, "config": { - "abis": "../contract-artifacts/artifacts/{Exchange,ERC20Token}.json" + "abis": "../contract-artifacts/artifacts/{AssetProxyOwner,Coordinator,CoordinatorRegistry,DevUtils,DummyERC20Token,DummyERC721Token,DutchAuction,ERC20Proxy,ERC20Token,ERC721Proxy,ERC721Token,EthBalanceChecker,Exchange,Forwarder,IAssetProxy,IValidator,IWallet,MultiAssetProxy,OrderValidator,WETH9,ZRXToken}.json" }, "repository": { "type": "git", @@ -25,7 +25,7 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/python-contract-wrappers/README.md", "devDependencies": { - "@0x/abi-gen": "^2.1.1", + "@0x/abi-gen": "^4.1.0", "shx": "^0.2.2" }, "publishConfig": { diff --git a/packages/react-docs/.npmignore b/packages/react-docs/.npmignore deleted file mode 100644 index ea588d4859..0000000000 --- a/packages/react-docs/.npmignore +++ /dev/null @@ -1,9 +0,0 @@ -# Blacklist all files -.* -* -# Whitelist lib -!lib/**/* -# Blacklist tests and publish scripts -/lib/test/* -/lib/monorepo_scripts/ -# Package specific ignore diff --git a/packages/react-docs/CHANGELOG.json b/packages/react-docs/CHANGELOG.json deleted file mode 100644 index abd4a84860..0000000000 --- a/packages/react-docs/CHANGELOG.json +++ /dev/null @@ -1,534 +0,0 @@ -[ - { - "timestamp": 1563047529, - "version": "2.0.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563006338, - "version": "2.0.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1558712885, - "version": "2.0.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557507213, - "version": "2.0.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.0.10", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1554997931 - }, - { - "timestamp": 1553183790, - "version": "2.0.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1553091633, - "version": "2.0.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551479279, - "version": "2.0.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551220833, - "version": "2.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551130135, - "version": "2.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1549733923, - "version": "2.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1549547375 - }, - { - "timestamp": 1549504360, - "version": "2.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1549452781, - "version": "2.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.0.0", - "changes": [ - { - "note": "Upgrade the bignumber.js to v8.0.2", - "pr": 1517 - } - ], - "timestamp": 1549373905 - }, - { - "timestamp": 1547561734, - "version": "1.0.25", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1547225310, - "version": "1.0.24", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1547040760, - "version": "1.0.23", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.0.22", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1544739608 - }, - { - "version": "1.0.21", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1544570656 - }, - { - "timestamp": 1543401373, - "version": "1.0.20", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1542821676, - "version": "1.0.19", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1542208198, - "version": "1.0.18", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1542134075, - "version": "1.0.17", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1542028948, - "version": "1.0.16", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.0.15", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1541740904 - }, - { - "timestamp": 1539871071, - "version": "1.0.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.0.13", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1538693146 - }, - { - "timestamp": 1538157789, - "version": "1.0.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1537907159, - "version": "1.0.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1537875740, - "version": "1.0.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1537541580, - "version": "1.0.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1536142250, - "version": "1.0.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1535377027, - "version": "1.0.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1535133899, - "version": "1.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1534210131, - "version": "1.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1532619515, - "version": "1.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1532614997, - "version": "1.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1532605697, - "version": "1.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1532357734, - "version": "1.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1532043000, - "version": "1.0.0", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1531919263, - "version": "0.0.17", - "changes": [ - { - "note": "Nest MD files under versions so that you can update them for future versions", - "pr": 844 - } - ] - }, - { - "timestamp": 1531919263, - "version": "0.0.16", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1531149657, - "version": "0.0.15", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1529397769, - "version": "0.0.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "0.0.13", - "changes": [ - { - "note": "Incorrect publish that was unpublished" - } - ], - "timestamp": 1527810075 - }, - { - "timestamp": 1527009133, - "version": "0.0.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1525477860, - "version": "0.0.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1525466747, - "version": "0.0.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1525428773, - "version": "0.0.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "0.0.8", - "changes": [ - { - "note": "Added support for rendering default param values", - "pr": 519 - }, - { - "note": "Added support for rendering nested function types within interface types", - "pr": 519 - }, - { - "note": "Improve type comment rendering", - "pr": 535 - } - ], - "timestamp": 1524044013 - }, - { - "timestamp": 1523462196, - "version": "0.0.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1522673609, - "version": "0.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "0.0.5", - "changes": [ - { - "note": "Handle `reflection` type rendering so that anonymous function type declarations render properly", - "pr": 465 - }, - { - "note": "Rename `MethodSignature` to `Signature` and change it's props so that it can be used to render method and function signatures.", - "pr": 465 - }, - { - "note": "Rename `MethodBlock` to `SignatureBlock` since it is not used to render method and function signature blocks.", - "pr": 465 - }, - { - "note": "Add support for documenting exported functions.", - "pr": 465 - } - ], - "timestamp": 1522658513 - }, - { - "version": "0.0.3", - "changes": [ - { - "note": "Move TS typings from devDependencies to dependencies since they are needed by the package user." - } - ], - "timestamp": 1521298800 - }, - { - "version": "0.0.2", - "changes": [ - { - "note": "Move example out into a separate sub-package" - }, - { - "note": "Consolidate all `console.log` calls into `logUtils` in the `@0xproject/utils` package", - "pr": 452 - } - ], - "timestamp": 1521298800 - } -] diff --git a/packages/react-docs/CHANGELOG.md b/packages/react-docs/CHANGELOG.md deleted file mode 100644 index 94654022c7..0000000000 --- a/packages/react-docs/CHANGELOG.md +++ /dev/null @@ -1,236 +0,0 @@ - - -CHANGELOG - -## v2.0.14 - _July 13, 2019_ - - * Dependencies updated - -## v2.0.13 - _July 13, 2019_ - - * Dependencies updated - -## v2.0.12 - _May 24, 2019_ - - * Dependencies updated - -## v2.0.11 - _May 10, 2019_ - - * Dependencies updated - -## v2.0.10 - _April 11, 2019_ - - * Dependencies updated - -## v2.0.9 - _March 21, 2019_ - - * Dependencies updated - -## v2.0.8 - _March 20, 2019_ - - * Dependencies updated - -## v2.0.7 - _March 1, 2019_ - - * Dependencies updated - -## v2.0.6 - _February 26, 2019_ - - * Dependencies updated - -## v2.0.5 - _February 25, 2019_ - - * Dependencies updated - -## v2.0.4 - _February 9, 2019_ - - * Dependencies updated - -## v2.0.3 - _February 7, 2019_ - - * Dependencies updated - -## v2.0.2 - _February 7, 2019_ - - * Dependencies updated - -## v2.0.1 - _February 6, 2019_ - - * Dependencies updated - -## v2.0.0 - _February 5, 2019_ - - * Upgrade the bignumber.js to v8.0.2 (#1517) - -## v1.0.25 - _January 15, 2019_ - - * Dependencies updated - -## v1.0.24 - _January 11, 2019_ - - * Dependencies updated - -## v1.0.23 - _January 9, 2019_ - - * Dependencies updated - -## v1.0.22 - _December 13, 2018_ - - * Dependencies updated - -## v1.0.21 - _December 11, 2018_ - - * Dependencies updated - -## v1.0.20 - _November 28, 2018_ - - * Dependencies updated - -## v1.0.19 - _November 21, 2018_ - - * Dependencies updated - -## v1.0.18 - _November 14, 2018_ - - * Dependencies updated - -## v1.0.17 - _November 13, 2018_ - - * Dependencies updated - -## v1.0.16 - _November 12, 2018_ - - * Dependencies updated - -## v1.0.15 - _November 9, 2018_ - - * Dependencies updated - -## v1.0.14 - _October 18, 2018_ - - * Dependencies updated - -## v1.0.13 - _October 4, 2018_ - - * Dependencies updated - -## v1.0.12 - _September 28, 2018_ - - * Dependencies updated - -## v1.0.11 - _September 25, 2018_ - - * Dependencies updated - -## v1.0.10 - _September 25, 2018_ - - * Dependencies updated - -## v1.0.9 - _September 21, 2018_ - - * Dependencies updated - -## v1.0.8 - _September 5, 2018_ - - * Dependencies updated - -## v1.0.7 - _August 27, 2018_ - - * Dependencies updated - -## v1.0.6 - _August 24, 2018_ - - * Dependencies updated - -## v1.0.5 - _August 14, 2018_ - - * Dependencies updated - -## v1.0.4 - _July 26, 2018_ - - * Dependencies updated - -## v1.0.3 - _July 26, 2018_ - - * Dependencies updated - -## v1.0.2 - _July 26, 2018_ - - * Dependencies updated - -## v1.0.1 - _July 23, 2018_ - - * Dependencies updated - -## v1.0.0 - _July 19, 2018_ - - * Dependencies updated - -## v0.0.17 - _July 18, 2018_ - - * Nest MD files under versions so that you can update them for future versions (#844) - -## v0.0.16 - _July 18, 2018_ - - * Dependencies updated - -## v0.0.15 - _July 9, 2018_ - - * Dependencies updated - -## v0.0.14 - _June 19, 2018_ - - * Dependencies updated - -## v0.0.13 - _May 31, 2018_ - - * Incorrect publish that was unpublished - -## v0.0.12 - _May 22, 2018_ - - * Dependencies updated - -## v0.0.11 - _May 4, 2018_ - - * Dependencies updated - -## v0.0.10 - _May 4, 2018_ - - * Dependencies updated - -## v0.0.9 - _May 4, 2018_ - - * Dependencies updated - -## v0.0.8 - _April 18, 2018_ - - * Added support for rendering default param values (#519) - * Added support for rendering nested function types within interface types (#519) - * Improve type comment rendering (#535) - -## v0.0.7 - _April 11, 2018_ - - * Dependencies updated - -## v0.0.6 - _April 2, 2018_ - - * Dependencies updated - -## v0.0.5 - _April 2, 2018_ - - * Handle `reflection` type rendering so that anonymous function type declarations render properly (#465) - * Rename `MethodSignature` to `Signature` and change it's props so that it can be used to render method and function signatures. (#465) - * Rename `MethodBlock` to `SignatureBlock` since it is not used to render method and function signature blocks. (#465) - * Add support for documenting exported functions. (#465) - -## v0.0.3 - _March 17, 2018_ - - * Move TS typings from devDependencies to dependencies since they are needed by the package user. - -## v0.0.2 - _March 17, 2018_ - - * Move example out into a separate sub-package - * Consolidate all `console.log` calls into `logUtils` in the `@0xproject/utils` package (#452) diff --git a/packages/react-docs/README.md b/packages/react-docs/README.md deleted file mode 100644 index 7b1f4f80ac..0000000000 --- a/packages/react-docs/README.md +++ /dev/null @@ -1,96 +0,0 @@ -## @0x/react-docs - -#### WARNING: Alpha software. Expect things to break when trying to use. - -A full-page React component for rendering beautiful documentation for Solidity and Typescript code generated with [TypeDoc](http://typedoc.org/) or [sol-doc](https://github.com/0xProject/0x-monorepo/tree/development/packages/sol-doc). - -
- -
react-docs generating 0x's smart contract docs
-
- -#### Features - -- Mobile optimized -- Reads Javadoc-style comments in your code to generate class/method/argument/return/type comments. -- Syntax highlighting support for TypeScript & Solidity -- Type declaration linking -- Type declaration popovers to avoid clicking through to the definition -- Section/method/type anchors for easily pointing others to a specific part of your docs. -- Version picker -- Customizable sidebar header -- Supports custom markdown sections so you can easily add an intro or installation instructions. - -## Installation - -```bash -yarn add @0x/react-docs -``` - -## Usage - -This package exposes both a single `Documentation` react component that will render a docs page, as well as all of it's sub-components in case someone wants to build their own layout. - -Currently this package still has some external dependencies outside of the `Documentation` component, so please start your project off by copying the [react-docs-example](https://github.com/0xProject/0x-monorepo/tree/development/packages/react-docs-example) directory and modifying it there. If you need changes in the [react-docs](https://github.com/0xProject/0x-monorepo/tree/development/packages/react-docs) package, fork the 0x monorepo, make the required changes and submit a PR. Until we merge it, you can have your project depend on your own custom fork. - -If your project is in [TypeScript](https://www.typescriptlang.org/), add the following to your `tsconfig.json`: - -```json -"compilerOptions": { - "typeRoots": ["node_modules/@0x/typescript-typings/types", "node_modules/@types"], -} -``` - -## Future improvements - -Feel free to contribute to these improvements! - -- Allow user to pass in styling for all major elements similar to [Material-UI](http://www.material-ui.com/). -- Allow user to define an alternative font and have it change everywhere. -- Add source links to Solidity docs (currently unsupported by solc, which underlies sol-doc). - -## Contributing - -We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository. - -Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. - -### Install dependencies - -If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: - -```bash -yarn config set workspaces-experimental true -``` - -Then install dependencies - -```bash -yarn install -``` - -### Build - -To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory: - -```bash -PKG=@0x/react-docs yarn build -``` - -Or continuously rebuild on change: - -```bash -PKG=@0x/react-docs yarn watch -``` - -### Clean - -```bash -yarn clean -``` - -### Lint - -```bash -yarn lint -``` diff --git a/packages/react-docs/package.json b/packages/react-docs/package.json deleted file mode 100644 index eb5bd4d0d8..0000000000 --- a/packages/react-docs/package.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "name": "@0x/react-docs", - "version": "2.0.14", - "engines": { - "node": ">=6.12" - }, - "description": "React documentation component for rendering TypeDoc & sol-doc generated JSON", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "scripts": { - "lint": "tslint --format stylish --project .", - "fix": "tslint --fix --format stylish --project .", - "build": "tsc -b", - "build:ci": "yarn build", - "clean": "shx rm -rf lib" - }, - "author": "Fabio Berger", - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/0x-monorepo/issues" - }, - "homepage": "https://github.com/0xProject/0x-monorepo/packages/react-docs/README.md", - "repository": { - "type": "git", - "url": "https://github.com/0xProject/0x-monorepo.git" - }, - "devDependencies": { - "@0x/dev-utils": "^2.2.4", - "@0x/tslint-config": "^3.0.1", - "@types/compare-versions": "^3.0.0", - "@types/styled-components": "4.1.1", - "make-promises-safe": "^1.1.0", - "shx": "^0.2.2", - "tslint": "5.11.0", - "typescript": "3.0.1" - }, - "dependencies": { - "@0x/react-shared": "^2.0.14", - "@0x/types": "^2.4.0", - "@0x/utils": "^4.4.0", - "@types/lodash": "4.14.104", - "@types/material-ui": "^0.20.0", - "@types/node": "*", - "@types/react": "*", - "@types/react-dom": "*", - "@types/react-scroll": "1.5.3", - "basscss": "^8.0.3", - "compare-versions": "^3.0.1", - "lodash": "^4.17.11", - "material-ui": "^0.20.0", - "react": "^16.5.2", - "react-dom": "^16.5.2", - "react-markdown": "^3.2.2", - "react-scroll": "0xproject/react-scroll#pr-330-and-replace-state", - "react-tooltip": "^3.2.7", - "semver": "5.5.0", - "styled-components": "^4.1.1" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/packages/react-docs/src/globals.d.ts b/packages/react-docs/src/globals.d.ts deleted file mode 100644 index 94e63a32de..0000000000 --- a/packages/react-docs/src/globals.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module '*.json' { - const json: any; - /* tslint:disable */ - export default json; - /* tslint:enable */ -} diff --git a/packages/react-docs/src/index.ts b/packages/react-docs/src/index.ts deleted file mode 100644 index a5ed788b15..0000000000 --- a/packages/react-docs/src/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -export { DocAgnosticFormat, GeneratedDocJson } from '@0x/types'; - -// Exported to give users of this library added flexibility if they want to build -// a docs page from scratch using the individual components. -export { Badge } from './components/badge'; -export { Comment } from './components/comment'; -export { CustomEnum } from './components/custom_enum'; -export { DocReference } from './components/doc_reference'; -export { Enum } from './components/enum'; -export { EventDefinition } from './components/event_definition'; -export { Interface } from './components/interface'; -export { SignatureBlock } from './components/signature_block'; -export { Signature } from './components/signature'; -export { SourceLink } from './components/source_link'; -export { TypeDefinition } from './components/type_definition'; -export { Type } from './components/type'; -export { TypeDocUtils } from './utils/typedoc_utils'; - -export { DocsInfo } from './docs_info'; - -export { DocsInfoConfig, DocsMenu, SupportedDocJson } from './types'; - -export { constants } from './utils/constants'; diff --git a/packages/react-docs/src/types.ts b/packages/react-docs/src/types.ts deleted file mode 100644 index 1534485132..0000000000 --- a/packages/react-docs/src/types.ts +++ /dev/null @@ -1,66 +0,0 @@ -export interface SectionNameToMarkdownByVersion { - [version: string]: { [sectionName: string]: string }; -} - -export interface DocsInfoConfig { - id: string; - packageName: string; - type: SupportedDocJson; - displayName: string; - packageUrl: string; - markdownMenu: DocsMenu; - markdownSections: SectionsMap; - sectionNameToMarkdownByVersion: SectionNameToMarkdownByVersion; - contractsByVersionByNetworkId?: ContractsByVersionByNetworkId; -} - -export interface DocsMenu { - [sectionName: string]: string[]; -} - -export interface SectionsMap { - [sectionName: string]: string; -} - -// Exception: We don't make the values uppercase because these KindString's need to -// match up those returned by TypeDoc -export enum KindString { - Constructor = 'Constructor', - Property = 'Property', - Method = 'Method', - Interface = 'Interface', - TypeAlias = 'Type alias', - ObjectLiteral = 'Object literal', - Variable = 'Variable', - Function = 'Function', - Enumeration = 'Enumeration', - Class = 'Class', -} - -export enum SupportedDocJson { - SolDoc = 'SOL_DOC', - TypeDoc = 'TYPEDOC', -} - -export interface ContractsByVersionByNetworkId { - [version: string]: { - [networkName: string]: { - [contractName: string]: string; - }; - }; -} - -export interface AddressByContractName { - [contractName: string]: string; -} - -export interface EnumValue { - name: string; - defaultValue?: string; -} - -export enum AbiTypes { - Constructor = 'constructor', - Function = 'function', - Event = 'event', -} diff --git a/packages/react-docs/src/utils/constants.ts b/packages/react-docs/src/utils/constants.ts deleted file mode 100644 index b5b6cc00d0..0000000000 --- a/packages/react-docs/src/utils/constants.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { SupportedDocJson } from '../types'; - -export const constants = { - TYPES_SECTION_NAME: 'types', - EXTERNAL_EXPORTS_SECTION_NAME: 'external exports', - TYPE_TO_SYNTAX: { - [SupportedDocJson.SolDoc]: 'solidity', - [SupportedDocJson.TypeDoc]: 'typescript', - } as { [supportedDocType: string]: string }, -}; diff --git a/packages/react-docs/tsconfig.json b/packages/react-docs/tsconfig.json deleted file mode 100644 index 76e2cd0278..0000000000 --- a/packages/react-docs/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "../../tsconfig", - "compilerOptions": { - "outDir": "lib", - "rootDir": "src", - "jsx": "react", - "baseUrl": ".", - "strictNullChecks": false, - "paths": { - "*": ["node_modules/@types/*", "*"] - } - }, - "include": ["./src/**/*"] -} diff --git a/packages/react-docs/tslint.json b/packages/react-docs/tslint.json deleted file mode 100644 index c3f6d9cae7..0000000000 --- a/packages/react-docs/tslint.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": ["@0x/tslint-config"], - "rules": { - "no-object-literal-type-assertion": false, - "completed-docs": false, - "prefer-function-over-method": false, - "custom-no-magic-numbers": false - } -} diff --git a/packages/react-shared/.npmignore b/packages/react-shared/.npmignore deleted file mode 100644 index ea588d4859..0000000000 --- a/packages/react-shared/.npmignore +++ /dev/null @@ -1,9 +0,0 @@ -# Blacklist all files -.* -* -# Whitelist lib -!lib/**/* -# Blacklist tests and publish scripts -/lib/test/* -/lib/monorepo_scripts/ -# Package specific ignore diff --git a/packages/react-shared/CHANGELOG.json b/packages/react-shared/CHANGELOG.json deleted file mode 100644 index fb22d4a286..0000000000 --- a/packages/react-shared/CHANGELOG.json +++ /dev/null @@ -1,497 +0,0 @@ -[ - { - "timestamp": 1563047529, - "version": "2.0.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1563006338, - "version": "2.0.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1558712885, - "version": "2.0.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1557507213, - "version": "2.0.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.0.10", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1554997931 - }, - { - "timestamp": 1553183790, - "version": "2.0.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1553091633, - "version": "2.0.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551479279, - "version": "2.0.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551220833, - "version": "2.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1551130135, - "version": "2.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1549733923, - "version": "2.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1549547375 - }, - { - "timestamp": 1549504360, - "version": "2.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1549452781, - "version": "2.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "2.0.0", - "changes": [ - { - "note": "Upgrade the bignumber.js to v8.0.2", - "pr": 1517 - } - ], - "timestamp": 1549373905 - }, - { - "timestamp": 1547561734, - "version": "1.1.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1547225310, - "version": "1.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.1.0", - "changes": [ - { - "note": "Change implementation to use react-router-dom NavLink instead of Link. Expose `activeStyle` prop.", - "pr": 1448 - } - ], - "timestamp": 1547040760 - }, - { - "version": "1.0.25", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1544739608 - }, - { - "version": "1.0.24", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1544570656 - }, - { - "timestamp": 1543401373, - "version": "1.0.23", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1542821676, - "version": "1.0.22", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1542208198, - "version": "1.0.21", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1542134075, - "version": "1.0.20", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1542028948, - "version": "1.0.19", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "1.0.18", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1541740904 - }, - { - "version": "1.0.17", - "changes": [ - { - "note": "Dependencies updated" - } - ], - "timestamp": 1539871071 - }, - { - "timestamp": 1538693146, - "version": "1.0.16", - "changes": [ - { - "note": "Unpublished package" - } - ] - }, - { - "timestamp": 1538475601, - "version": "1.0.14", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1538157789, - "version": "1.0.13", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1537907159, - "version": "1.0.12", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1537875740, - "version": "1.0.11", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1537541580, - "version": "1.0.10", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1536142250, - "version": "1.0.9", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1535377027, - "version": "1.0.8", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1535133899, - "version": "1.0.7", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1534210131, - "version": "1.0.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1532619515, - "version": "1.0.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1532614997, - "version": "1.0.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1532605697, - "version": "1.0.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1532551340, - "version": "1.0.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1532357734, - "version": "1.0.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1532043000, - "version": "1.0.0", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1531919263, - "version": "0.2.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1531149657, - "version": "0.2.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1529397769, - "version": "0.2.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1525477860, - "version": "0.2.0", - "changes": [ - { - "note": "Removed portal specific colors" - } - ] - }, - { - "timestamp": 1525477860, - "version": "0.1.6", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1525466747, - "version": "0.1.5", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1525428773, - "version": "0.1.4", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1524044013, - "version": "0.1.3", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1523462196, - "version": "0.1.2", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "timestamp": 1522673609, - "version": "0.1.1", - "changes": [ - { - "note": "Dependencies updated" - } - ] - }, - { - "version": "0.1.0", - "changes": [ - { - "note": "Added new colors", - "pr": 468 - }, - { - "note": "Fix section and menuItem text display to replace dashes with spaces." - }, - { - "note": "Reorganized colors and added new ones" - } - ], - "timestamp": 1522658513 - } -] diff --git a/packages/react-shared/CHANGELOG.md b/packages/react-shared/CHANGELOG.md deleted file mode 100644 index 9ed07fa2a5..0000000000 --- a/packages/react-shared/CHANGELOG.md +++ /dev/null @@ -1,224 +0,0 @@ - - -CHANGELOG - -## v2.0.14 - _July 13, 2019_ - - * Dependencies updated - -## v2.0.13 - _July 13, 2019_ - - * Dependencies updated - -## v2.0.12 - _May 24, 2019_ - - * Dependencies updated - -## v2.0.11 - _May 10, 2019_ - - * Dependencies updated - -## v2.0.10 - _April 11, 2019_ - - * Dependencies updated - -## v2.0.9 - _March 21, 2019_ - - * Dependencies updated - -## v2.0.8 - _March 20, 2019_ - - * Dependencies updated - -## v2.0.7 - _March 1, 2019_ - - * Dependencies updated - -## v2.0.6 - _February 26, 2019_ - - * Dependencies updated - -## v2.0.5 - _February 25, 2019_ - - * Dependencies updated - -## v2.0.4 - _February 9, 2019_ - - * Dependencies updated - -## v2.0.3 - _February 7, 2019_ - - * Dependencies updated - -## v2.0.2 - _February 7, 2019_ - - * Dependencies updated - -## v2.0.1 - _February 6, 2019_ - - * Dependencies updated - -## v2.0.0 - _February 5, 2019_ - - * Upgrade the bignumber.js to v8.0.2 (#1517) - -## v1.1.2 - _January 15, 2019_ - - * Dependencies updated - -## v1.1.1 - _January 11, 2019_ - - * Dependencies updated - -## v1.1.0 - _January 9, 2019_ - - * Change implementation to use react-router-dom NavLink instead of Link. Expose `activeStyle` prop. (#1448) - -## v1.0.25 - _December 13, 2018_ - - * Dependencies updated - -## v1.0.24 - _December 11, 2018_ - - * Dependencies updated - -## v1.0.23 - _November 28, 2018_ - - * Dependencies updated - -## v1.0.22 - _November 21, 2018_ - - * Dependencies updated - -## v1.0.21 - _November 14, 2018_ - - * Dependencies updated - -## v1.0.20 - _November 13, 2018_ - - * Dependencies updated - -## v1.0.19 - _November 12, 2018_ - - * Dependencies updated - -## v1.0.18 - _November 9, 2018_ - - * Dependencies updated - -## v1.0.17 - _October 18, 2018_ - - * Dependencies updated - -## v1.0.16 - _October 4, 2018_ - - * Unpublished package - -## v1.0.14 - _October 2, 2018_ - - * Dependencies updated - -## v1.0.13 - _September 28, 2018_ - - * Dependencies updated - -## v1.0.12 - _September 25, 2018_ - - * Dependencies updated - -## v1.0.11 - _September 25, 2018_ - - * Dependencies updated - -## v1.0.10 - _September 21, 2018_ - - * Dependencies updated - -## v1.0.9 - _September 5, 2018_ - - * Dependencies updated - -## v1.0.8 - _August 27, 2018_ - - * Dependencies updated - -## v1.0.7 - _August 24, 2018_ - - * Dependencies updated - -## v1.0.6 - _August 14, 2018_ - - * Dependencies updated - -## v1.0.5 - _July 26, 2018_ - - * Dependencies updated - -## v1.0.4 - _July 26, 2018_ - - * Dependencies updated - -## v1.0.3 - _July 26, 2018_ - - * Dependencies updated - -## v1.0.2 - _July 25, 2018_ - - * Dependencies updated - -## v1.0.1 - _July 23, 2018_ - - * Dependencies updated - -## v1.0.0 - _July 19, 2018_ - - * Dependencies updated - -## v0.2.3 - _July 18, 2018_ - - * Dependencies updated - -## v0.2.2 - _July 9, 2018_ - - * Dependencies updated - -## v0.2.1 - _June 19, 2018_ - - * Dependencies updated - -## v0.2.0 - _May 4, 2018_ - - * Removed portal specific colors - -## v0.1.6 - _May 4, 2018_ - - * Dependencies updated - -## v0.1.5 - _May 4, 2018_ - - * Dependencies updated - -## v0.1.4 - _May 4, 2018_ - - * Dependencies updated - -## v0.1.3 - _April 18, 2018_ - - * Dependencies updated - -## v0.1.2 - _April 11, 2018_ - - * Dependencies updated - -## v0.1.1 - _April 2, 2018_ - - * Dependencies updated - -## v0.1.0 - _April 2, 2018_ - - * Added new colors (#468) - * Fix section and menuItem text display to replace dashes with spaces. - * Reorganized colors and added new ones diff --git a/packages/react-shared/README.md b/packages/react-shared/README.md deleted file mode 100644 index 7ff9a94d90..0000000000 --- a/packages/react-shared/README.md +++ /dev/null @@ -1,63 +0,0 @@ -## @0x/react-shared - -Contains React components & frontend types/utils shared between 0x projects. - -## Installation - -```bash -yarn add @0x/react-shared -``` - -If your project is in [TypeScript](https://www.typescriptlang.org/), add the following to your `tsconfig.json`: - -```json -"compilerOptions": { - "typeRoots": ["node_modules/@0x/typescript-typings/types", "node_modules/@types"], -} -``` - -## Contributing - -We welcome improvements and fixes from the wider community! To report bugs within this package, please create an issue in this repository. - -Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started. - -### Install dependencies - -If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them: - -```bash -yarn config set workspaces-experimental true -``` - -Then install dependencies - -```bash -yarn install -``` - -### Build - -To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory: - -```bash -PKG=@0x/react-shared yarn build -``` - -Or continuously rebuild on change: - -```bash -PKG=@0x/react-shared yarn watch -``` - -### Clean - -```bash -yarn clean -``` - -### Lint - -```bash -yarn lint -``` diff --git a/packages/react-shared/package.json b/packages/react-shared/package.json deleted file mode 100644 index 7a14245236..0000000000 --- a/packages/react-shared/package.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "name": "@0x/react-shared", - "version": "2.0.14", - "engines": { - "node": ">=6.12" - }, - "description": "0x shared react components", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "scripts": { - "lint": "tslint --format stylish --project .", - "fix": "tslint --fix --format stylish --project .", - "build": "tsc", - "build:ci": "yarn build", - "watch_without_deps": "tsc -w", - "clean": "shx rm -rf lib" - }, - "author": "Fabio Berger", - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/0xProject/0x-monorepo/issues" - }, - "homepage": "https://github.com/0xProject/0x-monorepo/packages/react-shared/README.md", - "repository": { - "type": "git", - "url": "https://github.com/0xProject/0x-monorepo.git" - }, - "devDependencies": { - "@0x/dev-utils": "^2.2.4", - "@0x/tslint-config": "^3.0.1", - "make-promises-safe": "^1.1.0", - "shx": "^0.2.2", - "tslint": "5.11.0", - "typescript": "3.0.1" - }, - "dependencies": { - "@0x/types": "^2.4.0", - "@material-ui/core": "^3.0.1", - "@types/is-mobile": "0.3.0", - "@types/lodash": "4.14.104", - "@types/material-ui": "^0.20.0", - "@types/node": "*", - "@types/react": "*", - "@types/react-dom": "*", - "@types/react-router-dom": "^4.0.4", - "@types/react-scroll": "1.5.3", - "@types/styled-components": "4.1.1", - "@types/valid-url": "^1.0.2", - "basscss": "^8.0.3", - "change-case": "^3.0.2", - "is-mobile": "^0.2.2", - "lodash": "^4.17.11", - "material-ui": "^0.20.0", - "react": "^16.5.2", - "react-dom": "^16.5.2", - "react-highlight": "0xproject/react-highlight#react-peer-deps", - "react-markdown": "^3.2.2", - "react-router-dom": "^4.3.1", - "react-scroll": "0xproject/react-scroll#pr-330-and-replace-state", - "styled-components": "^4.1.1", - "valid-url": "^1.0.9" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/packages/react-shared/src/globals.d.ts b/packages/react-shared/src/globals.d.ts deleted file mode 100644 index 94e63a32de..0000000000 --- a/packages/react-shared/src/globals.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare module '*.json' { - const json: any; - /* tslint:disable */ - export default json; - /* tslint:enable */ -} diff --git a/packages/react-shared/src/index.ts b/packages/react-shared/src/index.ts deleted file mode 100644 index 285e1c6b45..0000000000 --- a/packages/react-shared/src/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -export { AnchorTitle } from './components/anchor_title'; -export { MarkdownLinkBlock } from './components/markdown_link_block'; -export { MarkdownCodeBlock } from './components/markdown_code_block'; -export { MarkdownSection } from './components/markdown_section'; -export { SectionHeader } from './components/section_header'; -export { Link, LinkProps } from './components/link'; - -export { HeaderSizes, Styles, EtherscanLinkSuffixes, Networks, ALink } from './types'; - -export { utils } from './utils/utils'; -export { constants } from './utils/constants'; -export { colors } from './utils/colors'; diff --git a/packages/react-shared/src/types.ts b/packages/react-shared/src/types.ts deleted file mode 100644 index 9e8dcb6b64..0000000000 --- a/packages/react-shared/src/types.ts +++ /dev/null @@ -1,33 +0,0 @@ -export interface Styles { - [name: string]: React.CSSProperties; -} - -export enum HeaderSizes { - H1 = 'h1', - H2 = 'h2', - H3 = 'h3', -} - -export enum EtherscanLinkSuffixes { - Address = 'address', - Tx = 'tx', -} - -export enum Networks { - Mainnet = 'Mainnet', - Kovan = 'Kovan', - Ropsten = 'Ropsten', - Rinkeby = 'Rinkeby', -} - -export enum LinkType { - External = 'EXTERNAL', - ReactScroll = 'REACT_SCROLL', - ReactRoute = 'REACT_ROUTE', -} - -export interface ALink { - title: string; - to: string; - shouldOpenInNewTab?: boolean; -} diff --git a/packages/react-shared/src/utils/constants.ts b/packages/react-shared/src/utils/constants.ts deleted file mode 100644 index 2dca1a078d..0000000000 --- a/packages/react-shared/src/utils/constants.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Networks } from '../types'; - -export const constants = { - DOCS_SCROLL_DURATION_MS: 0, - SCROLL_CONTAINER_ID: 'scroll_container', - SCROLL_TOP_ID: 'pageScrollTop', - NETWORK_NAME_BY_ID: { - 1: Networks.Mainnet, - 3: Networks.Ropsten, - 4: Networks.Rinkeby, - 42: Networks.Kovan, - } as { [symbol: number]: string }, - NETWORK_ID_BY_NAME: { - [Networks.Mainnet]: 1, - [Networks.Ropsten]: 3, - [Networks.Rinkeby]: 4, - [Networks.Kovan]: 42, - } as { [networkName: string]: number }, -}; diff --git a/packages/react-shared/src/utils/utils.ts b/packages/react-shared/src/utils/utils.ts deleted file mode 100644 index 16e7930ede..0000000000 --- a/packages/react-shared/src/utils/utils.ts +++ /dev/null @@ -1,52 +0,0 @@ -import changeCase = require('change-case'); -import isMobile = require('is-mobile'); -import * as _ from 'lodash'; -import { scroller } from 'react-scroll'; - -import { EtherscanLinkSuffixes, Networks } from '../types'; - -import { constants } from './constants'; - -export const utils = { - setUrlHash(anchorId: string): void { - window.location.hash = anchorId; - }, - scrollToHash(hash: string, containerId: string): void { - let finalHash = hash; - if (_.isEmpty(hash)) { - finalHash = constants.SCROLL_TOP_ID; // scroll to the top - } - - scroller.scrollTo(finalHash, { - duration: 0, - offset: 0, - containerId, - }); - }, - isUserOnMobile(): boolean { - const isUserOnMobile = isMobile(); - return isUserOnMobile; - }, - getIdFromName(name: string): string { - const id = name.replace(/ /g, '-'); - return id; - }, - convertDashesToSpaces(text: string): string { - return text.replace(/-/g, ' '); - }, - convertCamelCaseToSpaces(text: string): string { - return changeCase.snake(text).replace(/_/g, ' '); - }, - getEtherScanLinkIfExists( - addressOrTxHash: string, - networkId: number, - suffix: EtherscanLinkSuffixes, - ): string | undefined { - const networkName = constants.NETWORK_NAME_BY_ID[networkId]; - if (networkName === undefined) { - return undefined; - } - const etherScanPrefix = networkName === Networks.Mainnet ? '' : `${networkName.toLowerCase()}.`; - return `https://${etherScanPrefix}etherscan.io/${suffix}/${addressOrTxHash}`; - }, -}; diff --git a/packages/react-shared/tsconfig.json b/packages/react-shared/tsconfig.json deleted file mode 100644 index 5abe0ab4e7..0000000000 --- a/packages/react-shared/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../../tsconfig", - "compilerOptions": { - "outDir": "lib", - "rootDir": "src", - "jsx": "react", - "baseUrl": ".", - "paths": { - "*": ["node_modules/@types/*", "*"] - } - }, - "include": ["./src/**/*"] -} diff --git a/packages/react-shared/tslint.json b/packages/react-shared/tslint.json deleted file mode 100644 index c3f6d9cae7..0000000000 --- a/packages/react-shared/tslint.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": ["@0x/tslint-config"], - "rules": { - "no-object-literal-type-assertion": false, - "completed-docs": false, - "prefer-function-over-method": false, - "custom-no-magic-numbers": false - } -} diff --git a/packages/sol-compiler/.npmignore b/packages/sol-compiler/.npmignore index d7e21883c6..8bf011e330 100644 --- a/packages/sol-compiler/.npmignore +++ b/packages/sol-compiler/.npmignore @@ -9,3 +9,5 @@ # Package specific ignore !bin/**/* !solc_bin/.gitkeep +lib/solc_bin/* +!lib/solc_bin/.gitkeep diff --git a/packages/sol-compiler/CHANGELOG.json b/packages/sol-compiler/CHANGELOG.json index c13fdb9a47..36a263f436 100644 --- a/packages/sol-compiler/CHANGELOG.json +++ b/packages/sol-compiler/CHANGELOG.json @@ -2,16 +2,40 @@ { "version": "3.2.0", "changes": [ - { - "note": "re-export new ethereum-types types, TupleDataItem", - "pr": 1919 - }, { "note": "Convert `getContractNamesToCompile` to public function of `Compiler` class", - "pr": 1919 + "pr": 2055 } ] }, + { + "timestamp": 1565296576, + "version": "3.1.12", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1564604963, + "version": "3.1.11", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "version": "3.1.10", + "changes": [ + { + "note": "re-export new ethereum-types types, TupleDataItem", + "pr": 1919 + } + ], + "timestamp": 1563957393 + }, { "timestamp": 1563006338, "version": "3.1.9", diff --git a/packages/sol-compiler/CHANGELOG.md b/packages/sol-compiler/CHANGELOG.md index ad97de97d4..2a54ae8539 100644 --- a/packages/sol-compiler/CHANGELOG.md +++ b/packages/sol-compiler/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.1.12 - _August 8, 2019_ + + * Dependencies updated + +## v3.1.11 - _July 31, 2019_ + + * Dependencies updated + +## v3.1.10 - _July 24, 2019_ + + * re-export new ethereum-types types, TupleDataItem (#1919) + ## v3.1.9 - _July 13, 2019_ * Dependencies updated diff --git a/packages/sol-compiler/package.json b/packages/sol-compiler/package.json index 619922dca5..472b91eb65 100644 --- a/packages/sol-compiler/package.json +++ b/packages/sol-compiler/package.json @@ -1,6 +1,6 @@ { "name": "@0x/sol-compiler", - "version": "3.1.9", + "version": "3.1.12", "engines": { "node": ">=6.12" }, @@ -43,10 +43,10 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/sol-compiler/README.md", "devDependencies": { - "@0x/dev-utils": "^2.2.4", + "@0x/dev-utils": "^2.3.0", "@0x/tslint-config": "^3.0.1", - "@types/chokidar": "^1.7.5", "@types/mkdirp": "^0.5.2", + "@types/mocha": "^5.2.7", "@types/pluralize": "^0.0.29", "@types/require-from-string": "^1.2.0", "@types/semver": "5.5.0", @@ -57,7 +57,7 @@ "copyfiles": "^2.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "shx": "^0.2.2", @@ -70,17 +70,17 @@ "zeppelin-solidity": "1.8.0" }, "dependencies": { - "@0x/assert": "^2.1.0", - "@0x/json-schemas": "^3.0.11", - "@0x/sol-resolver": "^2.0.8", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", + "@0x/assert": "^2.1.3", + "@0x/json-schemas": "^3.1.13", + "@0x/sol-resolver": "^2.0.9", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", "@types/yargs": "^11.0.0", "chalk": "^2.3.0", - "chokidar": "^2.0.4", - "ethereum-types": "^2.1.3", + "chokidar": "^3.0.2", + "ethereum-types": "^2.1.4", "ethereumjs-util": "^5.1.1", "lodash": "^4.17.11", "mkdirp": "^0.5.1", diff --git a/packages/sol-coverage/CHANGELOG.json b/packages/sol-coverage/CHANGELOG.json index 684ac63aca..d5d7e1ece8 100644 --- a/packages/sol-coverage/CHANGELOG.json +++ b/packages/sol-coverage/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1565296576, + "version": "3.0.9", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1564604963, + "version": "3.0.8", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1563957393, + "version": "3.0.7", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563006338, "version": "3.0.6", diff --git a/packages/sol-coverage/CHANGELOG.md b/packages/sol-coverage/CHANGELOG.md index 8616f0949a..b34d42a15f 100644 --- a/packages/sol-coverage/CHANGELOG.md +++ b/packages/sol-coverage/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.0.9 - _August 8, 2019_ + + * Dependencies updated + +## v3.0.8 - _July 31, 2019_ + + * Dependencies updated + +## v3.0.7 - _July 24, 2019_ + + * Dependencies updated + ## v3.0.6 - _July 13, 2019_ * Dependencies updated diff --git a/packages/sol-coverage/package.json b/packages/sol-coverage/package.json index a664c03082..8b1e62565f 100644 --- a/packages/sol-coverage/package.json +++ b/packages/sol-coverage/package.json @@ -1,6 +1,6 @@ { "name": "@0x/sol-coverage", - "version": "3.0.6", + "version": "3.0.9", "engines": { "node": ">=6.12" }, @@ -30,11 +30,11 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/sol-coverage/README.md", "dependencies": { - "@0x/sol-tracing-utils": "^6.0.13", - "@0x/subproviders": "^4.1.1", - "@0x/typescript-typings": "^4.2.3", + "@0x/sol-tracing-utils": "^6.0.16", + "@0x/subproviders": "^5.0.1", + "@0x/typescript-typings": "^4.2.4", "@types/minimatch": "^3.0.3", - "ethereum-types": "^2.1.3", + "ethereum-types": "^2.1.4", "lodash": "^4.17.11", "minimatch": "^3.0.4", "web3-provider-engine": "14.0.6" diff --git a/packages/sol-doc/CHANGELOG.json b/packages/sol-doc/CHANGELOG.json index 76a6d996fa..d388166302 100644 --- a/packages/sol-doc/CHANGELOG.json +++ b/packages/sol-doc/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1565296576, + "version": "2.0.16", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1564604963, + "version": "2.0.15", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1563957393, + "version": "2.0.14", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.0.13", "changes": [ diff --git a/packages/sol-doc/CHANGELOG.md b/packages/sol-doc/CHANGELOG.md index d908fa79ff..86dd359795 100644 --- a/packages/sol-doc/CHANGELOG.md +++ b/packages/sol-doc/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.16 - _August 8, 2019_ + + * Dependencies updated + +## v2.0.15 - _July 31, 2019_ + + * Dependencies updated + +## v2.0.14 - _July 24, 2019_ + + * Dependencies updated + ## v2.0.13 - _July 13, 2019_ * Confirm devdoc components exist before using them (#1878) diff --git a/packages/sol-doc/package.json b/packages/sol-doc/package.json index 2fd28010a9..832bfb3736 100644 --- a/packages/sol-doc/package.json +++ b/packages/sol-doc/package.json @@ -1,6 +1,6 @@ { "name": "@0x/sol-doc", - "version": "2.0.13", + "version": "2.0.16", "description": "Solidity documentation generator", "main": "lib/src/index.js", "types": "lib/src/index.d.js", @@ -26,22 +26,23 @@ "author": "F. Eugene Aumson", "license": "Apache-2.0", "dependencies": { - "@0x/sol-compiler": "^3.1.9", - "@0x/types": "^2.4.0", - "@0x/utils": "^4.4.0", - "ethereum-types": "^2.1.3", + "@0x/sol-compiler": "^3.1.12", + "@0x/types": "^2.4.1", + "@0x/utils": "^4.5.0", + "ethereum-types": "^2.1.4", "ethereumjs-util": "^5.1.1", "lodash": "^4.17.11", "yargs": "^10.0.3" }, "devDependencies": { "@0x/tslint-config": "^3.0.1", + "@types/mocha": "^5.2.7", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^3.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "shx": "^0.2.2", "source-map-support": "^0.5.0", "tslint": "5.11.0" diff --git a/packages/sol-profiler/CHANGELOG.json b/packages/sol-profiler/CHANGELOG.json index 46fc52d1de..dd53d21744 100644 --- a/packages/sol-profiler/CHANGELOG.json +++ b/packages/sol-profiler/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1565296576, + "version": "3.1.11", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1564604963, + "version": "3.1.10", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1563957393, + "version": "3.1.9", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563006338, "version": "3.1.8", diff --git a/packages/sol-profiler/CHANGELOG.md b/packages/sol-profiler/CHANGELOG.md index 13c10b27f7..13992eb0a9 100644 --- a/packages/sol-profiler/CHANGELOG.md +++ b/packages/sol-profiler/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v3.1.11 - _August 8, 2019_ + + * Dependencies updated + +## v3.1.10 - _July 31, 2019_ + + * Dependencies updated + +## v3.1.9 - _July 24, 2019_ + + * Dependencies updated + ## v3.1.8 - _July 13, 2019_ * Dependencies updated diff --git a/packages/sol-profiler/package.json b/packages/sol-profiler/package.json index 22b2fc5050..950de1c386 100644 --- a/packages/sol-profiler/package.json +++ b/packages/sol-profiler/package.json @@ -1,6 +1,6 @@ { "name": "@0x/sol-profiler", - "version": "3.1.8", + "version": "3.1.11", "engines": { "node": ">=6.12" }, @@ -30,11 +30,11 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/sol-profiler/README.md", "dependencies": { - "@0x/sol-tracing-utils": "^6.0.13", - "@0x/subproviders": "^4.1.1", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "ethereum-types": "^2.1.3", + "@0x/sol-tracing-utils": "^6.0.16", + "@0x/subproviders": "^5.0.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "ethereum-types": "^2.1.4", "ethereumjs-util": "^5.1.1", "lodash": "^4.17.11", "web3-provider-engine": "14.0.6" diff --git a/packages/sol-resolver/CHANGELOG.json b/packages/sol-resolver/CHANGELOG.json index 8af80f3aec..7d390e13e2 100644 --- a/packages/sol-resolver/CHANGELOG.json +++ b/packages/sol-resolver/CHANGELOG.json @@ -1,4 +1,13 @@ [ + { + "timestamp": 1563957393, + "version": "2.0.9", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563006338, "version": "2.0.8", diff --git a/packages/sol-resolver/CHANGELOG.md b/packages/sol-resolver/CHANGELOG.md index e7a988d8fc..87fd247ce8 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 +## v2.0.9 - _July 24, 2019_ + + * Dependencies updated + ## v2.0.8 - _July 13, 2019_ * Dependencies updated diff --git a/packages/sol-resolver/package.json b/packages/sol-resolver/package.json index 2fd30df86b..b7f153c94c 100644 --- a/packages/sol-resolver/package.json +++ b/packages/sol-resolver/package.json @@ -1,6 +1,6 @@ { "name": "@0x/sol-resolver", - "version": "2.0.8", + "version": "2.0.9", "engines": { "node": ">=6.12" }, @@ -31,8 +31,8 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", "lodash": "^4.17.11" }, "publishConfig": { diff --git a/packages/sol-trace/CHANGELOG.json b/packages/sol-trace/CHANGELOG.json index 29b70c0b83..742d49f5b5 100644 --- a/packages/sol-trace/CHANGELOG.json +++ b/packages/sol-trace/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1565296576, + "version": "2.0.17", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1564604963, + "version": "2.0.16", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1563957393, + "version": "2.0.15", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563006338, "version": "2.0.14", diff --git a/packages/sol-trace/CHANGELOG.md b/packages/sol-trace/CHANGELOG.md index 85cb2f4632..c4de50b090 100644 --- a/packages/sol-trace/CHANGELOG.md +++ b/packages/sol-trace/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.17 - _August 8, 2019_ + + * Dependencies updated + +## v2.0.16 - _July 31, 2019_ + + * Dependencies updated + +## v2.0.15 - _July 24, 2019_ + + * Dependencies updated + ## v2.0.14 - _July 13, 2019_ * Dependencies updated diff --git a/packages/sol-trace/package.json b/packages/sol-trace/package.json index f4c254712f..0f89fa6887 100644 --- a/packages/sol-trace/package.json +++ b/packages/sol-trace/package.json @@ -1,6 +1,6 @@ { "name": "@0x/sol-trace", - "version": "2.0.14", + "version": "2.0.17", "engines": { "node": ">=6.12" }, @@ -30,11 +30,11 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/sol-trace/README.md", "dependencies": { - "@0x/sol-tracing-utils": "^6.0.13", - "@0x/subproviders": "^4.1.1", - "@0x/typescript-typings": "^4.2.3", + "@0x/sol-tracing-utils": "^6.0.16", + "@0x/subproviders": "^5.0.1", + "@0x/typescript-typings": "^4.2.4", "chalk": "^2.3.0", - "ethereum-types": "^2.1.3", + "ethereum-types": "^2.1.4", "ethereumjs-util": "^5.1.1", "lodash": "^4.17.11", "loglevel": "^1.6.1", diff --git a/packages/sol-tracing-utils/CHANGELOG.json b/packages/sol-tracing-utils/CHANGELOG.json index 191ff34353..12d481c638 100644 --- a/packages/sol-tracing-utils/CHANGELOG.json +++ b/packages/sol-tracing-utils/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1565296576, + "version": "6.0.16", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1564604963, + "version": "6.0.15", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1563957393, + "version": "6.0.14", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563006338, "version": "6.0.13", diff --git a/packages/sol-tracing-utils/CHANGELOG.md b/packages/sol-tracing-utils/CHANGELOG.md index e89c460304..b56a54eb7c 100644 --- a/packages/sol-tracing-utils/CHANGELOG.md +++ b/packages/sol-tracing-utils/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v6.0.16 - _August 8, 2019_ + + * Dependencies updated + +## v6.0.15 - _July 31, 2019_ + + * Dependencies updated + +## v6.0.14 - _July 24, 2019_ + + * Dependencies updated + ## v6.0.13 - _July 13, 2019_ * Dependencies updated diff --git a/packages/sol-tracing-utils/package.json b/packages/sol-tracing-utils/package.json index 54a500206b..f42869ef69 100644 --- a/packages/sol-tracing-utils/package.json +++ b/packages/sol-tracing-utils/package.json @@ -1,6 +1,6 @@ { "name": "@0x/sol-tracing-utils", - "version": "6.0.13", + "version": "6.0.16", "engines": { "node": ">=6.12" }, @@ -43,16 +43,16 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/sol-tracing-utils/README.md", "dependencies": { - "@0x/dev-utils": "^2.2.4", - "@0x/sol-compiler": "^3.1.9", - "@0x/sol-resolver": "^2.0.8", - "@0x/subproviders": "^4.1.1", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", + "@0x/dev-utils": "^2.3.0", + "@0x/sol-compiler": "^3.1.12", + "@0x/sol-resolver": "^2.0.9", + "@0x/subproviders": "^5.0.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", "@types/solidity-parser-antlr": "^0.2.3", "chalk": "^2.3.0", - "ethereum-types": "^2.1.3", + "ethereum-types": "^2.1.4", "ethereumjs-util": "^5.1.1", "ethers": "~4.0.4", "glob": "^7.1.2", @@ -70,14 +70,14 @@ "@types/istanbul": "^0.4.30", "@types/loglevel": "^1.5.3", "@types/mkdirp": "^0.5.2", - "@types/mocha": "^2.2.42", + "@types/mocha": "^5.2.7", "@types/node": "*", "@types/rimraf": "^2.0.2", "chai": "^4.0.1", "copyfiles": "^2.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "shx": "^0.2.2", diff --git a/packages/sra-spec/CHANGELOG.json b/packages/sra-spec/CHANGELOG.json index 16b12bdc9c..7d54b7df60 100644 --- a/packages/sra-spec/CHANGELOG.json +++ b/packages/sra-spec/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "timestamp": 1565296576, + "version": "2.0.14", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1564604963, + "version": "2.0.13", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1563957393, + "version": "2.0.12", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563006338, "version": "2.0.11", diff --git a/packages/sra-spec/CHANGELOG.md b/packages/sra-spec/CHANGELOG.md index 8f7825d901..556b14c727 100644 --- a/packages/sra-spec/CHANGELOG.md +++ b/packages/sra-spec/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.14 - _August 8, 2019_ + + * Dependencies updated + +## v2.0.13 - _July 31, 2019_ + + * Dependencies updated + +## v2.0.12 - _July 24, 2019_ + + * Dependencies updated + ## v2.0.11 - _July 13, 2019_ * Dependencies updated diff --git a/packages/sra-spec/package.json b/packages/sra-spec/package.json index 1907685ead..c5f3cf578e 100644 --- a/packages/sra-spec/package.json +++ b/packages/sra-spec/package.json @@ -1,6 +1,6 @@ { "name": "@0x/sra-spec", - "version": "2.0.11", + "version": "2.0.14", "engines": { "node": ">=6.12" }, @@ -36,19 +36,19 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/sra-spec/README.md", "dependencies": { - "@0x/json-schemas": "^3.0.11", + "@0x/json-schemas": "^3.1.13", "@loopback/openapi-v3-types": "^0.8.2" }, "devDependencies": { "@0x/tslint-config": "^3.0.1", - "@types/mocha": "^2.2.42", + "@types/mocha": "^5.2.7", "@types/node": "*", "chai": "^4.0.1", "chokidar-cli": "^1.2.0", "copyfiles": "^2.0.0", "dirty-chai": "^2.0.1", "discharge": "^0.7.1", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "redoc-cli": "^0.6.1", diff --git a/packages/sra-spec/src/md/introduction.md b/packages/sra-spec/src/md/introduction.md index 3f7431c516..63ac98062d 100644 --- a/packages/sra-spec/src/md/introduction.md +++ b/packages/sra-spec/src/md/introduction.md @@ -200,7 +200,7 @@ For more information see [the Asset Proxy](https://github.com/0xProject/0x-proto In v2 of the standard relayer API we added the `metaData` field. It is meant to provide a standard place for relayers to put optional, custom or non-standard fields that may of interest to the consumer of the API. -A good example of such a field is `remainingTakerAssetAmount`, which is a convenience field that communicates how much of a 0x order is potentially left to be filled. Unlike the other fields in a 0x order, it is not guaranteed to be correct as it is derived from whatever mechanism the implementer (ie. the relayer) is using. While convenient for prototyping and low stakes situations, we recommend validating the value of the field by checking the state of the blockchain yourself, such as by using [Order Watcher](https://0xproject.com/wiki#0x-OrderWatcher). +A good example of such a field is `remainingTakerAssetAmount`, which is a convenience field that communicates how much of a 0x order is potentially left to be filled. Unlike the other fields in a 0x order, it is not guaranteed to be correct as it is derived from whatever mechanism the implementer (ie. the relayer) is using. While convenient for prototyping and low stakes situations, we recommend validating the value of the field by checking the state of the blockchain yourself. # Misc. diff --git a/packages/subproviders/CHANGELOG.json b/packages/subproviders/CHANGELOG.json index 70739d363a..f2835cff83 100644 --- a/packages/subproviders/CHANGELOG.json +++ b/packages/subproviders/CHANGELOG.json @@ -1,4 +1,31 @@ [ + { + "version": "5.0.2", + "changes": [ + { + "note": "Updated `MetamaskSubprovider` to use `personal_sign` instead of `eth_sign` to support proxied hardware wallets.", + "pr": 2054 + } + ] + }, + { + "timestamp": 1565296576, + "version": "5.0.1", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "version": "5.0.0", + "changes": [ + { + "note": "Remove eth-lightwallet subprovider" + } + ], + "timestamp": 1564604963 + }, { "version": "4.1.2", "changes": [ @@ -6,7 +33,8 @@ "note": "Fix bug in Private Key subprovider causing checksummed tx.origin addresses to be rejected.", "pr": 1962 } - ] + ], + "timestamp": 1563957393 }, { "version": "4.1.1", diff --git a/packages/subproviders/CHANGELOG.md b/packages/subproviders/CHANGELOG.md index b790cb4b11..a34b61da2d 100644 --- a/packages/subproviders/CHANGELOG.md +++ b/packages/subproviders/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v5.0.1 - _August 8, 2019_ + + * Dependencies updated + +## v5.0.0 - _July 31, 2019_ + + * Remove eth-lightwallet subprovider + +## v4.1.2 - _July 24, 2019_ + + * Fix bug in Private Key subprovider causing checksummed tx.origin addresses to be rejected. (#1962) + ## v4.1.1 - _July 13, 2019_ * Fix bug in Trezor subprovider causing Trezor response to not be hex encoded (#1867) diff --git a/packages/subproviders/package.json b/packages/subproviders/package.json index 6c625091c7..ad66e44f2e 100644 --- a/packages/subproviders/package.json +++ b/packages/subproviders/package.json @@ -1,6 +1,6 @@ { "name": "@0x/subproviders", - "version": "4.1.1", + "version": "5.0.1", "engines": { "node": ">=6.12" }, @@ -30,23 +30,21 @@ } }, "dependencies": { - "@0x/assert": "^2.1.0", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", + "@0x/assert": "^2.1.3", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", "@ledgerhq/hw-app-eth": "^4.3.0", "@ledgerhq/hw-transport-u2f": "4.24.0", - "@types/eth-lightwallet": "^3.0.0", "@types/hdkey": "^0.7.0", "@types/web3-provider-engine": "^14.0.0", "bip39": "^2.5.0", "bn.js": "^4.11.8", - "eth-lightwallet": "^3.0.1", - "ethereum-types": "^2.1.3", + "ethereum-types": "^2.1.4", "ethereumjs-tx": "^1.3.5", "ethereumjs-util": "^5.1.1", - "ganache-core": "^2.5.3", + "ganache-core": "^2.6.0", "hdkey": "^0.7.1", "json-rpc-error": "2.0.0", "lodash": "^4.17.11", @@ -60,14 +58,14 @@ "@types/ethereumjs-tx": "^1.0.0", "@types/hdkey": "^0.7.0", "@types/lodash": "4.14.104", - "@types/mocha": "^2.2.42", + "@types/mocha": "^5.2.7", "@types/node": "*", "@types/sinon": "^2.2.2", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "shx": "^0.2.2", diff --git a/packages/subproviders/src/index.ts b/packages/subproviders/src/index.ts index ca89c43012..5b5c8b0847 100644 --- a/packages/subproviders/src/index.ts +++ b/packages/subproviders/src/index.ts @@ -28,7 +28,6 @@ export { NonceTrackerSubprovider } from './subproviders/nonce_tracker'; export { PrivateKeyWalletSubprovider } from './subproviders/private_key_wallet'; export { MnemonicWalletSubprovider } from './subproviders/mnemonic_wallet'; export { MetamaskSubprovider } from './subproviders/metamask_subprovider'; -export { EthLightwalletSubprovider } from './subproviders/eth_lightwallet_subprovider'; export { TrezorSubprovider } from './subproviders/trezor'; export { diff --git a/packages/subproviders/src/subproviders/eth_lightwallet_subprovider.ts b/packages/subproviders/src/subproviders/eth_lightwallet_subprovider.ts deleted file mode 100644 index 15cd713af3..0000000000 --- a/packages/subproviders/src/subproviders/eth_lightwallet_subprovider.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { EIP712TypedData } from '@0x/types'; -import * as lightwallet from 'eth-lightwallet'; - -import { PartialTxParams } from '../types'; - -import { BaseWalletSubprovider } from './base_wallet_subprovider'; -import { PrivateKeyWalletSubprovider } from './private_key_wallet'; - -/* - * This class implements the web3-provider-engine subprovider interface and forwards - * requests involving user accounts and signing operations to eth-lightwallet - * - * Source: https://github.com/MetaMask/provider-engine/blob/master/subproviders/subprovider.js - */ -export class EthLightwalletSubprovider extends BaseWalletSubprovider { - private readonly _keystore: lightwallet.keystore; - private readonly _pwDerivedKey: Uint8Array; - /** - * Instantiate an EthLightwalletSubprovider - * @param keystore The EthLightWallet keystore you wish to use - * @param pwDerivedKey The password derived key to use - * @return EthLightwalletSubprovider instance - */ - constructor(keystore: lightwallet.keystore, pwDerivedKey: Uint8Array) { - super(); - this._keystore = keystore; - this._pwDerivedKey = pwDerivedKey; - } - /** - * Retrieve the accounts associated with the eth-lightwallet instance. - * This method is implicitly called when issuing a `eth_accounts` JSON RPC request - * via your providerEngine instance. - * - * @return An array of accounts - */ - public async getAccountsAsync(): Promise { - const accounts = this._keystore.getAddresses(); - return accounts; - } - /** - * Signs a transaction with the account specificed by the `from` field in txParams. - * If you've added this Subprovider to your app's provider, you can simply send - * an `eth_sendTransaction` JSON RPC request, and this method will be called auto-magically. - * If you are not using this via a ProviderEngine instance, you can call it directly. - * @param txParams Parameters of the transaction to sign - * @return Signed transaction hex string - */ - public async signTransactionAsync(txParams: PartialTxParams): Promise { - // Lightwallet loses the chain id information when hex encoding the transaction - // this results in a different signature on certain networks. PrivateKeyWallet - // respects this as it uses the parameters passed in - let privateKey = this._keystore.exportPrivateKey(txParams.from, this._pwDerivedKey); - const privateKeyWallet = new PrivateKeyWalletSubprovider(privateKey); - privateKey = ''; - const privateKeySignature = await privateKeyWallet.signTransactionAsync(txParams); - return privateKeySignature; - } - /** - * Sign a personal Ethereum signed message. The signing account will be the account - * associated with the provided address. - * If you've added this Subprovider to your app's provider, you can simply send an `eth_sign` - * or `personal_sign` JSON RPC request, and this method will be called auto-magically. - * If you are not using this via a ProviderEngine instance, you can call it directly. - * @param data Hex string message to sign - * @param address Address of the account to sign with - * @return Signature hex string (order: rsv) - */ - public async signPersonalMessageAsync(data: string, address: string): Promise { - let privateKey = this._keystore.exportPrivateKey(address, this._pwDerivedKey); - const privateKeyWallet = new PrivateKeyWalletSubprovider(privateKey); - privateKey = ''; - const result = privateKeyWallet.signPersonalMessageAsync(data, address); - return result; - } - /** - * Sign an EIP712 Typed Data message. The signing address will associated with the provided address. - * If you've added this Subprovider to your app's provider, you can simply send an `eth_signTypedData` - * JSON RPC request, and this method will be called auto-magically. - * If you are not using this via a ProviderEngine instance, you can call it directly. - * @param address Address of the account to sign with - * @param data the typed data object - * @return Signature hex string (order: rsv) - */ - public async signTypedDataAsync(address: string, typedData: EIP712TypedData): Promise { - let privateKey = this._keystore.exportPrivateKey(address, this._pwDerivedKey); - const privateKeyWallet = new PrivateKeyWalletSubprovider(privateKey); - privateKey = ''; - const result = privateKeyWallet.signTypedDataAsync(address, typedData); - return result; - } -} diff --git a/packages/subproviders/src/subproviders/metamask_subprovider.ts b/packages/subproviders/src/subproviders/metamask_subprovider.ts index bb85cf771b..3efb113ef2 100644 --- a/packages/subproviders/src/subproviders/metamask_subprovider.ts +++ b/packages/subproviders/src/subproviders/metamask_subprovider.ts @@ -1,7 +1,6 @@ import { providerUtils } from '@0x/utils'; import { marshaller, Web3Wrapper } from '@0x/web3-wrapper'; import { JSONRPCRequestPayload, SupportedProvider, ZeroExProvider } from 'ethereum-types'; -import * as ethUtil from 'ethereumjs-util'; import { Callback, ErrorCallback } from '../types'; @@ -71,11 +70,15 @@ export class MetamaskSubprovider extends Subprovider { [address, message] = payload.params; try { // Metamask incorrectly implements eth_sign and does not prefix the message as per the spec - // Source: https://github.com/MetaMask/metamask-extension/commit/a9d36860bec424dcee8db043d3e7da6a5ff5672e - const msgBuff = ethUtil.toBuffer(message); - const prefixedMsgBuff = ethUtil.hashPersonalMessage(msgBuff); - const prefixedMsgHex = ethUtil.bufferToHex(prefixedMsgBuff); - const signature = await this._web3Wrapper.signMessageAsync(address, prefixedMsgHex); + // It does however implement personal_sign and will leave off the prefix when used as a proxy for hardware wallets + // Source: https://metamask.github.io/metamask-docs/API_Reference/Signing_Data/Personal_Sign + // See: https://github.com/MetaMask/eth-ledger-bridge-keyring/blob/master/index.js#L192 + // and https://github.com/MetaMask/eth-trezor-keyring/blob/master/index.js#L211 + // and https://github.com/MetaMask/eth-sig-util/blob/master/index.js#L250 + const signature = await this._web3Wrapper.sendRawPayloadAsync({ + method: 'personal_sign', + params: [message, address], + }); signature ? end(null, signature) : end(new Error('Error performing eth_sign'), null); } catch (err) { end(err); diff --git a/packages/subproviders/test/unit/eth_lightwallet_subprovider_test.ts b/packages/subproviders/test/unit/eth_lightwallet_subprovider_test.ts deleted file mode 100644 index 468a9725f4..0000000000 --- a/packages/subproviders/test/unit/eth_lightwallet_subprovider_test.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { providerUtils } from '@0x/utils'; -import * as chai from 'chai'; -import * as lightwallet from 'eth-lightwallet'; -import { JSONRPCResponsePayload } from 'ethereum-types'; -import * as ethUtils from 'ethereumjs-util'; - -import { EthLightwalletSubprovider, Web3ProviderEngine } from '../../src'; -import { DoneCallback } from '../../src/types'; -import { chaiSetup } from '../chai_setup'; -import { fixtureData } from '../utils/fixture_data'; -import { ganacheSubprovider } from '../utils/ganache_subprovider'; -import { reportCallbackErrors } from '../utils/report_callback_errors'; - -chaiSetup.configure(); -const expect = chai.expect; - -const DEFAULT_NUM_ACCOUNTS = 10; -const PASSWORD = 'supersecretpassword99'; -const SALT = 'kvODghzs7Ff1uqHyI0P3wI4Hso4w4iWT2e9qmrWz0y4'; - -describe('EthLightwalletSubprovider', () => { - let ethLightwalletSubprovider: EthLightwalletSubprovider; - before(async () => { - const options = { - password: PASSWORD, - seedPhrase: fixtureData.TEST_RPC_MNEMONIC, - salt: SALT, - hdPathString: fixtureData.TESTRPC_BASE_DERIVATION_PATH, - }; - const createVaultAsync = async (vaultOptions: lightwallet.VaultOptions) => { - return new Promise(resolve => { - lightwallet.keystore.createVault(vaultOptions, (err: Error, vaultKeystore) => { - if (err) { - throw new Error(`Failed to createVault: ${err}`); - } - resolve(vaultKeystore); - }); - }); - }; - const deriveKeyFromPasswordAsync = async (vaultKeystore: lightwallet.keystore) => { - return new Promise(resolve => { - vaultKeystore.keyFromPassword(PASSWORD, (err: Error, passwordDerivedKey: Uint8Array) => { - if (err) { - throw new Error(`Failed to get key from password: ${err}`); - } - resolve(passwordDerivedKey); - }); - }); - }; - const keystore: lightwallet.keystore = await createVaultAsync(options); - const pwDerivedKey: Uint8Array = await deriveKeyFromPasswordAsync(keystore); - - // Generate 10 addresses - keystore.generateNewAddress(pwDerivedKey, DEFAULT_NUM_ACCOUNTS); - - ethLightwalletSubprovider = new EthLightwalletSubprovider(keystore, pwDerivedKey); - }); - describe('direct method calls', () => { - describe('success cases', () => { - it('returns a list of accounts', async () => { - const accounts = await ethLightwalletSubprovider.getAccountsAsync(); - expect(accounts[0]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_0); - expect(accounts[1]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_1); - expect(accounts.length).to.be.equal(DEFAULT_NUM_ACCOUNTS); - }); - it('signs a personal message hash', async () => { - const accounts = await ethLightwalletSubprovider.getAccountsAsync(); - const signingAccount = accounts[0]; - const data = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING)); - const ecSignatureHex = await ethLightwalletSubprovider.signPersonalMessageAsync(data, signingAccount); - expect(ecSignatureHex).to.be.equal(fixtureData.PERSONAL_MESSAGE_SIGNED_RESULT); - }); - it('signs a transaction', async () => { - const txHex = await ethLightwalletSubprovider.signTransactionAsync(fixtureData.TX_DATA); - expect(txHex).to.be.equal(fixtureData.TX_DATA_SIGNED_RESULT); - }); - it('signs an EIP712 sign typed data message', async () => { - const signature = await ethLightwalletSubprovider.signTypedDataAsync( - fixtureData.TEST_RPC_ACCOUNT_0, - fixtureData.EIP712_TEST_TYPED_DATA, - ); - expect(signature).to.be.equal(fixtureData.EIP712_TEST_TYPED_DATA_SIGNED_RESULT); - }); - }); - }); - describe('calls through a provider', () => { - let provider: Web3ProviderEngine; - before(() => { - provider = new Web3ProviderEngine(); - provider.addProvider(ethLightwalletSubprovider); - provider.addProvider(ganacheSubprovider); - providerUtils.startProviderEngine(provider); - }); - describe('success cases', () => { - it('returns a list of accounts', (done: DoneCallback) => { - const payload = { - jsonrpc: '2.0', - method: 'eth_accounts', - params: [], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result[0]).to.be.equal(fixtureData.TEST_RPC_ACCOUNT_0); - expect(response.result.length).to.be.equal(DEFAULT_NUM_ACCOUNTS); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('signs a personal message hash with eth_sign', (done: DoneCallback) => { - const data = ethUtils.bufferToHex(ethUtils.toBuffer(fixtureData.PERSONAL_MESSAGE_STRING)); - const account = fixtureData.TEST_RPC_ACCOUNT_0; - const payload = { - jsonrpc: '2.0', - method: 'eth_sign', - params: [account, data], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result).to.be.equal(fixtureData.PERSONAL_MESSAGE_SIGNED_RESULT); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('signs a transaction', (done: DoneCallback) => { - const payload = { - jsonrpc: '2.0', - method: 'eth_signTransaction', - params: [fixtureData.TX_DATA], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result.raw).to.be.equal(fixtureData.TX_DATA_SIGNED_RESULT); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('signs an EIP712 sign typed data message with eth_signTypedData', (done: DoneCallback) => { - const payload = { - jsonrpc: '2.0', - method: 'eth_signTypedData', - params: [fixtureData.TEST_RPC_ACCOUNT_0, fixtureData.EIP712_TEST_TYPED_DATA], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, response: JSONRPCResponsePayload) => { - expect(err).to.be.a('null'); - expect(response.result).to.be.equal(fixtureData.EIP712_TEST_TYPED_DATA_SIGNED_RESULT); - done(); - }); - provider.sendAsync(payload, callback); - }); - }); - describe('failure cases', () => { - it('should throw if `data` param not hex when calling eth_sign', (done: DoneCallback) => { - const nonHexMessage = 'hello world'; - const payload = { - jsonrpc: '2.0', - method: 'eth_sign', - params: [fixtureData.TEST_RPC_ACCOUNT_0, nonHexMessage], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, _response: JSONRPCResponsePayload) => { - expect(err).to.not.be.a('null'); - expect(err.message).to.be.equal('Expected data to be of type HexString, encountered: hello world'); - done(); - }); - provider.sendAsync(payload, callback); - }); - it('should throw if `data` param not hex when calling personal_sign', (done: DoneCallback) => { - const nonHexMessage = 'hello world'; - const payload = { - jsonrpc: '2.0', - method: 'personal_sign', - params: [nonHexMessage, fixtureData.TEST_RPC_ACCOUNT_0], - id: 1, - }; - const callback = reportCallbackErrors(done)((err: Error, _response: JSONRPCResponsePayload) => { - expect(err).to.not.be.a('null'); - expect(err.message).to.be.equal('Expected data to be of type HexString, encountered: hello world'); - done(); - }); - provider.sendAsync(payload, callback); - }); - }); - }); -}); diff --git a/packages/testnet-faucets/package.json b/packages/testnet-faucets/package.json index edc52a40c0..a5cec6ee4b 100644 --- a/packages/testnet-faucets/package.json +++ b/packages/testnet-faucets/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@0x/testnet-faucets", - "version": "1.0.83", + "version": "1.0.84", "engines": { "node": ">=6.12" }, @@ -19,13 +19,14 @@ "author": "Fabio Berger", "license": "Apache-2.0", "dependencies": { - "0x.js": "^6.0.12", - "@0x/subproviders": "^4.1.1", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", + "0x.js": "^6.0.15", + "@0x/contract-wrappers": "^11.0.0", + "@0x/subproviders": "^5.0.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", "body-parser": "^1.17.1", - "ethereum-types": "^2.1.3", + "ethereum-types": "^2.1.4", "ethereumjs-tx": "^1.3.5", "ethereumjs-util": "^5.1.1", "express": "^4.15.2", diff --git a/packages/testnet-faucets/src/ts/dispense_asset_tasks.ts b/packages/testnet-faucets/src/ts/dispense_asset_tasks.ts index 23dfc0db99..e66e51fe74 100644 --- a/packages/testnet-faucets/src/ts/dispense_asset_tasks.ts +++ b/packages/testnet-faucets/src/ts/dispense_asset_tasks.ts @@ -1,4 +1,4 @@ -import { ERC20TokenWrapper } from '0x.js'; +import { ERC20TokenContract, SupportedProvider } from '0x.js'; import { BigNumber, logUtils } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import * as _ from 'lodash'; @@ -37,7 +37,7 @@ export const dispenseAssetTasks = { recipientAddress: string, tokenSymbol: string, networkId: number, - erc20TokenWrapper: ERC20TokenWrapper, + provider: SupportedProvider, ): AsyncTask { return async () => { logUtils.log(`Processing ${tokenSymbol} ${recipientAddress}`); @@ -47,10 +47,8 @@ export const dispenseAssetTasks = { throw new Error(`Unsupported asset type: ${tokenSymbol}`); } const baseUnitAmount = Web3Wrapper.toBaseUnitAmount(amountToDispense, tokenIfExists.decimals); - const userBalanceBaseUnits = await erc20TokenWrapper.getBalanceAsync( - tokenIfExists.address, - recipientAddress, - ); + const erc20Token = new ERC20TokenContract(tokenIfExists.address, provider); + const userBalanceBaseUnits = await erc20Token.balanceOf.callAsync(recipientAddress); const maxAmountBaseUnits = Web3Wrapper.toBaseUnitAmount( new BigNumber(DISPENSE_MAX_AMOUNT_TOKEN), tokenIfExists.decimals, @@ -61,12 +59,9 @@ export const dispenseAssetTasks = { ); return; } - const txHash = await erc20TokenWrapper.transferAsync( - tokenIfExists.address, - configs.DISPENSER_ADDRESS, - recipientAddress, - baseUnitAmount, - ); + const txHash = await erc20Token.transfer.sendTransactionAsync(recipientAddress, baseUnitAmount, { + from: configs.DISPENSER_ADDRESS, + }); logUtils.log(`Sent ${amountToDispense} ${tokenSymbol} to ${recipientAddress} tx: ${txHash}`); }; }, diff --git a/packages/testnet-faucets/src/ts/handler.ts b/packages/testnet-faucets/src/ts/handler.ts index 08f3270d22..fafc1dad1c 100644 --- a/packages/testnet-faucets/src/ts/handler.ts +++ b/packages/testnet-faucets/src/ts/handler.ts @@ -124,7 +124,7 @@ export class Handler { recipient, requestedAssetType, networkConfig.networkId, - networkConfig.contractWrappers.erc20Token, + networkConfig.contractWrappers.getProvider(), ); break; default: diff --git a/packages/types/CHANGELOG.json b/packages/types/CHANGELOG.json index 2dda41a7a3..b2b07e836c 100644 --- a/packages/types/CHANGELOG.json +++ b/packages/types/CHANGELOG.json @@ -1,6 +1,6 @@ [ { - "version": "2.4.1", + "version": "2.4.2", "changes": [ { "note": "Add `OrderStatus` type", @@ -12,6 +12,15 @@ } ] }, + { + "timestamp": 1563957393, + "version": "2.4.1", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "2.4.0", "changes": [ diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index c0f9860c5c..617b9d8055 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.4.1 - _July 24, 2019_ + + * Dependencies updated + ## v2.4.0 - _July 13, 2019_ * Add MarketOperation type (#1914) diff --git a/packages/types/package.json b/packages/types/package.json index 524d35012e..3fd92b807e 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@0x/types", - "version": "2.4.0", + "version": "2.4.1", "engines": { "node": ">=6.12" }, @@ -32,7 +32,7 @@ "dependencies": { "@types/node": "*", "bignumber.js": "~8.0.2", - "ethereum-types": "^2.1.3" + "ethereum-types": "^2.1.4" }, "publishConfig": { "access": "public" diff --git a/packages/typescript-typings/CHANGELOG.json b/packages/typescript-typings/CHANGELOG.json index 04fe93427d..f134b9d0c7 100644 --- a/packages/typescript-typings/CHANGELOG.json +++ b/packages/typescript-typings/CHANGELOG.json @@ -8,6 +8,15 @@ } ] }, + { + "timestamp": 1563957393, + "version": "4.2.4", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "timestamp": 1563006338, "version": "4.2.3", diff --git a/packages/typescript-typings/CHANGELOG.md b/packages/typescript-typings/CHANGELOG.md index 44b082e4d8..531117d146 100644 --- a/packages/typescript-typings/CHANGELOG.md +++ b/packages/typescript-typings/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v4.2.4 - _July 24, 2019_ + + * Dependencies updated + ## v4.2.3 - _July 13, 2019_ * Dependencies updated diff --git a/packages/typescript-typings/package.json b/packages/typescript-typings/package.json index bbeffdd84d..51f0fd544a 100644 --- a/packages/typescript-typings/package.json +++ b/packages/typescript-typings/package.json @@ -1,6 +1,6 @@ { "name": "@0x/typescript-typings", - "version": "4.2.3", + "version": "4.2.4", "engines": { "node": ">=6.12" }, @@ -27,7 +27,7 @@ "@types/bn.js": "^4.11.0", "@types/react": "*", "bignumber.js": "~8.0.2", - "ethereum-types": "^2.1.3", + "ethereum-types": "^2.1.4", "popper.js": "1.14.3" }, "devDependencies": { diff --git a/packages/utils/CHANGELOG.json b/packages/utils/CHANGELOG.json index 7ed47a6ffc..68fdaa241f 100644 --- a/packages/utils/CHANGELOG.json +++ b/packages/utils/CHANGELOG.json @@ -5,6 +5,33 @@ { "note": "Add `SafeMathRevertErrors.SafeMathErrorCodes.Uint256DivisionByZero`", "pr": 2031 + }, + { + "note": "Updated to include `strictDecode` for decoding method arguments", + "pr": 2018 + }, + { + "note": "Throw exception when trying to decode beyond boundaries of calldata", + "pr": 2018 + } + ], + "timestamp": 1565296576 + }, + { + "timestamp": 1564604963, + "version": "4.4.2", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1563957393, + "version": "4.4.1", + "changes": [ + { + "note": "Dependencies updated" } ] }, diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md index 15a3cee1ce..1f6bb88465 100644 --- a/packages/utils/CHANGELOG.md +++ b/packages/utils/CHANGELOG.md @@ -5,6 +5,19 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v4.5.0 - _August 8, 2019_ + + * Updated to include `strictDecode` for decoding method arguments (#2018) + * Throw exception when trying to decode beyond boundaries of calldata (#2018) + +## v4.4.2 - _July 31, 2019_ + + * Dependencies updated + +## v4.4.1 - _July 24, 2019_ + + * Dependencies updated + ## v4.4.0 - _July 13, 2019_ * Add function deleteNestedProperty (#1842) diff --git a/packages/utils/package.json b/packages/utils/package.json index 9807f58f6d..553cac8694 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@0x/utils", - "version": "4.4.0", + "version": "4.5.0", "engines": { "node": ">=6.12" }, @@ -32,27 +32,27 @@ "@0x/tslint-config": "^3.0.1", "@types/detect-node": "2.0.0", "@types/lodash": "4.14.104", - "@types/mocha": "^2.2.42", + "@types/mocha": "^5.2.7", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^3.0.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", "tslint": "5.11.0", "typescript": "3.0.1" }, "dependencies": { - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", "@types/node": "*", "abortcontroller-polyfill": "^1.1.9", "bignumber.js": "~8.0.2", "chalk": "^2.3.0", "detect-node": "2.0.3", - "ethereum-types": "^2.1.3", + "ethereum-types": "^2.1.4", "ethereumjs-util": "^5.1.1", "ethers": "~4.0.4", "isomorphic-fetch": "2.2.1", diff --git a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts index 3b90a71741..3a591bd774 100644 --- a/packages/utils/src/abi_encoder/calldata/raw_calldata.ts +++ b/packages/utils/src/abi_encoder/calldata/raw_calldata.ts @@ -31,8 +31,13 @@ export class RawCalldata { } public popBytes(lengthInBytes: number): Buffer { - const value = this._value.slice(this._offset, this._offset + lengthInBytes); - this.setOffset(this._offset + lengthInBytes); + const popBegin = this._offset; + const popEnd = popBegin + lengthInBytes; + if (popEnd > this._value.byteLength) { + throw new Error(`Tried to decode beyond the end of calldata`); + } + const value = this._value.slice(popBegin, popEnd); + this.setOffset(popEnd); return value; } diff --git a/packages/utils/src/abi_encoder/evm_data_types/method.ts b/packages/utils/src/abi_encoder/evm_data_types/method.ts index 93746fa002..803fe77d89 100644 --- a/packages/utils/src/abi_encoder/evm_data_types/method.ts +++ b/packages/utils/src/abi_encoder/evm_data_types/method.ts @@ -34,6 +34,19 @@ export class MethodDataType extends AbstractSetDataType { return value; } + public strictDecode(calldata: string, rules?: DecodingRules): T { + const value = super.decode(calldata, rules, this._methodSelector); + const valueAsArray: any = _.isObject(value) ? _.values(value) : [value]; + switch (valueAsArray.length) { + case 0: + return undefined as any; + case 1: + return valueAsArray[0]; + default: + return valueAsArray; + } + } + public encodeReturnValues(value: any, rules?: EncodingRules): string { const returnData = this._returnDataType.encode(value, rules); return returnData; diff --git a/packages/utils/test/abi_encoder/evm_data_types_test.ts b/packages/utils/test/abi_encoder/evm_data_types_test.ts index 94fc340f7d..9271abb263 100644 --- a/packages/utils/test/abi_encoder/evm_data_types_test.ts +++ b/packages/utils/test/abi_encoder/evm_data_types_test.ts @@ -800,6 +800,19 @@ describe('ABI Encoder: EVM Data Type Encoding/Decoding', () => { const decodedArgs = dataType.decode(nullEncodedArgs); expect(decodedArgs).to.be.deep.equal(args); }); + it('Should fail to decode if not enough bytes in calldata', async () => { + // Create DataType object + const testDataItem = { name: 'Integer (256)', type: 'int' }; + const dataType = new AbiEncoder.Int(testDataItem); + const args = new BigNumber(0); + const encodedArgs = dataType.encode(args, encodingRules); + const truncatedCalldataLength = 60; + const encodedArgsTruncated = encodedArgs.substr(0, truncatedCalldataLength); + // Encode Args and validate result + expect(() => { + dataType.decode(encodedArgsTruncated); + }).to.throw(); + }); }); describe('Unsigned Integer', () => { diff --git a/packages/utils/test/abi_encoder/methods_test.ts b/packages/utils/test/abi_encoder/methods_test.ts index d8045fece9..4f9b2d94d1 100644 --- a/packages/utils/test/abi_encoder/methods_test.ts +++ b/packages/utils/test/abi_encoder/methods_test.ts @@ -1,4 +1,5 @@ import * as chai from 'chai'; +import * as _ from 'lodash'; import 'mocha'; import { AbiEncoder, BigNumber } from '../../src/'; @@ -10,130 +11,114 @@ chaiSetup.configure(); const expect = chai.expect; describe('ABI Encoder: Method Encoding / Decoding', () => { - const encodingRules: AbiEncoder.EncodingRules = { shouldOptimize: false }; // optimizer is tested separately. - it('Types with default widths', async () => { - // Generate calldata - const method = new AbiEncoder.Method(AbiSamples.typesWithDefaultWidthsAbi); - const args = [new BigNumber(1), new BigNumber(-1), '0x56', [new BigNumber(1)], [new BigNumber(-1)], ['0x56']]; - const calldata = method.encode(args, encodingRules); - // Validate calldata - const expectedCalldata = - '0x09f2b0c30000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000015600000000000000000000000000000000000000000000000000000000000000'; - expect(calldata).to.be.equal(expectedCalldata); + const defaultEncodingRules: AbiEncoder.EncodingRules = { shouldOptimize: false }; // optimizer is tested separately. + const defaultDecodingRules: AbiEncoder.DecodingRules = { shouldConvertStructsToObjects: false }; + const runTest = ( + encoder: AbiEncoder.Method, + methodArgs: any, + expectedEncoding: string, + encodingRules: AbiEncoder.EncodingRules = defaultEncodingRules, + decodingRules: AbiEncoder.DecodingRules = defaultDecodingRules, + ) => { + // Validate encoding + // note - the encoder takes an array of parameters as input; + // if there is only 1 parameter then we wrap it in an array (`methodArgsAsAray`) to save code. + const methodArgsAsArray = (encoder.getDataItem().components as any).length > 1 ? methodArgs : [methodArgs]; + const encoding = encoder.encode(methodArgsAsArray, encodingRules); + expect(encoding, 'testing `.encode`').to.be.equal(expectedEncoding); // Validate decoding - const decodingRules = { shouldConvertStructsToObjects: false }; - const decodedValue = method.decode(calldata, decodingRules); - expect(decodedValue).to.be.deep.equal(args); + const decodedValue = encoder.decode(encoding, decodingRules); + const decodedValueAsArray = _.isArray(decodedValue) ? decodedValue : _.toArray(decodedValue); + expect(decodedValueAsArray, 'testing `.decode`').to.be.deep.equal(methodArgsAsArray); + // Validate strict decoding + const strictDecodedValue = encoder.strictDecode(encoding, decodingRules); + expect(strictDecodedValue, 'testing `.strictDecode`').to.be.deep.equal(methodArgs); + }; + it('Types with default widths', async () => { + const method = new AbiEncoder.Method(AbiSamples.typesWithDefaultWidthsAbi); + const methodArgs = [ + new BigNumber(1), + new BigNumber(-1), + '0x56', + [new BigNumber(1)], + [new BigNumber(-1)], + ['0x56'], + ]; + const expectedEncoding = + '0x09f2b0c30000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000015600000000000000000000000000000000000000000000000000000000000000'; + runTest(method, methodArgs, expectedEncoding); }); it('Array of Static Tuples (Array has defined length)', async () => { - // Generate calldata const method = new AbiEncoder.Method(AbiSamples.arrayOfStaticTuplesWithDefinedLengthAbi); let value = 0; - const arrayOfTuples = []; - const arrayOfTuplesLength = 8; - for (let i = 0; i < arrayOfTuplesLength; ++i) { - arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value)]); + const methodArgs = []; + const methodArgsLength = 8; + for (let i = 0; i < methodArgsLength; ++i) { + methodArgs.push([new BigNumber(++value), new BigNumber(++value)]); } - const args = [arrayOfTuples]; - const calldata = method.encode(args, encodingRules); - // Validate calldata - const expectedCalldata = + const expectedEncoding = '0x9eb20969000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010'; - expect(calldata).to.be.equal(expectedCalldata); - // Validate decoding - const decodingRules = { shouldConvertStructsToObjects: false }; - const decodedValue = method.decode(calldata, decodingRules); - expect(decodedValue).to.be.deep.equal(args); + runTest(method, methodArgs, expectedEncoding); }); it('Array of Static Tuples (Array has dynamic length)', async () => { - // Generate calldata const method = new AbiEncoder.Method(AbiSamples.arrayOfStaticTuplesWithDynamicLengthAbi); let value = 0; - const arrayOfTuples = []; - const arrayOfTuplesLength = 8; - for (let i = 0; i < arrayOfTuplesLength; ++i) { - arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value)]); + const methodArgs = []; + const methodArgsLength = 8; + for (let i = 0; i < methodArgsLength; ++i) { + methodArgs.push([new BigNumber(++value), new BigNumber(++value)]); } - const args = [arrayOfTuples]; - const calldata = method.encode(args, encodingRules); - // Validate calldata - const expectedCalldata = + const expectedEncoding = '0x63275d6e00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010'; - expect(calldata).to.be.equal(expectedCalldata); - // Validate decoding - const decodingRules = { shouldConvertStructsToObjects: false }; - const decodedValue = method.decode(calldata, decodingRules); - expect(decodedValue).to.be.deep.equal(args); + runTest(method, methodArgs, expectedEncoding); }); it('Array of Dynamic Tuples (Array has defined length)', async () => { - // Generate Calldata const method = new AbiEncoder.Method(AbiSamples.arrayOfDynamicTuplesWithDefinedLengthAbi); let value = 0; - const arrayOfTuples = []; - const arrayOfTuplesLength = 8; - for (let i = 0; i < arrayOfTuplesLength; ++i) { - arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value).toString()]); + const methodArgs = []; + const methodArgsLength = 8; + for (let i = 0; i < methodArgsLength; ++i) { + methodArgs.push([new BigNumber(++value), new BigNumber(++value).toString()]); } - const args = [arrayOfTuples]; - const calldata = method.encode(args, encodingRules); - // Validate calldata - const expectedCalldata = + const expectedEncoding = '0xdeedb00f00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000'; - expect(calldata).to.be.equal(expectedCalldata); - // Validate decoding - const decodingRules = { shouldConvertStructsToObjects: false }; - const decodedValue = method.decode(calldata, decodingRules); - expect(decodedValue).to.be.deep.equal(args); + runTest(method, methodArgs, expectedEncoding); }); it('Array of Dynamic Tuples (Array has dynamic length)', async () => { - // Generate calldata const method = new AbiEncoder.Method(AbiSamples.arrayOfDynamicTuplesWithUndefinedLengthAbi); let value = 0; - const arrayOfTuples = []; - const arrayOfTuplesLength = 8; - for (let i = 0; i < arrayOfTuplesLength; ++i) { - arrayOfTuples.push([new BigNumber(++value), new BigNumber(++value).toString()]); + const methodArgs = []; + const methodArgsLength = 8; + for (let i = 0; i < methodArgsLength; ++i) { + methodArgs.push([new BigNumber(++value), new BigNumber(++value).toString()]); } - const args = [arrayOfTuples]; - const calldata = method.encode(args, encodingRules); - // Validate calldata - const expectedCalldata = + const expectedEncoding = '0x60c847fb000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000013400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023132000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000023136000000000000000000000000000000000000000000000000000000000000'; - expect(calldata).to.be.equal(expectedCalldata); - // Validate decoding - const decodingRules = { shouldConvertStructsToObjects: false }; - const decodedValue = method.decode(calldata, decodingRules); - expect(decodedValue).to.be.deep.equal(args); + runTest(method, methodArgs, expectedEncoding); }); it('Multidimensional Arrays / Static Members', async () => { - // Generate calldata const method = new AbiEncoder.Method(AbiSamples.multiDimensionalArraysStaticTypeAbi); // Eight 3-dimensional arrays of uint8[2][2][2] let value = 0; - const args = []; - const argsLength = 8; - for (let i = 0; i < argsLength; ++i) { - args.push([[[++value, ++value], [++value, ++value]], [[++value, ++value], [++value, ++value]]]); + const methodArgs = []; + const methodArgsLength = 8; + for (let i = 0; i < methodArgsLength; ++i) { + methodArgs.push([[[++value, ++value], [++value, ++value]], [[++value, ++value], [++value, ++value]]]); } - const calldata = method.encode(args, encodingRules); // Validate calldata - const expectedCalldata = + const expectedEncoding = '0xc2f47d6f00000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000d400000000000000000000000000000000000000000000000000000000000000e600000000000000000000000000000000000000000000000000000000000000039000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001500000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000019000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000025000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000027000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000029000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002f0000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000003100000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000033000000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000038'; - expect(calldata).to.be.equal(expectedCalldata); - // Validate decoding - const decodingRules = { shouldConvertStructsToObjects: false }; - const decodedValue = method.decode(calldata, decodingRules); - expect(decodedValue).to.be.deep.equal(args); + runTest(method, methodArgs, expectedEncoding); }); + it('Multidimensional Arrays / Dynamic Members', async () => { - // Generate calldata const method = new AbiEncoder.Method(AbiSamples.multiDimensionalArraysDynamicTypeAbi); // Eight 3-dimensional arrays of string[2][2][2] let value = 0; - const args = []; - const argsLength = 4; - for (let i = 0; i < argsLength; ++i) { - args.push([ + const methodArgs = []; + const methodArgsLength = 4; + for (let i = 0; i < methodArgsLength; ++i) { + methodArgs.push([ [ [new BigNumber(++value).toString(), new BigNumber(++value).toString()], [new BigNumber(++value).toString(), new BigNumber(++value).toString()], @@ -144,153 +129,78 @@ describe('ABI Encoder: Method Encoding / Decoding', () => { ], ]); } - const calldata = method.encode(args, encodingRules); - // Validate calldata - const expectedCalldata = + const expectedEncoding = '0x81534ebd0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000052000000000000000000000000000000000000000000000000000000000000009a00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000013300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000137000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023131000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000231320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002313300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023134000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000231370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002313800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023139000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000023231000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023234000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000232370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002323800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002323900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002333100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023332000000000000000000000000000000000000000000000000000000000000'; - expect(calldata).to.be.equal(expectedCalldata); - // Validate decoding - const decodingRules = { shouldConvertStructsToObjects: false }; - const decodedValue = method.decode(calldata, decodingRules); - expect(decodedValue).to.be.deep.equal(args); + runTest(method, methodArgs, expectedEncoding); }); it('Fixed Length Array / Dynamic Members', async () => { - // Generate calldata const method = new AbiEncoder.Method(AbiSamples.staticArrayDynamicMembersAbi); - const args = [['Brave', 'New', 'World']]; - const calldata = method.encode(args, encodingRules); - // Validate calldata - const expectedCalldata = + const methodArgs = ['Brave', 'New', 'World']; + const expectedEncoding = '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000'; - expect(calldata).to.be.equal(expectedCalldata); - // Validate decoding - const decodingRules = { shouldConvertStructsToObjects: false }; - const decodedValue = method.decode(calldata, decodingRules); - expect(decodedValue).to.be.deep.equal(args); + runTest(method, methodArgs, expectedEncoding); }); it('Fixed Length Array / Dynamic Members', async () => { - // Generaet calldata const method = new AbiEncoder.Method(AbiSamples.staticArrayDynamicMembersAbi); - const args = [['Brave', 'New', 'World']]; - const calldata = method.encode(args, encodingRules); - // Validate calldata - const expectedCalldata = + const methodArgs = ['Brave', 'New', 'World']; + const expectedEncoding = '0x243a6e6e0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000'; - expect(calldata).to.be.equal(expectedCalldata); - // Validate decoding - const decodingRules = { shouldConvertStructsToObjects: false }; - const decodedValue = method.decode(calldata, decodingRules); - expect(decodedValue).to.be.deep.equal(args); + runTest(method, methodArgs, expectedEncoding); }); it('Unfixed Length Array / Dynamic Members ABI', async () => { - // Generate calldata const method = new AbiEncoder.Method(AbiSamples.dynamicArrayDynamicMembersAbi); - const args = [['Brave', 'New', 'World']]; - const calldata = method.encode(args, encodingRules); - // Validate calldata - const expectedCalldata = + const methodArgs = ['Brave', 'New', 'World']; + const expectedEncoding = '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005427261766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e657700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000'; - expect(calldata).to.be.equal(expectedCalldata); - // Validate decoding - const decodingRules = { shouldConvertStructsToObjects: false }; - const decodedValue = method.decode(calldata, decodingRules); - expect(decodedValue).to.be.deep.equal(args); + runTest(method, methodArgs, expectedEncoding); }); it('Unfixed Length Array / Static Members ABI', async () => { - // Generate calldata const method = new AbiEncoder.Method(AbiSamples.dynamicArrayStaticMembersAbi); - // tslint:disable custom-no-magic-numbers - const args = [[127, 14, 54]]; - // tslint:enable custom-no-magic-numbers - const calldata = method.encode(args, encodingRules); - // Validate calldata - const expectedCalldata = + // tslint:disable-next-line custom-no-magic-numbers + const methodArgs = [127, 14, 54]; + const expectedEncoding = '0x4fc8a83300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036'; - expect(calldata).to.be.equal(expectedCalldata); - // Validate decoding - const decodingRules = { shouldConvertStructsToObjects: false }; - const decodedValue = method.decode(calldata, decodingRules); - expect(decodedValue).to.be.deep.equal(args); + runTest(method, methodArgs, expectedEncoding); }); it('Fixed Length Array / Static Members ABI', async () => { - // Generate calldata const method = new AbiEncoder.Method(AbiSamples.staticArrayAbi); - // tslint:disable custom-no-magic-numbers - const args = [[127, 14, 54]]; - // tslint:enable custom-no-magic-numbers - const calldata = method.encode(args, encodingRules); - // Validate calldata - const expectedCalldata = + // tslint:disable-next-line custom-no-magic-numbers + const methodArgs = [127, 14, 54]; + const expectedEncoding = '0xf68ade72000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036'; - expect(calldata).to.be.equal(expectedCalldata); - // Validate decoding - const decodingRules = { shouldConvertStructsToObjects: false }; - const decodedValue = method.decode(calldata, decodingRules); - expect(decodedValue).to.be.deep.equal(args); + runTest(method, methodArgs, expectedEncoding); }); it('Array ABI', async () => { - // Generate calldata const method = new AbiEncoder.Method(AbiSamples.stringAbi); - const args = [['five', 'six', 'seven']]; - const calldata = method.encode(args, encodingRules); - // Validate calldata - const expectedCalldata = + const methodArgs = ['five', 'six', 'seven']; + const expectedEncoding = '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000373697800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005736576656e000000000000000000000000000000000000000000000000000000'; - expect(calldata).to.be.equal(expectedCalldata); - // Validate decoding - const decodingRules = { shouldConvertStructsToObjects: false }; - const decodedValue = method.decode(calldata, decodingRules); - expect(decodedValue).to.be.deep.equal(args); + runTest(method, methodArgs, expectedEncoding); }); it('Static Tuple', async () => { - // Generate calldata - // This is dynamic because it has dynamic members const method = new AbiEncoder.Method(AbiSamples.staticTupleAbi); - const args = [[new BigNumber(5), new BigNumber(10), new BigNumber(15), false]]; - const calldata = method.encode(args, encodingRules); - // Validate calldata - const expectedCalldata = + const methodArgs = [new BigNumber(5), new BigNumber(10), new BigNumber(15), false]; + const expectedEncoding = '0xa9125e150000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000000'; - expect(calldata).to.be.equal(expectedCalldata); - // Validate decoding - const decodingRules = { shouldConvertStructsToObjects: false }; - const decodedValue = method.decode(calldata, decodingRules); - expect(decodedValue).to.be.deep.equal(args); + runTest(method, methodArgs, expectedEncoding); }); it('Dynamic Tuple (Array input)', async () => { - // Generate calldata - // This is dynamic because it has dynamic members const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi); - const args = [[new BigNumber(5), 'five']]; - const calldata = method.encode(args, encodingRules); - // Validate calldata - const expectedCalldata = + const methodArgs = [new BigNumber(5), 'five']; + const expectedEncoding = '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000'; - expect(calldata).to.be.equal(expectedCalldata); - // Validate decoding - const decodingRules = { shouldConvertStructsToObjects: false }; - const decodedValue = method.decode(calldata, decodingRules); - expect(decodedValue).to.be.deep.equal(args); + runTest(method, methodArgs, expectedEncoding); }); it('Dynamic Tuple (Object input)', async () => { - // Generate Calldata - // This is dynamic because it has dynamic members const method = new AbiEncoder.Method(AbiSamples.dynamicTupleAbi); - const args = [[new BigNumber(5), 'five']]; - const calldata = method.encode(args, encodingRules); - // Validate calldata - const expectedCalldata = + const methodArgs = [new BigNumber(5), 'five']; + const expectedEncoding = '0x5b998f3500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000046669766500000000000000000000000000000000000000000000000000000000'; - expect(calldata).to.be.equal(expectedCalldata); - // Validate decoding - const decodingRules = { shouldConvertStructsToObjects: false }; - const decodedValue = method.decode(calldata, decodingRules); - expect(decodedValue).to.be.deep.equal(args); + runTest(method, methodArgs, expectedEncoding); }); it('Large, Flat ABI', async () => { - // Construct calldata const method = new AbiEncoder.Method(AbiSamples.largeFlatAbi); - const args = [ + const methodArgs = [ new BigNumber(256745454), new BigNumber(-256745454), new BigNumber(434244), @@ -301,15 +211,9 @@ describe('ABI Encoder: Method Encoding / Decoding', () => { '0xe41d2489571d322189246dafa5ebde1f4699f498', true, ]; - // Validate calldata - const calldata = method.encode(args, encodingRules); - const expectedCalldata = + const expectedEncoding = '0x312d4d42000000000000000000000000000000000000000000000000000000000f4d9feefffffffffffffffffffffffffffffffffffffffffffffffffffffffff0b26012000000000000000000000000000000000000000000000000000000000006a0444300000000000000000000000000000000000000000000000000000000000000000102030405060708091112131415161718192021222324252627282930313200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000180000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f4980000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000003800010203040506070809111213141516171819202122232425262728293031320809111213141516171819202122232425262728293031320000000000000000000000000000000000000000000000000000000000000000000000000000002c4c6974746c65207065746572207069706572207069706564206120706970696e672070657070657220706f740000000000000000000000000000000000000000'; - expect(calldata).to.be.equal(expectedCalldata); - // Validate decoding - const decodingRules = { shouldConvertStructsToObjects: false }; - const decodedValue = method.decode(calldata, decodingRules); - expect(decodedValue).to.be.deep.equal(args); + runTest(method, methodArgs, expectedEncoding); }); it('Large, Nested ABI', async () => { // Construct Calldata @@ -364,7 +268,7 @@ describe('ABI Encoder: Method Encoding / Decoding', () => { someAddress: '0x89571d322189e415ebde1f4699f498d24246dafa', }; const someArrayOfTuplesWithDynamicTypes = [someTupleWithDynamicTypes2, someTupleWithDynamicTypes3]; - const args = { + const methodArgs = [ someStaticArray, someStaticArrayWithDynamicMembers, someDynamicArrayWithDynamicMembers, @@ -372,14 +276,26 @@ describe('ABI Encoder: Method Encoding / Decoding', () => { someTuple, someTupleWithDynamicTypes, someArrayOfTuplesWithDynamicTypes, - }; - const calldata = method.encode(args, encodingRules); - // Validate calldata - const expectedCalldata = + ]; + const expectedEncoding = '0x4b49031c000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000009800000000000000000000000000000000000000000000000000000000000000ae0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000163874563783498732482743928742389723894723984700000000000000000000000000000000000000000000000000000000000000000000000000000000006e72834723982374239847239847298472489274987489742847289472394874987498478743294237434923473298472398423748923748923748923472389472894789474893742894728947389427498237432987423894723894732894723894372498237498237428934723980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000027283473298473248923749238742398742398472894729843278942374982374892374892743982000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000b736f6d6520737472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013736f6d6520616e6f7468657220737472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024746865726520617265206a75737420746f6f206d616e7920737472696e6773757020696e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002079616c6c2067686f6e6e61206d616b65206d65206c6f7365206d79206d696e640000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000034746865206c6974746c6520706970696e67207069706572207069706564206120706970696e6720706970706572207061707065720000000000000000000000000000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0ac511500000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000081746865206b6964206b6e6f777320686f7720746f20777269746520706f656d732c20776861742063616e204920736179202d2d2049206775657373207468657265732061206c6f74204920636f756c642073617920746f2074727920746f2066696c6c2074686973206c696e6520776974682061206c6f74206f6620746578742e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003d69d500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000e41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000000000000000000000000000000000000000004e616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894723843743289742389472398473289472348927489274894738427428947389facdea0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000089b51500000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000746dafa5ebde1f4699f4981d3221892e41d24895000000000000000000000000000000000000000000000000000000000000004e6b73646873616a6b646873616a6b646861646a6b617368646a6b73616468616a6b646873616a6b64687361646a6b616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002829384723894398473289472348927489272384374328974238947274894738427428947389facde100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fa3150000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000010000000000000000000000000089571d322189e415ebde1f4699f498d24246dafa000000000000000000000000000000000000000000000000000000000000004e73646873616a6b646873616a6b646861646a6b617368646a616b64686a61736a6b646861736a6b6c647368646a6168646b6a73616864616a6b6b73616468616a6b646873616a6b64687361646a6b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002838947238437432829384729742389472398473289472348927489274894738427428947389facdef000000000000000000000000000000000000000000000000'; - expect(calldata).to.be.equal(expectedCalldata); - // Validate decoding - const decodedValue = method.decode(calldata, { shouldConvertStructsToObjects: true }); - expect(decodedValue).to.be.deep.equal(args); + const customDecodingRules = { shouldConvertStructsToObjects: true }; // custom to improve readability + runTest(method, methodArgs, expectedEncoding, defaultEncodingRules, customDecodingRules); + }); + it('Should throw if decoding calldata where selector does not match the method', async () => { + const method = AbiEncoder.createMethod('foobar'); + const methodSelector = method.getSelector(); + const badMethodSelector = '0x01020304'; + expect(() => method.decode(badMethodSelector)).to.throw( + `Tried to decode calldata, but it was missing the function selector. Expected prefix '${methodSelector}'. Got '${badMethodSelector}'.`, + ); + }); + it('Should throw if strict decoding calldata where selector does not match the method', async () => { + const method = AbiEncoder.createMethod('foobar'); + const methodSelector = method.getSelector(); + const badMethodSelector = '0x01020304'; + expect(() => method.strictDecode(badMethodSelector)).to.throw( + `Tried to decode calldata, but it was missing the function selector. Expected prefix '${methodSelector}'. Got '${badMethodSelector}'.`, + ); }); }); diff --git a/packages/web3-wrapper/CHANGELOG.json b/packages/web3-wrapper/CHANGELOG.json index 3f0339e941..b8711afe25 100644 --- a/packages/web3-wrapper/CHANGELOG.json +++ b/packages/web3-wrapper/CHANGELOG.json @@ -1,6 +1,6 @@ [ { - "version": "6.0.9", + "version": "6.0.11", "changes": [ { "note": "Let `toBaseUnitAmount()` accept a `number`", @@ -8,6 +8,24 @@ } ] }, + { + "timestamp": 1565296576, + "version": "6.0.10", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { + "timestamp": 1564604963, + "version": "6.0.9", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, { "version": "6.0.8", "changes": [ @@ -15,7 +33,8 @@ "note": "re-export new ethereum-types types, TupleDataItem", "pr": 1919 } - ] + ], + "timestamp": 1563957393 }, { "timestamp": 1563006338, diff --git a/packages/web3-wrapper/CHANGELOG.md b/packages/web3-wrapper/CHANGELOG.md index 115c5b164f..83706cbdea 100644 --- a/packages/web3-wrapper/CHANGELOG.md +++ b/packages/web3-wrapper/CHANGELOG.md @@ -5,6 +5,18 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v6.0.10 - _August 8, 2019_ + + * Dependencies updated + +## v6.0.9 - _July 31, 2019_ + + * Dependencies updated + +## v6.0.8 - _July 24, 2019_ + + * re-export new ethereum-types types, TupleDataItem (#1919) + ## v6.0.7 - _July 13, 2019_ * Dependencies updated diff --git a/packages/web3-wrapper/package.json b/packages/web3-wrapper/package.json index c1ffef9166..446bc2cd86 100644 --- a/packages/web3-wrapper/package.json +++ b/packages/web3-wrapper/package.json @@ -1,6 +1,6 @@ { "name": "@0x/web3-wrapper", - "version": "6.0.7", + "version": "6.0.10", "engines": { "node": ">=6.12" }, @@ -39,13 +39,14 @@ "devDependencies": { "@0x/tslint-config": "^3.0.1", "@types/lodash": "4.14.104", + "@types/mocha": "^5.2.7", "chai": "^4.0.1", "chai-as-promised": "^7.1.0", "chai-bignumber": "^3.0.0", "dirty-chai": "^2.0.1", - "ganache-core": "^2.5.3", + "ganache-core": "^2.6.0", "make-promises-safe": "^1.1.0", - "mocha": "^4.1.0", + "mocha": "^6.2.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "shx": "^0.2.2", @@ -54,11 +55,11 @@ "typescript": "3.0.1" }, "dependencies": { - "@0x/assert": "^2.1.0", - "@0x/json-schemas": "^3.0.11", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "ethereum-types": "^2.1.3", + "@0x/assert": "^2.1.3", + "@0x/json-schemas": "^3.1.13", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "ethereum-types": "^2.1.4", "ethereumjs-util": "^5.1.1", "ethers": "~4.0.4", "lodash": "^4.17.11" diff --git a/packages/web3-wrapper/test/web3_wrapper_test.ts b/packages/web3-wrapper/test/web3_wrapper_test.ts index 45bee95e07..7bdce5d059 100644 --- a/packages/web3-wrapper/test/web3_wrapper_test.ts +++ b/packages/web3-wrapper/test/web3_wrapper_test.ts @@ -35,7 +35,7 @@ describe('Web3Wrapper tests', () => { describe('#getNodeVersionAsync', () => { it('gets the node version', async () => { const nodeVersion = await web3Wrapper.getNodeVersionAsync(); - const NODE_VERSION = 'EthereumJS TestRPC/v2.5.3/ethereum-js'; + const NODE_VERSION = 'EthereumJS TestRPC/v2.6.0/ethereum-js'; expect(nodeVersion).to.be.equal(NODE_VERSION); }); }); diff --git a/packages/website/md/docs/asset_swapper/installation.md b/packages/website/md/docs/asset_swapper/installation.md new file mode 100644 index 0000000000..113590ac84 --- /dev/null +++ b/packages/website/md/docs/asset_swapper/installation.md @@ -0,0 +1,18 @@ +#### Install + +```bash +yarn add @0x/asset-swapper +``` + +#### Import + +```javascript +import { SwapQuoter, SwapQuoteConsumer } from '@0x/asset-swapper'; +``` + +or + +```javascript +var SwapQuoter = require('@0x/asset-swapper').SwapQuoter; +var SwapQuoteConsumer = require('@0x/asset-swapper').SwapQuoteConsumer; +``` diff --git a/packages/website/md/docs/asset_swapper/introduction.md b/packages/website/md/docs/asset_swapper/introduction.md new file mode 100644 index 0000000000..a696a68241 --- /dev/null +++ b/packages/website/md/docs/asset_swapper/introduction.md @@ -0,0 +1 @@ +Welcome to the [asset-swapper](https://github.com/0xProject/0x-monorepo/tree/development/packages/asset-swapper) documentation! Asset-swapper is a library that provides an easy way to swap any ERC asset for another ERC asset for smart contract integrations, leveraging 0x liquidity. diff --git a/packages/website/md/docs/order_watcher/1/installation.md b/packages/website/md/docs/order_watcher/1/installation.md deleted file mode 100644 index 4b28f583d3..0000000000 --- a/packages/website/md/docs/order_watcher/1/installation.md +++ /dev/null @@ -1,17 +0,0 @@ -**Install** - -```bash -yarn add @0xproject/order-watcher -``` - -**Import** - -```javascript -import { OrderWatcher } from '@0xproject/order-watcher'; -``` - -or - -```javascript -var OrderWatcher = require('@0xproject/order-utils').OrderWatcher; -``` diff --git a/packages/website/md/docs/order_watcher/1/introduction.md b/packages/website/md/docs/order_watcher/1/introduction.md deleted file mode 100644 index f922d922f8..0000000000 --- a/packages/website/md/docs/order_watcher/1/introduction.md +++ /dev/null @@ -1 +0,0 @@ -Welcome to the [@0xproject/order-watcher](https://github.com/0xProject/0x-monorepo/tree/development/packages/order-watcher) documentation! OrderWatcher is a daemon that efficiently watches a set of orders, emitting events whenever the validity of an order changes. It can be used by relayers to prune an orderbook, or by traders to keep orders fetched from a Relayer up-to-date. diff --git a/packages/website/md/docs/order_watcher/2/installation.md b/packages/website/md/docs/order_watcher/2/installation.md deleted file mode 100644 index 883eb40e56..0000000000 --- a/packages/website/md/docs/order_watcher/2/installation.md +++ /dev/null @@ -1,17 +0,0 @@ -**Install** - -```bash -yarn add @0x/order-watcher -``` - -**Import** - -```javascript -import { OrderWatcher } from '@0x/order-watcher'; -``` - -or - -```javascript -var OrderWatcher = require('@0x/order-utils').OrderWatcher; -``` diff --git a/packages/website/md/docs/order_watcher/2/introduction.md b/packages/website/md/docs/order_watcher/2/introduction.md deleted file mode 100644 index 912cc55e27..0000000000 --- a/packages/website/md/docs/order_watcher/2/introduction.md +++ /dev/null @@ -1,3 +0,0 @@ -**DEPRECATED: This project is deprecated. Please use [0x Mesh](https://github.com/0xProject/0x-mesh) for all your orderbook pruning needs. It can be used with or without order sharing enabled. If you have any questions about how to use Mesh, reach out to us in the [#mesh channel on Discord](https://discordapp.com/invite/d3FTX3M)** - -Welcome to the [order-watcher](https://github.com/0xProject/0x-monorepo/tree/development/packages/order-watcher) documentation! OrderWatcher is a daemon that efficiently watches a set of orders, emitting events whenever the validity of an order changes. It can be used by relayers to prune an orderbook, or by traders to keep orders fetched from a Relayer up-to-date. diff --git a/packages/website/package.json b/packages/website/package.json index cdebc46466..3fbc9815b7 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -1,6 +1,6 @@ { "name": "@0x/website", - "version": "0.0.86", + "version": "0.0.87", "engines": { "node": ">=6.12" }, @@ -21,18 +21,16 @@ "author": "Fabio Berger", "license": "Apache-2.0", "dependencies": { - "@0x/asset-buyer": "^6.1.8", - "@0x/contract-addresses": "^3.0.2", - "@0x/contract-wrappers": "^9.1.7", - "@0x/json-schemas": "^3.0.11", - "@0x/order-utils": "^8.2.2", - "@0x/react-docs": "^2.0.14", - "@0x/react-shared": "^2.0.14", - "@0x/subproviders": "^4.1.1", - "@0x/types": "^2.4.0", - "@0x/typescript-typings": "^4.2.3", - "@0x/utils": "^4.4.0", - "@0x/web3-wrapper": "^6.0.7", + "@0x/asset-buyer": "^6.1.11", + "@0x/contract-addresses": "^3.0.3", + "@0x/contract-wrappers": "^11.0.0", + "@0x/json-schemas": "^3.1.13", + "@0x/order-utils": "^8.2.5", + "@0x/subproviders": "^5.0.1", + "@0x/types": "^2.4.1", + "@0x/typescript-typings": "^4.2.4", + "@0x/utils": "^4.5.0", + "@0x/web3-wrapper": "^6.0.10", "@reach/dialog": "^0.1.2", "@types/react-lazyload": "^2.3.1", "@types/react-loadable": "^5.4.2", @@ -42,16 +40,19 @@ "basscss": "^8.0.3", "blockies": "^0.0.2", "bowser": "^1.9.4", + "change-case": "^3.0.2", "deep-equal": "^1.0.1", - "ethereum-types": "^2.1.3", + "ethereum-types": "^2.1.4", "ethereumjs-util": "^5.1.1", "find-versions": "^2.0.0", + "is-mobile": "^0.2.2", "jsonschema": "^1.2.0", "less": "^2.7.2", "lodash": "^4.17.11", "material-ui": "^0.20.0", "moment": "2.21.0", "moment-precise-range-plugin": "^1.3.0", + "node-sass": "^4.12.0", "numeral": "^2.0.6", "polished": "^1.9.2", "query-string": "^6.0.0", @@ -62,6 +63,7 @@ "react-flickity-component": "^3.1.0", "react-headroom": "2.2.2", "react-helmet": "^5.2.0", + "react-highlight": "0xproject/react-highlight#react-peer-deps", "react-lazyload": "^2.3.0", "react-loadable": "^5.5.0", "react-markdown": "^4.0.6", @@ -69,26 +71,32 @@ "react-redux": "^5.0.3", "react-responsive": "^6.0.1", "react-router-dom": "^4.3.1", - "react-scroll": "0xproject/react-scroll#pr-330-and-replace-state", + "react-scroll": "https://github.com/0xProject/react-scroll.git#d2afc2729dc09980e4113d8c38a1b012ba180d81", "react-scrollable-anchor": "^0.6.1", "react-syntax-highlighter": "^10.1.1", "react-tooltip": "^3.2.7", + "react-transition-group": "^4.2.1", "react-typist": "^2.0.4", "redux": "^3.6.0", "redux-devtools-extension": "^2.13.2", "rollbar": "^2.4.7", + "sass-loader": "^7.1.0", + "semver": "5.5.0", "semver-sort": "0.0.4", "styled-components": "^4.1.1", "thenby": "^1.2.3", "truffle-contract": "2.0.1", + "valid-url": "^1.0.9", "web3-provider-engine": "14.0.6", "xml-js": "^1.6.4" }, "devDependencies": { + "@0x/tslint-config": "^3.0.1", "@types/accounting": "^0.4.1", "@types/blockies": "^0.0.0", "@types/deep-equal": "^1.0.0", "@types/find-versions": "^2.0.0", + "@types/is-mobile": "0.3.0", "@types/jsonschema": "^1.1.1", "@types/lodash": "4.14.104", "@types/material-ui": "^0.20.0", @@ -104,7 +112,9 @@ "@types/react-scroll": "1.5.3", "@types/react-syntax-highlighter": "^0.0.8", "@types/react-tap-event-plugin": "0.0.30", + "@types/react-transition-group": "^4.2.0", "@types/redux": "^3.6.0", + "@types/valid-url": "^1.0.2", "@types/web3-provider-engine": "^14.0.0", "awesome-typescript-loader": "^5.2.1", "css-loader": "0.23.x", diff --git a/packages/website/public/images/governance/zeip-23.png b/packages/website/public/images/governance/zeip-23.png new file mode 100644 index 0000000000..03485b0429 Binary files /dev/null and b/packages/website/public/images/governance/zeip-23.png differ diff --git a/packages/website/public/images/governance/zeip-24.png b/packages/website/public/images/governance/zeip-24.png new file mode 100644 index 0000000000..a5605bd4c2 Binary files /dev/null and b/packages/website/public/images/governance/zeip-24.png differ diff --git a/packages/website/public/images/governance/zeip-39.png b/packages/website/public/images/governance/zeip-39.png new file mode 100644 index 0000000000..19c22fbe1e Binary files /dev/null and b/packages/website/public/images/governance/zeip-39.png differ diff --git a/packages/website/public/images/team/alext.jpg b/packages/website/public/images/team/alext.jpg new file mode 100644 index 0000000000..b963e6b8cc Binary files /dev/null and b/packages/website/public/images/team/alext.jpg differ diff --git a/packages/website/public/images/team/oskarp.jpg b/packages/website/public/images/team/oskarp.jpg new file mode 100644 index 0000000000..70845f0501 Binary files /dev/null and b/packages/website/public/images/team/oskarp.jpg differ diff --git a/packages/website/public/sitemap.txt b/packages/website/public/sitemap.txt index 5ee7cb843f..17c24535df 100644 --- a/packages/website/public/sitemap.txt +++ b/packages/website/public/sitemap.txt @@ -23,7 +23,6 @@ https://0x.org/docs/contracts https://0x.org/docs/connect https://0x.org/docs/web3-wrapper https://0x.org/docs/contract-wrappers -https://0x.org/docs/order-watcher https://0x.org/docs/sol-compiler https://0x.org/docs/json-schemas https://0x.org/docs/sol-coverage diff --git a/packages/website/sass/modal_video.scss b/packages/website/sass/modal_video.scss new file mode 100644 index 0000000000..98f7b0a19a --- /dev/null +++ b/packages/website/sass/modal_video.scss @@ -0,0 +1,134 @@ +$animation-speed: 0.3s; +$animation-function: ease-out; +$backdrop-color: rgba(0, 0, 0, 0.5); + +@keyframes modal-video { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +@keyframes modal-video-inner { + from { + transform: translate(0, 100px); + } + + to { + transform: translate(0, 0); + } +} + +.modal-video { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: $backdrop-color; + z-index: 1000000; + cursor: pointer; + opacity: 1; + animation-timing-function: $animation-function; + animation-duration: $animation-speed; + animation-name: modal-video; + -webkit-transition: opacity $animation-speed $animation-function; + -moz-transition: opacity $animation-speed $animation-function; + -ms-transition: opacity $animation-speed $animation-function; + -o-transition: opacity $animation-speed $animation-function; + transition: opacity $animation-speed $animation-function; +} + +.modal-video-effect-exit { + opacity: 0; + + & .modal-video-movie-wrap { + -webkit-transform: translate(0, 100px); + -moz-transform: translate(0, 100px); + -ms-transform: translate(0, 100px); + -o-transform: translate(0, 100px); + transform: translate(0, 100px); + } +} + +.modal-video-body { + max-width: 1300px; + width: 100%; + height: 100%; + margin: 0 auto; + display: table; +} + +.modal-video-inner { + display: table-cell; + vertical-align: middle; + width: 100%; + height: 100%; +} + +.modal-video-movie-wrap { + width: 100%; + height: 0; + position: relative; + padding-bottom: 56.25%; + background-color: #333; + animation-timing-function: $animation-function; + animation-duration: $animation-speed; + animation-name: modal-video-inner; + -webkit-transform: translate(0, 0); + -moz-transform: translate(0, 0); + -ms-transform: translate(0, 0); + -o-transform: translate(0, 0); + transform: translate(0, 0); + -webkit-transition: -webkit-transform $animation-speed $animation-function; + -moz-transition: -moz-transform $animation-speed $animation-function; + -ms-transition: -ms-transform $animation-speed $animation-function; + -o-transition: -o-transform $animation-speed $animation-function; + transition: transform $animation-speed $animation-function; + + & iframe { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + } +} + +.modal-video-close-btn { + position: absolute; + z-index: 2; + top: -35px; + right: -35px; + display: inline-block; + width: 35px; + height: 35px; + overflow: hidden; + border: none; + background: transparent; + + &:before { + transform: rotate(45deg); + } + + &:after { + transform: rotate(-45deg); + } + + &:before, + &:after { + content: ''; + position: absolute; + height: 2px; + width: 100%; + top: 50%; + left: 0; + margin-top: -1px; + background: #fff; + border-radius: 5px; + margin-top: -6px; + } +} diff --git a/packages/website/ts/blockchain.ts b/packages/website/ts/blockchain.ts index de7f38a8b5..d458327be9 100644 --- a/packages/website/ts/blockchain.ts +++ b/packages/website/ts/blockchain.ts @@ -2,14 +2,15 @@ import { BlockRange, ContractWrappers, DecodedLogEvent, + ERC20TokenContract, ExchangeCancelEventArgs, ExchangeEventArgs, ExchangeEvents, ExchangeFillEventArgs, IndexedFilterValues, + WETH9Contract, } from '@0x/contract-wrappers'; import { assetDataUtils, orderHashUtils, signatureUtils } from '@0x/order-utils'; -import { EtherscanLinkSuffixes, utils as sharedUtils } from '@0x/react-shared'; import { ledgerEthereumBrowserClientFactoryAsync, LedgerSubprovider, @@ -43,6 +44,7 @@ import { BlockchainCallErrs, BlockchainErrs, ContractInstance, + EtherscanLinkSuffixes, Fill, InjectedProvider, InjectedProviderObservable, @@ -237,11 +239,12 @@ export class Blockchain { utils.assert(this._contractWrappers !== undefined, 'Contract Wrappers must be instantiated.'); this._showFlashMessageIfLedger(); - const txHash = await this._contractWrappers.erc20Token.setProxyAllowanceAsync( - token.address, - this._userAddressIfExists, + const erc20Token = new ERC20TokenContract(token.address, this._contractWrappers.getProvider()); + const txHash = await erc20Token.approve.sendTransactionAsync( + this._contractWrappers.contractAddresses.erc20Proxy, amountInBaseUnits, { + from: this._userAddressIfExists, gasPrice: this._defaultGasPrice, }, ); @@ -258,11 +261,7 @@ export class Blockchain { this._showFlashMessageIfLedger(); const txHash = await this._web3Wrapper.sendTransactionAsync(transaction); await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); - const etherScanLinkIfExists = sharedUtils.getEtherScanLinkIfExists( - txHash, - this.networkId, - EtherscanLinkSuffixes.Tx, - ); + const etherScanLinkIfExists = utils.getEtherScanLinkIfExists(txHash, this.networkId, EtherscanLinkSuffixes.Tx); this._dispatcher.showFlashMessage( React.createElement(AssetSendCompleted, { etherScanLinkIfExists, @@ -278,21 +277,13 @@ export class Blockchain { utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); this._showFlashMessageIfLedger(); - const txHash = await this._contractWrappers.erc20Token.transferAsync( - token.address, - this._userAddressIfExists, - toAddress, - amountInBaseUnits, - { - gasPrice: this._defaultGasPrice, - }, - ); + const erc20Token = new ERC20TokenContract(token.address, this._contractWrappers.getProvider()); + const txHash = await erc20Token.transfer.validateAndSendTransactionAsync(toAddress, amountInBaseUnits, { + from: this._userAddressIfExists, + gasPrice: this._defaultGasPrice, + }); await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); - const etherScanLinkIfExists = sharedUtils.getEtherScanLinkIfExists( - txHash, - this.networkId, - EtherscanLinkSuffixes.Tx, - ); + const etherScanLinkIfExists = utils.getEtherScanLinkIfExists(txHash, this.networkId, EtherscanLinkSuffixes.Tx); this._dispatcher.showFlashMessage( React.createElement(AssetSendCompleted, { etherScanLinkIfExists, @@ -307,11 +298,12 @@ export class Blockchain { utils.assert(this._contractWrappers !== undefined, 'ContractWrappers must be instantiated.'); utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); this._showFlashMessageIfLedger(); - const txHash = await this._contractWrappers.exchange.fillOrderAsync( + const txHash = await this._contractWrappers.exchange.fillOrder.validateAndSendTransactionAsync( signedOrder, fillTakerTokenAmount, - this._userAddressIfExists, + signedOrder.signature, { + from: this._userAddressIfExists, gasPrice: this._defaultGasPrice, }, ); @@ -324,7 +316,8 @@ export class Blockchain { } public async cancelOrderAsync(signedOrder: SignedOrder): Promise { this._showFlashMessageIfLedger(); - const txHash = await this._contractWrappers.exchange.cancelOrderAsync(signedOrder, { + const txHash = await this._contractWrappers.exchange.cancelOrder.validateAndSendTransactionAsync(signedOrder, { + from: signedOrder.makerAddress, gasPrice: this._defaultGasPrice, }); const receipt = await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); @@ -337,7 +330,7 @@ export class Blockchain { public async getUnavailableTakerAmountAsync(orderHash: string): Promise { utils.assert(orderHashUtils.isValidOrderHash(orderHash), 'Must be valid orderHash'); utils.assert(this._contractWrappers !== undefined, 'ContractWrappers must be instantiated.'); - const unavailableTakerAmount = await this._contractWrappers.exchange.getFilledTakerAssetAmountAsync(orderHash); + const unavailableTakerAmount = await this._contractWrappers.exchange.filled.callAsync(orderHash); return unavailableTakerAmount; } public getExchangeContractAddressIfExists(): string | undefined { @@ -348,10 +341,13 @@ export class Blockchain { fillTakerTokenAmount: BigNumber, takerAddress: string, ): Promise { - await this._contractWrappers.exchange.validateFillOrderThrowIfInvalidAsync( + await this._contractWrappers.exchange.fillOrder.callAsync( signedOrder, fillTakerTokenAmount, - takerAddress, + signedOrder.signature, + { + from: takerAddress, + }, ); } public isValidAddress(address: string): boolean { @@ -428,14 +424,12 @@ export class Blockchain { utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); this._showFlashMessageIfLedger(); - const txHash = await this._contractWrappers.etherToken.depositAsync( - etherTokenAddress, - amount, - this._userAddressIfExists, - { - gasPrice: this._defaultGasPrice, - }, - ); + const etherToken = new WETH9Contract(etherTokenAddress, this._contractWrappers.getProvider()); + const txHash = await etherToken.deposit.validateAndSendTransactionAsync({ + value: amount, + from: this._userAddressIfExists, + gasPrice: this._defaultGasPrice, + }); await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); } public async convertWrappedEthTokensToEthAsync(etherTokenAddress: string, amount: BigNumber): Promise { @@ -443,14 +437,11 @@ export class Blockchain { utils.assert(this._doesUserAddressExist(), BlockchainCallErrs.UserHasNoAssociatedAddresses); this._showFlashMessageIfLedger(); - const txHash = await this._contractWrappers.etherToken.withdrawAsync( - etherTokenAddress, - amount, - this._userAddressIfExists, - { - gasPrice: this._defaultGasPrice, - }, - ); + const etherToken = new WETH9Contract(etherTokenAddress, this._contractWrappers.getProvider()); + const txHash = await etherToken.withdraw.validateAndSendTransactionAsync(amount, { + from: this._userAddressIfExists, + gasPrice: this._defaultGasPrice, + }); await this._showEtherScanLinkAndAwaitTransactionMinedAsync(txHash); } public async doesContractExistAtAddressAsync(address: string): Promise { @@ -479,9 +470,13 @@ export class Blockchain { let balance = new BigNumber(0); let allowance = new BigNumber(0); if (this._doesUserAddressExist()) { + const erc20Token = new ERC20TokenContract(tokenAddress, this._contractWrappers.getProvider()); [balance, allowance] = await Promise.all([ - this._contractWrappers.erc20Token.getBalanceAsync(tokenAddress, ownerAddressIfExists), - this._contractWrappers.erc20Token.getProxyAllowanceAsync(tokenAddress, ownerAddressIfExists), + erc20Token.balanceOf.callAsync(ownerAddressIfExists), + erc20Token.allowance.callAsync( + ownerAddressIfExists, + this._contractWrappers.contractAddresses.erc20Proxy, + ), ]); } return [balance, allowance]; @@ -622,11 +617,7 @@ export class Blockchain { private async _showEtherScanLinkAndAwaitTransactionMinedAsync( txHash: string, ): Promise { - const etherScanLinkIfExists = sharedUtils.getEtherScanLinkIfExists( - txHash, - this.networkId, - EtherscanLinkSuffixes.Tx, - ); + const etherScanLinkIfExists = utils.getEtherScanLinkIfExists(txHash, this.networkId, EtherscanLinkSuffixes.Tx); this._dispatcher.showFlashMessage( React.createElement(TransactionSubmitted, { etherScanLinkIfExists, diff --git a/packages/website/ts/components/button.tsx b/packages/website/ts/components/button.tsx index 7f515cc38e..3ca578c300 100644 --- a/packages/website/ts/components/button.tsx +++ b/packages/website/ts/components/button.tsx @@ -108,7 +108,7 @@ const ButtonBase = styled.button` border-color: ${props => props.isTransparent && !props.isNoBorder && !props.isWithArrow && '#00AE99'}; svg { - transform: translate3d(2px, -2px, 0); + transform: ${props => (props.isWithArrow ? 'translate3d(2px, -2px, 0)' : '')}; } } `; diff --git a/packages/website/ts/components/dialogs/blockchain_err_dialog.tsx b/packages/website/ts/components/dialogs/blockchain_err_dialog.tsx index 1c47903dbd..146cb56514 100644 --- a/packages/website/ts/components/dialogs/blockchain_err_dialog.tsx +++ b/packages/website/ts/components/dialogs/blockchain_err_dialog.tsx @@ -1,9 +1,9 @@ -import { colors, Networks } from '@0x/react-shared'; import Dialog from 'material-ui/Dialog'; import FlatButton from 'material-ui/FlatButton'; import * as React from 'react'; import { Blockchain } from 'ts/blockchain'; -import { BlockchainErrs } from 'ts/types'; +import { BlockchainErrs, Networks } from 'ts/types'; +import { colors } from 'ts/utils/colors'; import { constants } from 'ts/utils/constants'; interface BlockchainErrDialogProps { diff --git a/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx b/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx index 9c799e9bab..5326cb70ae 100644 --- a/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx +++ b/packages/website/ts/components/dialogs/eth_weth_conversion_dialog.tsx @@ -1,4 +1,3 @@ -import { colors } from '@0x/react-shared'; import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; import Dialog from 'material-ui/Dialog'; @@ -8,6 +7,7 @@ import { Blockchain } from 'ts/blockchain'; import { TokenAmountInput } from 'ts/components/inputs/token_amount_input'; import { EthAmountInput } from 'ts/containers/inputs/eth_amount_input'; import { Side, Token } from 'ts/types'; +import { colors } from 'ts/utils/colors'; interface EthWethConversionDialogProps { blockchain: Blockchain; diff --git a/packages/website/ts/components/dialogs/ledger_config_dialog.tsx b/packages/website/ts/components/dialogs/ledger_config_dialog.tsx index 83cc857cdc..5df5e750b0 100644 --- a/packages/website/ts/components/dialogs/ledger_config_dialog.tsx +++ b/packages/website/ts/components/dialogs/ledger_config_dialog.tsx @@ -1,4 +1,3 @@ -import { colors, constants as sharedConstants } from '@0x/react-shared'; import { BigNumber, logUtils } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import * as _ from 'lodash'; @@ -13,6 +12,7 @@ import { NetworkDropDown } from 'ts/components/dropdowns/network_drop_down'; import { LifeCycleRaisedButton } from 'ts/components/ui/lifecycle_raised_button'; import { Dispatcher } from 'ts/redux/dispatcher'; import { ProviderType } from 'ts/types'; +import { colors } from 'ts/utils/colors'; import { configs } from 'ts/utils/configs'; import { constants } from 'ts/utils/constants'; import { utils } from 'ts/utils/utils'; @@ -85,7 +85,7 @@ export class LedgerConfigDialog extends React.Component
Follow these instructions before proceeding:
@@ -166,7 +166,7 @@ export class LedgerConfigDialog extends React.Component {_.map(this.props.tutorials, tutorialInfo => ( diff --git a/packages/react-docs/src/components/badge.tsx b/packages/website/ts/components/documentation/reference/badge.tsx similarity index 96% rename from packages/react-docs/src/components/badge.tsx rename to packages/website/ts/components/documentation/reference/badge.tsx index e3d5be273b..d0bdb99d30 100644 --- a/packages/react-docs/src/components/badge.tsx +++ b/packages/website/ts/components/documentation/reference/badge.tsx @@ -1,5 +1,5 @@ -import { Styles } from '@0x/react-shared'; import * as React from 'react'; +import { Styles } from 'ts/types'; const styles: Styles = { badge: { diff --git a/packages/react-docs/src/components/comment.tsx b/packages/website/ts/components/documentation/reference/comment.tsx similarity index 80% rename from packages/react-docs/src/components/comment.tsx rename to packages/website/ts/components/documentation/reference/comment.tsx index 4d34f711e9..5c14bebfd3 100644 --- a/packages/react-docs/src/components/comment.tsx +++ b/packages/website/ts/components/documentation/reference/comment.tsx @@ -1,6 +1,7 @@ -import { colors, MarkdownCodeBlock } from '@0x/react-shared'; import * as React from 'react'; import * as ReactMarkdown from 'react-markdown'; +import { MarkdownCodeBlock } from 'ts/components/documentation/shared/markdown_code_block'; +import { colors } from 'ts/utils/colors'; export interface CommentProps { comment: string; diff --git a/packages/react-docs/src/components/custom_enum.tsx b/packages/website/ts/components/documentation/reference/custom_enum.tsx similarity index 100% rename from packages/react-docs/src/components/custom_enum.tsx rename to packages/website/ts/components/documentation/reference/custom_enum.tsx diff --git a/packages/react-docs/src/components/doc_reference.tsx b/packages/website/ts/components/documentation/reference/doc_reference.tsx similarity index 93% rename from packages/react-docs/src/components/doc_reference.tsx rename to packages/website/ts/components/documentation/reference/doc_reference.tsx index 0b1842b40c..52ab5599d4 100644 --- a/packages/react-docs/src/components/doc_reference.tsx +++ b/packages/website/ts/components/documentation/reference/doc_reference.tsx @@ -1,14 +1,3 @@ -import { - colors, - constants as sharedConstants, - EtherscanLinkSuffixes, - HeaderSizes, - Link, - MarkdownSection, - Networks, - SectionHeader, - utils as sharedUtils, -} from '@0x/react-shared'; import { DocAgnosticFormat, Event, @@ -22,10 +11,15 @@ import { import * as _ from 'lodash'; import * as React from 'react'; import * as semver from 'semver'; +import { Link } from 'ts/components/documentation/shared/link'; +import { MarkdownSection } from 'ts/components/documentation/shared/markdown_section'; +import { SectionHeader } from 'ts/components/documentation/shared/section_header'; +import { AddressByContractName, EtherscanLinkSuffixes, HeaderSizes, Networks, SupportedDocJson } from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { constants } from 'ts/utils/constants'; +import { utils } from 'ts/utils/utils'; -import { DocsInfo } from '../docs_info'; -import { AddressByContractName, SupportedDocJson } from '../types'; -import { constants } from '../utils/constants'; +import { DocsInfo } from 'ts/utils/docs_info'; import { Badge } from './badge'; import { Comment } from './comment'; @@ -55,7 +49,7 @@ export class DocReference extends React.Component -
+
{renderedSections}
); @@ -250,9 +244,9 @@ export class DocReference extends React.Component = (props: TypeProps): any => { : `${props.docsInfo.typeSectionName}-${typeName}`; typeName = ( - {sharedUtils.isUserOnMobile() || props.isInPopover || isExportedClassReference ? ( + {utils.isUserOnMobile() || props.isInPopover || isExportedClassReference ? ( {typeName} ) : ( diff --git a/packages/react-docs/src/components/type_definition.tsx b/packages/website/ts/components/documentation/reference/type_definition.tsx similarity index 96% rename from packages/react-docs/src/components/type_definition.tsx rename to packages/website/ts/components/documentation/reference/type_definition.tsx index a1fde51dae..3ea1f915e8 100644 --- a/packages/react-docs/src/components/type_definition.tsx +++ b/packages/website/ts/components/documentation/reference/type_definition.tsx @@ -1,12 +1,13 @@ -import { AnchorTitle, colors, HeaderSizes } from '@0x/react-shared'; import { CustomType, CustomTypeChild, TypeDefinitionByName, TypeDocTypes } from '@0x/types'; import { errorUtils } from '@0x/utils'; import * as _ from 'lodash'; import * as React from 'react'; +import { AnchorTitle } from 'ts/components/documentation/shared/anchor_title'; -import { DocsInfo } from '../docs_info'; -import { KindString, SupportedDocJson } from '../types'; -import { constants } from '../utils/constants'; +import { HeaderSizes, KindString, SupportedDocJson } from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { constants } from 'ts/utils/constants'; +import { DocsInfo } from 'ts/utils/docs_info'; import { Comment } from './comment'; import { CustomEnum } from './custom_enum'; diff --git a/packages/website/ts/components/documentation/shared/.DS_Store b/packages/website/ts/components/documentation/shared/.DS_Store new file mode 100644 index 0000000000..426195b458 Binary files /dev/null and b/packages/website/ts/components/documentation/shared/.DS_Store differ diff --git a/packages/react-shared/src/components/anchor_title.tsx b/packages/website/ts/components/documentation/shared/anchor_title.tsx similarity index 93% rename from packages/react-shared/src/components/anchor_title.tsx rename to packages/website/ts/components/documentation/shared/anchor_title.tsx index fccd56de73..6aa17ae46e 100644 --- a/packages/react-shared/src/components/anchor_title.tsx +++ b/packages/website/ts/components/documentation/shared/anchor_title.tsx @@ -1,9 +1,10 @@ import * as React from 'react'; import styled from 'styled-components'; -import { Link } from '../components/link'; -import { HeaderSizes, Styles } from '../types'; -import { colors } from '../utils/colors'; +import { HeaderSizes, Styles } from 'ts/types'; +import { colors } from 'ts/utils/colors'; + +import { Link } from './link'; export interface AnchorTitleProps { title: string | React.ReactNode; diff --git a/packages/react-shared/src/components/link.tsx b/packages/website/ts/components/documentation/shared/link.tsx similarity index 98% rename from packages/react-shared/src/components/link.tsx rename to packages/website/ts/components/documentation/shared/link.tsx index f07a7b7297..bcaf0c4e2b 100644 --- a/packages/react-shared/src/components/link.tsx +++ b/packages/website/ts/components/documentation/shared/link.tsx @@ -4,8 +4,8 @@ import { NavLink as ReactRounterLink } from 'react-router-dom'; import { Link as ScrollLink } from 'react-scroll'; import * as validUrl from 'valid-url'; -import { LinkType } from '../types'; -import { constants } from '../utils/constants'; +import { LinkType } from 'ts/types'; +import { constants } from 'ts/utils/constants'; export interface BaseLinkProps { to: string; diff --git a/packages/react-shared/src/components/markdown_code_block.tsx b/packages/website/ts/components/documentation/shared/markdown_code_block.tsx similarity index 100% rename from packages/react-shared/src/components/markdown_code_block.tsx rename to packages/website/ts/components/documentation/shared/markdown_code_block.tsx diff --git a/packages/react-shared/src/components/markdown_link_block.tsx b/packages/website/ts/components/documentation/shared/markdown_link_block.tsx similarity index 95% rename from packages/react-shared/src/components/markdown_link_block.tsx rename to packages/website/ts/components/documentation/shared/markdown_link_block.tsx index f083a91cf2..a2f4fb767f 100644 --- a/packages/react-shared/src/components/markdown_link_block.tsx +++ b/packages/website/ts/components/documentation/shared/markdown_link_block.tsx @@ -1,8 +1,8 @@ import * as _ from 'lodash'; import * as React from 'react'; -import { constants } from '../utils/constants'; -import { utils } from '../utils/utils'; +import { constants } from 'ts/utils/constants'; +import { utils } from 'ts/utils/utils'; export interface MarkdownLinkBlockProps { href: string; diff --git a/packages/react-shared/src/components/markdown_paragraph_block.tsx b/packages/website/ts/components/documentation/shared/markdown_paragraph_block.tsx similarity index 90% rename from packages/react-shared/src/components/markdown_paragraph_block.tsx rename to packages/website/ts/components/documentation/shared/markdown_paragraph_block.tsx index 9ed44ed077..6b0102ac51 100644 --- a/packages/react-shared/src/components/markdown_paragraph_block.tsx +++ b/packages/website/ts/components/documentation/shared/markdown_paragraph_block.tsx @@ -1,7 +1,7 @@ import * as _ from 'lodash'; import * as React from 'react'; -import { colors } from '../utils/colors'; +import { colors } from 'ts/utils/colors'; export interface MarkdownParagraphBlockProps {} diff --git a/packages/react-shared/src/components/markdown_section.tsx b/packages/website/ts/components/documentation/shared/markdown_section.tsx similarity index 97% rename from packages/react-shared/src/components/markdown_section.tsx rename to packages/website/ts/components/documentation/shared/markdown_section.tsx index 2ab26dfa32..af9d5781b3 100644 --- a/packages/react-shared/src/components/markdown_section.tsx +++ b/packages/website/ts/components/documentation/shared/markdown_section.tsx @@ -3,9 +3,9 @@ import * as React from 'react'; import * as ReactMarkdown from 'react-markdown'; import { Element as ScrollElement } from 'react-scroll'; -import { HeaderSizes } from '../types'; -import { colors } from '../utils/colors'; -import { utils } from '../utils/utils'; +import { HeaderSizes } from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { utils } from 'ts/utils/utils'; import { AnchorTitle } from './anchor_title'; import { Link } from './link'; diff --git a/packages/react-shared/src/components/section_header.tsx b/packages/website/ts/components/documentation/shared/section_header.tsx similarity index 94% rename from packages/react-shared/src/components/section_header.tsx rename to packages/website/ts/components/documentation/shared/section_header.tsx index 137b63765e..5ca041bcd4 100644 --- a/packages/react-shared/src/components/section_header.tsx +++ b/packages/website/ts/components/documentation/shared/section_header.tsx @@ -1,9 +1,9 @@ import * as React from 'react'; import { Element as ScrollElement } from 'react-scroll'; -import { HeaderSizes } from '../types'; -import { colors } from '../utils/colors'; -import { utils } from '../utils/utils'; +import { HeaderSizes } from 'ts/types'; +import { colors } from 'ts/utils/colors'; +import { utils } from 'ts/utils/utils'; import { AnchorTitle } from './anchor_title'; diff --git a/packages/website/ts/components/documentation/sidebar_header.tsx b/packages/website/ts/components/documentation/sidebar_header.tsx index 0100f027c8..8b6214ca62 100644 --- a/packages/website/ts/components/documentation/sidebar_header.tsx +++ b/packages/website/ts/components/documentation/sidebar_header.tsx @@ -1,10 +1,10 @@ -import { colors } from '@0x/react-shared'; import * as _ from 'lodash'; import * as React from 'react'; import { VersionDropDown } from 'ts/components/documentation/version_drop_down'; import { Container } from 'ts/components/ui/container'; import { Text } from 'ts/components/ui/text'; import { ScreenWidths } from 'ts/types'; +import { colors } from 'ts/utils/colors'; export interface SidebarHeaderProps { screenWidth: ScreenWidths; diff --git a/packages/website/ts/components/documentation/tutorial_button.tsx b/packages/website/ts/components/documentation/tutorial_button.tsx index b747ef598f..5de621e791 100644 --- a/packages/website/ts/components/documentation/tutorial_button.tsx +++ b/packages/website/ts/components/documentation/tutorial_button.tsx @@ -1,12 +1,13 @@ -import { colors, Link } from '@0x/react-shared'; import * as _ from 'lodash'; import * as React from 'react'; import { Container } from 'ts/components/ui/container'; import { Text } from 'ts/components/ui/text'; +import { styled } from 'ts/style/theme'; import { Deco, Key, TutorialInfo } from 'ts/types'; +import { colors } from 'ts/utils/colors'; import { Translate } from 'ts/utils/translate'; -import { styled } from 'ts/style/theme'; +import { Link } from './shared/link'; export interface TutorialButtonProps { className?: string; diff --git a/packages/website/ts/components/documentation/version_drop_down.tsx b/packages/website/ts/components/documentation/version_drop_down.tsx index 5e77530fd0..b4fb4b4888 100644 --- a/packages/website/ts/components/documentation/version_drop_down.tsx +++ b/packages/website/ts/components/documentation/version_drop_down.tsx @@ -1,4 +1,3 @@ -import { colors } from '@0x/react-shared'; import * as _ from 'lodash'; import * as React from 'react'; import { Button } from 'ts/components/ui/button'; @@ -6,6 +5,7 @@ import { Container } from 'ts/components/ui/container'; import { DropDown, DropdownMouseEvent } from 'ts/components/ui/drop_down'; import { Text } from 'ts/components/ui/text'; import { styled } from 'ts/style/theme'; +import { colors } from 'ts/utils/colors'; interface ActiveNodeProps { className?: string; diff --git a/packages/website/ts/components/dropdowns/developers_drop_down.tsx b/packages/website/ts/components/dropdowns/developers_drop_down.tsx index 079132f2bc..a791379056 100644 --- a/packages/website/ts/components/dropdowns/developers_drop_down.tsx +++ b/packages/website/ts/components/dropdowns/developers_drop_down.tsx @@ -1,13 +1,15 @@ -import { ALink, colors, Link } from '@0x/react-shared'; import * as _ from 'lodash'; import * as React from 'react'; import { Container } from 'ts/components/ui/container'; import { DropDown } from 'ts/components/ui/drop_down'; import { Text } from 'ts/components/ui/text'; -import { Deco, Key, WebsitePaths } from 'ts/types'; +import { ALink, Deco, Key, WebsitePaths } from 'ts/types'; +import { colors } from 'ts/utils/colors'; import { constants } from 'ts/utils/constants'; import { Translate } from 'ts/utils/translate'; +import { Link } from '../documentation/shared/link'; + const gettingStartedKeyToLinkInfo1: ALink[] = [ { title: Key.BuildARelayer, diff --git a/packages/website/ts/components/dropdowns/dropdown_developers.tsx b/packages/website/ts/components/dropdowns/dropdown_developers.tsx index 91bc58a356..f004ce6774 100644 --- a/packages/website/ts/components/dropdowns/dropdown_developers.tsx +++ b/packages/website/ts/components/dropdowns/dropdown_developers.tsx @@ -1,8 +1,6 @@ -import { Link } from '@0x/react-shared'; import * as _ from 'lodash'; import * as React from 'react'; import styled, { withTheme } from 'styled-components'; - import { Button } from 'ts/components/button'; import { Column, FlexWrap, WrapGrid } from 'ts/components/newLayout'; import { ThemeValuesInterface } from 'ts/components/siteWrap'; @@ -10,6 +8,8 @@ import { Heading } from 'ts/components/text'; import { WebsitePaths } from 'ts/types'; import { constants } from 'ts/utils/constants'; +import { Link } from '../documentation/shared/link'; + interface Props { theme: ThemeValuesInterface; } diff --git a/packages/website/ts/components/dropdowns/dropdown_resources.tsx b/packages/website/ts/components/dropdowns/dropdown_resources.tsx index 4e638426ff..f65bdf635b 100644 --- a/packages/website/ts/components/dropdowns/dropdown_resources.tsx +++ b/packages/website/ts/components/dropdowns/dropdown_resources.tsx @@ -1,14 +1,14 @@ -import { Link } from '@0x/react-shared'; import * as _ from 'lodash'; import * as React from 'react'; import styled, { withTheme } from 'styled-components'; - import { Column, FlexWrap } from 'ts/components/newLayout'; import { ThemeValuesInterface } from 'ts/components/siteWrap'; import { Heading } from 'ts/components/text'; import { WebsitePaths } from 'ts/types'; import { constants } from 'ts/utils/constants'; +import { Link } from '../documentation/shared/link'; + interface Props { theme: ThemeValuesInterface; } diff --git a/packages/website/ts/components/dropdowns/network_drop_down.tsx b/packages/website/ts/components/dropdowns/network_drop_down.tsx index df2d72edc2..673b1c6c13 100644 --- a/packages/website/ts/components/dropdowns/network_drop_down.tsx +++ b/packages/website/ts/components/dropdowns/network_drop_down.tsx @@ -1,8 +1,8 @@ -import { constants as sharedConstants } from '@0x/react-shared'; import * as _ from 'lodash'; import DropDownMenu from 'material-ui/DropDownMenu'; import MenuItem from 'material-ui/MenuItem'; import * as React from 'react'; +import { constants } from 'ts/utils/constants'; interface NetworkDropDownProps { updateSelectedNetwork: (e: any, index: number, value: number) => void; @@ -24,7 +24,7 @@ export class NetworkDropDown extends React.Component { - const networkName = sharedConstants.NETWORK_NAME_BY_ID[networkId]; + const networkName = constants.NETWORK_NAME_BY_ID[networkId]; const primaryText = (
diff --git a/packages/website/ts/components/eth_wrappers.tsx b/packages/website/ts/components/eth_wrappers.tsx index 34f06cc304..8517c6ae58 100644 --- a/packages/website/ts/components/eth_wrappers.tsx +++ b/packages/website/ts/components/eth_wrappers.tsx @@ -1,4 +1,3 @@ -import { colors, EtherscanLinkSuffixes, utils as sharedUtils } from '@0x/react-shared'; import { BigNumber } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import * as _ from 'lodash'; @@ -11,6 +10,7 @@ import { Blockchain } from 'ts/blockchain'; import { EthWethConversionButton } from 'ts/components/eth_weth_conversion_button'; import { Dispatcher } from 'ts/redux/dispatcher'; import { + EtherscanLinkSuffixes, OutdatedWrappedEtherByNetworkId, Side, Token, @@ -18,6 +18,7 @@ import { TokenState, TokenStateByAddress, } from 'ts/types'; +import { colors } from 'ts/utils/colors'; import { configs } from 'ts/utils/configs'; import { constants } from 'ts/utils/constants'; import { utils } from 'ts/utils/utils'; @@ -91,7 +92,7 @@ export class EthWrappers extends React.Component * { padding-left: 20px; padding-right: 20px; } @@ -138,26 +138,39 @@ const BackgroundWrap = styled.div` top: 0; `; -export const Hero: React.StatelessComponent = (props: Props) => ( -
- {!!props.background && {props.background}} - - {props.figure && {props.figure}} +export class Hero extends React.Component { + public static defaultProps = { + isCenteredMobile: true, + }; + public shouldComponentUpdate(): boolean { + // The hero is a static component with animations. + // We do not want state changes in parent components to re-trigger animations. + return false; + } + public render(): React.ReactNode { + const props = this.props; + return ( +
+ {!!props.background && {props.background}} + + {props.figure && {props.figure}} - - {!!props.announcement && } - - {props.title} - + + {!!props.announcement && } + + {props.title} + - {props.description} + {props.description} - {props.actions && {props.actions}} - - -
-); - -Hero.defaultProps = { - isCenteredMobile: true, -}; + {props.actions && {props.actions}} + +
+
+ ); + } +} diff --git a/packages/website/ts/components/inputs/address_input.tsx b/packages/website/ts/components/inputs/address_input.tsx index 8bf85a8506..5926d08004 100644 --- a/packages/website/ts/components/inputs/address_input.tsx +++ b/packages/website/ts/components/inputs/address_input.tsx @@ -1,9 +1,9 @@ -import { colors } from '@0x/react-shared'; import { addressUtils } from '@0x/utils'; import * as _ from 'lodash'; import TextField from 'material-ui/TextField'; import * as React from 'react'; import { RequiredLabel } from 'ts/components/ui/required_label'; +import { colors } from 'ts/utils/colors'; interface AddressInputProps { disabled?: boolean; diff --git a/packages/website/ts/components/inputs/allowance_state_toggle.tsx b/packages/website/ts/components/inputs/allowance_state_toggle.tsx index 3a78d32f38..3065535419 100644 --- a/packages/website/ts/components/inputs/allowance_state_toggle.tsx +++ b/packages/website/ts/components/inputs/allowance_state_toggle.tsx @@ -1,4 +1,3 @@ -import { colors } from '@0x/react-shared'; import { BigNumber, logUtils } from '@0x/utils'; import * as _ from 'lodash'; import * as React from 'react'; @@ -11,6 +10,7 @@ import { Text } from 'ts/components/ui/text'; import { Dispatcher } from 'ts/redux/dispatcher'; import { BalanceErrs, Token, TokenState } from 'ts/types'; import { analytics } from 'ts/utils/analytics'; +import { colors } from 'ts/utils/colors'; import { errorReporter } from 'ts/utils/error_reporter'; import { utils } from 'ts/utils/utils'; diff --git a/packages/website/ts/components/inputs/balance_bounded_input.tsx b/packages/website/ts/components/inputs/balance_bounded_input.tsx index 0035066b69..07cc015870 100644 --- a/packages/website/ts/components/inputs/balance_bounded_input.tsx +++ b/packages/website/ts/components/inputs/balance_bounded_input.tsx @@ -1,10 +1,10 @@ -import { colors } from '@0x/react-shared'; import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; import TextField from 'material-ui/TextField'; import * as React from 'react'; import { RequiredLabel } from 'ts/components/ui/required_label'; import { ValidatedBigNumberCallback } from 'ts/types'; +import { colors } from 'ts/utils/colors'; import { utils } from 'ts/utils/utils'; interface BalanceBoundedInputProps { diff --git a/packages/website/ts/components/inputs/hash_input.tsx b/packages/website/ts/components/inputs/hash_input.tsx index 7688ffe21d..86e4547717 100644 --- a/packages/website/ts/components/inputs/hash_input.tsx +++ b/packages/website/ts/components/inputs/hash_input.tsx @@ -1,5 +1,4 @@ import { assetDataUtils, orderHashUtils } from '@0x/order-utils'; -import { Styles } from '@0x/react-shared'; import { Order } from '@0x/types'; import * as _ from 'lodash'; import * as React from 'react'; @@ -7,7 +6,7 @@ import ReactTooltip from 'react-tooltip'; import { Blockchain } from 'ts/blockchain'; import { FakeTextField } from 'ts/components/ui/fake_text_field'; -import { HashData } from 'ts/types'; +import { HashData, Styles } from 'ts/types'; import { constants } from 'ts/utils/constants'; const styles: Styles = { diff --git a/packages/website/ts/components/inputs/token_amount_input.tsx b/packages/website/ts/components/inputs/token_amount_input.tsx index b8872c516c..59680c06b5 100644 --- a/packages/website/ts/components/inputs/token_amount_input.tsx +++ b/packages/website/ts/components/inputs/token_amount_input.tsx @@ -1,10 +1,11 @@ -import { colors, Link } from '@0x/react-shared'; import { BigNumber } from '@0x/utils'; import { Web3Wrapper } from '@0x/web3-wrapper'; import * as _ from 'lodash'; import * as React from 'react'; import { Blockchain } from 'ts/blockchain'; +import { Link } from 'ts/components/documentation/shared/link'; import { BalanceBoundedInput } from 'ts/components/inputs/balance_bounded_input'; +import { colors } from 'ts/style/colors'; import { Token, ValidatedBigNumberCallback, WebsitePaths } from 'ts/types'; interface TokenAmountInputProps { diff --git a/packages/website/ts/components/inputs/token_input.tsx b/packages/website/ts/components/inputs/token_input.tsx index c3c2d8b37b..c317c553ba 100644 --- a/packages/website/ts/components/inputs/token_input.tsx +++ b/packages/website/ts/components/inputs/token_input.tsx @@ -1,4 +1,3 @@ -import { colors } from '@0x/react-shared'; import Paper from 'material-ui/Paper'; import * as React from 'react'; import { Blockchain } from 'ts/blockchain'; @@ -7,6 +6,7 @@ import { InputLabel } from 'ts/components/ui/input_label'; import { TokenIcon } from 'ts/components/ui/token_icon'; import { Dispatcher } from 'ts/redux/dispatcher'; import { AssetToken, BlockchainErrs, Side, Token, TokenByAddress } from 'ts/types'; +import { colors } from 'ts/utils/colors'; const TOKEN_ICON_DIMENSION = 80; diff --git a/packages/website/ts/components/link.tsx b/packages/website/ts/components/link.tsx index a66985accc..4b463e5e0d 100644 --- a/packages/website/ts/components/link.tsx +++ b/packages/website/ts/components/link.tsx @@ -1,6 +1,6 @@ -import { Link as SmartLink } from '@0x/react-shared'; import * as React from 'react'; import styled from 'styled-components'; +import { Link as SmartLink } from 'ts/components/documentation/shared/link'; interface LinkInterface { color?: string; diff --git a/packages/website/ts/components/modals/modal_contact.tsx b/packages/website/ts/components/modals/modal_contact.tsx index 9dcebb229b..794cab5423 100644 --- a/packages/website/ts/components/modals/modal_contact.tsx +++ b/packages/website/ts/components/modals/modal_contact.tsx @@ -480,7 +480,7 @@ export class ModalContact extends React.Component { name: this.nameRef.current.value, email: this.emailRef.current.value, project_name: this.companyProjectRef.current.value, - project_description: this.commentsRef.current.value, + comments: this.commentsRef.current.value, services: this.state.creditLeadsServices, }; } else if (this.props.modalContactType === ModalContactType.Explore) { diff --git a/packages/website/ts/components/modals/modal_video.tsx b/packages/website/ts/components/modals/modal_video.tsx new file mode 100644 index 0000000000..63a0707a34 --- /dev/null +++ b/packages/website/ts/components/modals/modal_video.tsx @@ -0,0 +1,257 @@ +import React from 'react'; +import CSSTransition from 'react-transition-group/CSSTransition'; + +interface ModalVideoClassnames { + modalVideoEffect: string; + modalVideo: string; + modalVideoClose: string; + modalVideoBody: string; + modalVideoInner: string; + modalVideoIframeWrap: string; + modalVideoCloseBtn: string; +} + +interface Aria { + openMessage: string; + dismissBtnMessage: string; +} + +export interface ModalVideoProps { + onClose?: () => void; + isOpen: boolean; + classNames?: ModalVideoClassnames; + ratio?: string; + animationSpeed?: number; + allowFullScreen?: boolean; + aria?: Aria; + videoId?: string; + channel?: string; + youtube?: any; + vimeo?: any; + youku?: any; +} + +export interface ModalVideoState { + isOpen: boolean; +} + +export class ModalVideo extends React.Component { + public static defaultProps: ModalVideoProps = { + channel: 'youtube', + isOpen: false, + youtube: { + autoplay: 1, + cc_load_policy: 1, + color: null, + controls: 1, + disablekb: 0, + enablejsapi: 0, + end: null, + fs: 1, + h1: null, + iv_load_policy: 1, + list: null, + listType: null, + loop: 0, + modestbranding: null, + origin: null, + playlist: null, + playsinline: null, + rel: 0, + showinfo: 1, + start: 0, + wmode: 'transparent', + theme: 'dark', + }, + ratio: '16:9', + vimeo: { + api: false, + autopause: true, + autoplay: true, + byline: true, + callback: null, + color: null, + height: null, + loop: false, + maxheight: null, + maxwidth: null, + player_id: null, + portrait: true, + title: true, + width: null, + xhtml: false, + }, + youku: { + autoplay: 1, + show_related: 0, + }, + allowFullScreen: true, + animationSpeed: 300, + classNames: { + modalVideoEffect: 'modal-video-effect', + modalVideo: 'modal-video', + modalVideoClose: 'modal-video-close', + modalVideoBody: 'modal-video-body', + modalVideoInner: 'modal-video-inner', + modalVideoIframeWrap: 'modal-video-movie-wrap', + modalVideoCloseBtn: 'modal-video-close-btn', + }, + aria: { + openMessage: 'You just openned the modal video', + dismissBtnMessage: 'Close the modal by clicking here', + }, + }; + public modal: any; + public modalbtn: any; + constructor(props: ModalVideoProps) { + super(props); + this.state = { + isOpen: false, + }; + } + + public openModal = (): void => { + this.setState({ isOpen: true }); + }; + + public closeModal = (): void => { + this.setState({ isOpen: false }); + if (typeof this.props.onClose === 'function') { + this.props.onClose(); + } + }; + + public keydownHandler(e: any): void { + if (e.keyCode === 27) { + this.closeModal(); + } + } + + public componentDidMount(): void { + document.addEventListener('keydown', this.keydownHandler.bind(this)); + } + + public componentWillUnmount(): void { + document.removeEventListener('keydown', this.keydownHandler.bind(this)); + } + + public componentWillReceiveProps(nextProps: ModalVideoProps): void { + this.setState({ isOpen: nextProps.isOpen }); + } + + public componentDidUpdate(): void { + if (this.state.isOpen && this.modal) { + this.modal.focus(); + } + } + + public updateFocus = (e: any): void => { + if (e.keyCode === 9) { + e.preventDefault(); + e.stopPropagation(); + if (this.modal === document.activeElement) { + this.modalbtn.focus(); + } else { + this.modal.focus(); + } + } + }; + + public getQueryString(obj: any): string { + let url = ''; + for (const key of Object.keys(obj)) { + if (obj.hasOwnProperty(key)) { + if (obj[key] !== null) { + url += `${key}=${obj[key]}&`; + } + } + } + return url.substr(0, url.length - 1); + } + + public getYoutubeUrl(youtube: any, videoId: string): string { + const query = this.getQueryString(youtube); + return `//www.youtube.com/embed/${videoId}?${query}`; + } + + public getVimeoUrl(vimeo: any, videoId: string): string { + const query = this.getQueryString(vimeo); + return `//play.vimeo.com/video/${videoId}?${query}`; + } + + public getYoukuUrl(youku: any, videoId: string): string { + const query = this.getQueryString(youku); + return `//player.youku.com/embed/${videoId}?${query}`; + } + + public getVideoUrl(opt: any, videoId: string): string { + if (opt.channel === 'youtube') { + return this.getYoutubeUrl(opt.youtube, videoId); + } else if (opt.channel === 'vimeo') { + return this.getVimeoUrl(opt.vimeo, videoId); + } else if (opt.channel === 'youku') { + return this.getYoukuUrl(opt.youku, videoId); + } + return ''; + } + + public getPadding(ratio: string): string { + const arr = ratio.split(':'); + const width = Number(arr[0]); + const height = Number(arr[1]); + const padding = (height * 100) / width; + return `${padding}%`; + } + + public render(): React.ReactNode { + const style = { + paddingBottom: this.getPadding(this.props.ratio), + }; + return ( + + {() => { + if (!this.state.isOpen) { + return null; + } + return ( +
{ + this.modal = node; + }} + onKeyDown={this.updateFocus} + > +
+
+
+