Compare commits

..

1 Commits

Author SHA1 Message Date
Fabio Berger
58a149485b Updated CHANGELOGS 2018-07-23 19:29:10 +02:00
2402 changed files with 176979 additions and 129396 deletions

View File

@@ -1,408 +1,236 @@
version: 2
jobs:
build:
resource_class: medium+
docker:
- image: circleci/node:9-browsers
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:
name: install-yarn
command: sudo npm install --global yarn@1.9.4
- run:
name: yarn
command: yarn --frozen-lockfile --ignore-engines install
- run: yarn build:ci:no_website
- run: yarn build:ts
- save_cache:
key: repo-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo
build-website:
resource_class: medium+
docker:
- image: circleci/node:9-browsers
working_directory: ~/repo
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run: cd packages/website && yarn build:prod
test-contracts-ganache:
docker:
- image: circleci/node:9-browsers
working_directory: ~/repo
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn wsrun test:circleci @0x/contracts-multisig
- run: yarn wsrun test:circleci @0x/contracts-utils
- run: yarn wsrun test:circleci @0x/contracts-libs
- run: yarn wsrun test:circleci @0x/contracts-tokens
- run: yarn wsrun test:circleci @0x/contracts-extensions
- run: yarn wsrun test:circleci @0x/contracts-protocol
test-contracts-geth:
docker:
- image: circleci/node:9-browsers
- image: 0xorg/devnet
working_directory: ~/repo
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
# HACK(albrow): we need to sleep 10 seconds to ensure the devnet is
# initialized
- run: sleep 10 && TEST_PROVIDER=geth yarn wsrun test @0x/contracts-multisig
- run: TEST_PROVIDER=geth yarn wsrun test @0x/contracts-utils
- run: TEST_PROVIDER=geth yarn wsrun test @0x/contracts-libs
- run: TEST_PROVIDER=geth yarn wsrun test @0x/contracts-tokens
- run: TEST_PROVIDER=geth yarn wsrun test @0x/contracts-extensions
- run: TEST_PROVIDER=geth yarn wsrun test @0x/contracts-protocol
test-publish:
resource_class: medium+
docker:
- image: circleci/node:9-browsers
- image: 0xorg/verdaccio
working_directory: ~/repo
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn test:publish:circleci
test-doc-generation:
docker:
- image: circleci/node:9-browsers
working_directory: ~/repo
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn test:generate_docs:circleci
test-pipeline:
docker:
- image: circleci/node:9
- image: postgres:11-alpine
working_directory: ~/repo
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run: ZEROEX_DATA_PIPELINE_TEST_DB_URL='postgresql://postgres@localhost/postgres' yarn wsrun test:circleci @0x/pipeline
- save_cache:
key: coverage-pipeline-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/pipeline/coverage/lcov.info
test-rest:
docker:
- image: circleci/node:9-browsers
working_directory: ~/repo
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn wsrun test:circleci @0x/contracts-test-utils
- run: yarn wsrun test:circleci @0x/abi-gen
- run: yarn wsrun test:circleci @0x/assert
- run: yarn wsrun test:circleci @0x/base-contract
- run: yarn wsrun test:circleci @0x/connect
- run: yarn wsrun test:circleci @0x/contract-wrappers
- run: yarn wsrun test:circleci @0x/dev-utils
- run: yarn wsrun test:circleci @0x/json-schemas
- run: yarn wsrun test:circleci @0x/metacoin
- 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
- run: yarn wsrun test:circleci @0x/subproviders
- run: yarn wsrun test:circleci @0x/web3-wrapper
- run: yarn wsrun test:circleci @0x/utils
- run: yarn wsrun test:circleci @0x/instant
- save_cache:
key: coverage-abi-gen-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/abi-gen/coverage/lcov.info
- save_cache:
key: coverage-assert-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/assert/coverage/lcov.info
- save_cache:
key: coverage-base-contract-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/base-contract/coverage/lcov.info
- save_cache:
key: coverage-connect-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/connect/coverage/lcov.info
- save_cache:
key: coverage-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/contract-wrappers/coverage/lcov.info
- save_cache:
key: coverage-dev-utils-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/dev-utils/coverage/lcov.info
- save_cache:
key: coverage-json-schemas-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/json-schemas/coverage/lcov.info
- save_cache:
key: coverage-metacoin-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/metacoin/coverage/lcov.info
- save_cache:
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:
- ~/repo/packages/sol-compiler/coverage/lcov.info
- save_cache:
key: coverage-sol-tracing-utils-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/sol-tracing-utils/coverage/lcov.info
- save_cache:
key: coverage-sol-doc-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/sol-doc/coverage/lcov.info
- save_cache:
key: coverage-subproviders-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/subproviders/coverage/lcov.info
- save_cache:
key: coverage-web3-wrapper-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/web3-wrapper/coverage/lcov.info
test-python:
working_directory: ~/repo
docker:
- image: circleci/python
- image: 0xorg/ganache-cli:2.2.2
- image: 0xorg/launch-kit-ci
command: |
yarn start:ts -p 3000:3000
steps:
- checkout
- run: sudo chown -R circleci:circleci /usr/local/bin
- run: sudo chown -R circleci:circleci /usr/local/lib/python3.7/site-packages
- restore_cache:
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
- run:
command: |
cd python-packages
python -m ensurepip
./install
- save_cache:
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
paths:
- '/usr/local/bin'
- '/usr/local/lib/python3.7/site-packages'
- run:
command: |
cd python-packages
./cmd_pkgs_in_dep_order.py coverage run setup.py test
- save_cache:
key: coverage-python-contract-addresses-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/python-packages/contract_addresses/.coverage
- save_cache:
key: coverage-python-contract-artifacts-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/python-packages/contract_artifacts/.coverage
- save_cache:
key: coverage-python-contract-demo-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/python-packages/contract_demo/.coverage
- save_cache:
key: coverage-python-json-schemas-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/python-packages/json_schemas/.coverage
- save_cache:
key: coverage-python-order-utils-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/python-packages/order_utils/.coverage
- save_cache:
key: coverage-python-sra-client-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/python-packages/sra_client/.coverage
test-rest-python:
working_directory: ~/repo
docker:
- image: circleci/python
steps:
- checkout
- run: sudo chown -R circleci:circleci /usr/local/bin
- run: sudo chown -R circleci:circleci /usr/local/lib/python3.7/site-packages
- restore_cache:
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
- run:
command: |
cd python-packages/order_utils
python -m ensurepip
python -m pip install .
- save_cache:
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
paths:
- '/usr/local/bin'
- '/usr/local/lib/python3.7/site-packages'
- '.eggs'
- '.mypy_cache'
- '.pytest_cache'
- '.tox'
- run:
command: |
cd python-packages/order_utils
tox
static-tests-python:
working_directory: ~/repo
docker:
- image: circleci/python
steps:
- checkout
- run: sudo chown -R circleci:circleci /usr/local/bin
- run: sudo chown -R circleci:circleci /usr/local/lib/python3.7/site-packages
- restore_cache:
key: deps9-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
- run:
command: |
python -m ensurepip
cd python-packages
./install
./lint
static-tests:
working_directory: ~/repo
docker:
- image: circleci/node:9-browsers
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn lerna run lint
- run: yarn prettier:ci
- run: cd packages/0x.js && yarn build:umd:prod
- run: yarn bundlewatch
submit-coverage:
docker:
- image: circleci/node:9-browsers
working_directory: ~/repo
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-abi-gen-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-assert-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-base-contract-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-connect-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-dev-utils-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-json-schemas-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-metacoin-{{ .Environment.CIRCLE_SHA1 }}
- 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 }}
- restore_cache:
keys:
- coverage-sol-tracing-utils-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-sol-doc-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-subproviders-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-web3-wrapper-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-contracts-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-python-json-schemas-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-python-contract-addresses-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-python-contract-artifacts-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-python-contract-demo-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-python-sra-client-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-python-order-utils-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn report_coverage
build:
docker:
- image: circleci/node:9
environment:
CONTRACTS_COMMIT_HASH: '9ed05f5'
working_directory: ~/repo
steps:
- checkout
- run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV
- restore_cache:
name: Restore Yarn Package Cache
keys:
- yarn-packages-{{ .Branch }}-{{ checksum "yarn.lock" }}
- yarn-packages-{{ .Branch }}
- yarn-packages-master
- yarn-packages-
- run:
name: yarn
command: yarn --frozen-lockfile install
- save_cache:
name: Save Yarn Package Cache
key: yarn-packages-{{ .Branch }}-{{ checksum "yarn.lock" }}
paths:
- node_modules/
- run: >
if [ -z "$(git diff --name-only v2-prototype packages/website)" ]; then
yarn build --exclude website
else
yarn build
fi
- save_cache:
key: repo-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo
test-contracts-ganache:
docker:
- image: circleci/node:9
working_directory: ~/repo
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn wsrun test:circleci contracts
test-contracts-geth:
docker:
- image: circleci/node:9
- image: albrow/0x-devnet
working_directory: ~/repo
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
# HACK(albrow): we need to sleep 10 seconds to ensure the devnet is
# initialized
- run: sleep 10 && TEST_PROVIDER=geth yarn wsrun test contracts
test-rest:
docker:
- image: circleci/node:9
working_directory: ~/repo
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn wsrun test:circleci 0x.js
- run: yarn wsrun test:circleci @0xproject/abi-gen
- run: yarn wsrun test:circleci @0xproject/assert
- run: yarn wsrun test:circleci @0xproject/base-contract
- run: yarn wsrun test:circleci @0xproject/connect
- run: yarn wsrun test:circleci @0xproject/contract-wrappers
- run: yarn wsrun test:circleci @0xproject/dev-utils
- run: yarn wsrun test:circleci @0xproject/json-schemas
- run: yarn wsrun test:circleci @0xproject/metacoin
- run: yarn wsrun test:circleci @0xproject/order-utils
- run: yarn wsrun test:circleci @0xproject/order-watcher
- run: yarn wsrun test:circleci @0xproject/sol-compiler
- run: yarn wsrun test:circleci @0xproject/sol-cov
- run: yarn wsrun test:circleci @0xproject/sra-report
- run: yarn wsrun test:circleci @0xproject/subproviders
- run: yarn wsrun test:circleci @0xproject/web3-wrapper
- save_cache:
key: coverage-0xjs-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/0x.js/coverage/lcov.info
- save_cache:
key: coverage-abi-gen-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/abi-gen/coverage/lcov.info
- save_cache:
key: coverage-assert-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/assert/coverage/lcov.info
- save_cache:
key: coverage-base-contract-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/base-contract/coverage/lcov.info
- save_cache:
key: coverage-connect-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/connect/coverage/lcov.info
- save_cache:
key: coverage-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/contract-wrappers/coverage/lcov.info
- save_cache:
key: coverage-dev-utils-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/dev-utils/coverage/lcov.info
- save_cache:
key: coverage-json-schemas-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/json-schemas/coverage/lcov.info
- save_cache:
key: coverage-metacoin-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/metacoin/coverage/lcov.info
- save_cache:
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:
- ~/repo/packages/sol-compiler/coverage/lcov.info
- save_cache:
key: coverage-sol-cov-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/sol-cov/coverage/lcov.info
- save_cache:
key: coverage-sra-report-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/sra-report/coverage/lcov.info
- save_cache:
key: coverage-subproviders-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/subproviders/coverage/lcov.info
- save_cache:
key: coverage-web3-wrapper-{{ .Environment.CIRCLE_SHA1 }}
paths:
- ~/repo/packages/web3-wrapper/coverage/lcov.info
static-tests:
working_directory: ~/repo
docker:
- image: circleci/node:9
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn prettier:ci
- run: yarn lerna:run lint
submit-coverage:
docker:
- image: circleci/node:9
working_directory: ~/repo
steps:
- restore_cache:
keys:
- repo-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-0xjs-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-abi-gen-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-assert-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-base-contract-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-connect-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-dev-utils-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-json-schemas-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-metacoin-{{ .Environment.CIRCLE_SHA1 }}
- 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 }}
- restore_cache:
keys:
- coverage-sol-cov-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-sra-report-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-subproviders-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-web3-wrapper-{{ .Environment.CIRCLE_SHA1 }}
- restore_cache:
keys:
- coverage-contracts-{{ .Environment.CIRCLE_SHA1 }}
- run: yarn report_coverage
workflows:
version: 2
main:
jobs:
version: 2
main:
jobs:
- build
- test-contracts-ganache:
requires:
- build
- build-website:
requires:
- build
- test-contracts-ganache:
requires:
- build
- test-contracts-geth:
requires:
- build
- test-pipeline:
requires:
- build
- test-rest:
requires:
- build
- static-tests:
requires:
- build
- test-publish:
requires:
- build
- test-doc-generation:
requires:
- build
- submit-coverage:
requires:
- test-rest
- test-python
- static-tests-python:
requires:
- test-python
- test-python
# skip python tox run for now, as we don't yet have multiple test environments to support.
#- test-rest-python
- test-contracts-geth:
requires:
- build
- test-rest:
requires:
- build
- static-tests:
requires:
- build
- submit-coverage:
requires:
- test-rest

6
.gitattributes vendored
View File

@@ -1,7 +1 @@
*.sol linguist-language=Solidity
# Automatically collapse generated files in GitHub.
*.svg linguist-generated
packages/contract-artifacts/artifacts/*json linguist-generated
packages/abi-gen-wrappers/wrappers/*.ts liguist-generated

View File

@@ -1,42 +0,0 @@
python: ['python-packages']
contracts: ['contracts']
sol-doc: ['packages/sol-doc']
sol-resolver: ['packages/sol-resolver']
sra-spec: ['packages/sra-spec']
subproviders: ['packages/subproviders']
contract-addresses: ['packages/contract-addresses']
migrations: ['packages/migrations']
web3-wrapper: ['packages/web3-wrapper']
sol-compiler: ['packages/sol-compiler']
types: ['packages/types']
instant: ['packages/instant']
abi-gen-templates: ['packages/abi-gen-templates']
abi-gen: ['packages/abi-gen']
website: ['packages/website']
sol-coverage: ['packages/sol-coverage']
sol-profiler: ['packages/sol-profiler']
sol-trace: ['packages/sol-trace']
sol-tracing-utils: ['packages/sol-tracing-utils']
utils: ['packages/utils']
tslint-config: ['packages/tslint-config']
asset-buyer: ['packages/asset-buyer']
order-watcher: ['packages/order-watcher']
react-docs: ['packages/react-docs']
order-utils: ['packages/order-utils']
react-shared: ['packages/react-shared']
assert: ['packages/assert']
base-contract: ['packages/base-contract']
typescript-typings: ['packages/typescript-typings']
0x.js: ['packages/0x.js']
abi-gen-wrappers: ['packages/abi-gen-wrappers']
metacoin: ['packages/metacoin']
contract-artifacts: ['packages/contract-artifacts']
dev-utils: ['packages/dev-utils']
contract-wrappers: ['packages/contract-wrappers']
json-schemas: ['packages/json-schemas']
ethereum-types: ['ethereum-types']
connect: ['packages/connect']
fill-scenarios: ['packages/fill-scenarios']
dev-tools-pages: ['packages/dev-tools-pages']
testnet-faucets: ['packages/testnet-faucets']
monorepo-scripts: ['packages/monorepo-scripts']

19
.github/stale.yml vendored
View File

@@ -1,19 +0,0 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 30
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 30
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: >
This issue has been automatically closed because no activity occured in 7 days after being marked as stale. If it's still relevant - feel free to reopen. Thank you
for your contributions.

46
.gitignore vendored
View File

@@ -11,10 +11,6 @@ pids
*.seed
*.pid.lock
# SQLite database files
*.db
*.sqlite
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
@@ -45,7 +41,6 @@ typings/
# Optional npm cache directory
.npm
.npmrc
# Optional eslint cache
.eslintcache
@@ -76,48 +71,31 @@ TODO.md
.vscode
packages/website/public/bundle*
packages/dev-tools-pages/public/bundle*
packages/react-docs/example/public/bundle*
# server cli
packages/testnet-faucets/server/
# generated contract artifacts/
contracts/protocol/generated-artifacts/
contracts/multisig/generated-artifacts/
contracts/utils/generated-artifacts/
contracts/libs/generated-artifacts/
contracts/interfaces/generated-artifacts/
contracts/tokens/generated-artifacts/
contracts/examples/generated-artifacts/
contracts/extensions/generated-artifacts/
packages/sol-tracing-utils/test/fixtures/artifacts/
packages/sol-cov/test/fixtures/artifacts/
packages/metacoin/artifacts/
packages/order-watcher/test/artifacts/
packages/contract-wrappers/test/artifacts/
# generated contract wrappers
packages/abi-gen-wrappers/wrappers
contracts/protocol/generated-wrappers/
contracts/multisig/generated-wrappers/
contracts/utils/generated-wrappers/
contracts/libs/generated-wrappers/
contracts/interfaces/generated-wrappers/
contracts/tokens/generated-wrappers/
contracts/examples/generated-wrappers/
contracts/extensions/generated-wrappers/
packages/0x.js/src/generated_contract_wrappers/
packages/contracts/generated_contract_wrappers/
packages/contract-wrappers/src/contract_wrappers/generated/
packages/metacoin/src/contract_wrappers
packages/fill-scenarios/src/generated_contract_wrappers/
packages/order-watcher/src/generated_contract_wrappers/
packages/order-utils/src/generated_contract_wrappers/
packages/migrations/src/1.0.0/contract_wrappers
packages/migrations/src/2.0.0/contract_wrappers
packages/migrations/src/2.0.0-beta-testnet/contract_wrappers
# solc-bin in sol-compiler
packages/sol-compiler/solc_bin/
# Monorepo scripts
packages/*/scripts/
# python stuff
.eggs
.mypy_cache
.tox
python-packages/*/build
python-packages/*/dist
__pycache__
python-packages/*/src/*.egg-info
python-packages/*/.coverage

View File

@@ -1,33 +1,22 @@
lib
.nyc_output
/contracts/protocol/generated-wrappers
/contracts/protocol/generated-artifacts
/contracts/multisig/generated-wrappers
/contracts/multisig/generated-artifacts
/contracts/utils/generated-wrappers
/contracts/utils/generated-artifacts
/contracts/libs/generated-wrappers
/contracts/libs/generated-artifacts
/contracts/interfaces/generated-wrappers
/contracts/interfaces/generated-artifacts
/contracts/tokens/generated-wrappers
/contracts/tokens/generated-artifacts
/contracts/examples/generated-wrappers
/contracts/examples/generated-artifacts
/contracts/extensions/generated-wrappers
/contracts/extensions/generated-artifacts
/packages/abi-gen-wrappers/src/generated-wrappers
/packages/contract-artifacts/artifacts
/python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts
/packages/json-schemas/schemas
/python-packages/json_schemas/src/zero_ex/json_schemas/schemas
/packages/contract-wrappers/src/contract_wrappers/generated/
/packages/metacoin/src/contract_wrappers
/packages/0x.js/src/generated_contract_wrappers/
/packages/contracts/generated_contract_wrappers/
/packages/fill-scenarios/src/generated_contract_wrappers/
/packages/order-watcher/src/generated_contract_wrappers/
/packages/order-utils/src/generated_contract_wrappers/
/packages/migrations/src/1.0.0/contract_wrappers
/packages/migrations/src/2.0.0/contract_wrappers
/packages/migrations/src/2.0.0-beta-testnet/contract_wrappers
/packages/0x.js/src/artifacts
/packages/contracts/src/artifacts
/packages/metacoin/artifacts
/packages/sra-spec/public/
/packages/dev-tools-pages/ts/**/data.json
/packages/contract-wrappers/test/artifacts
/packages/order-watcher/test/artifacts
/packages/migrations/artifacts/1.0.0
/packages/migrations/artifacts/2.0.0
/packages/migrations/artifacts/2.0.0-beta-testnet
package.json
scripts/postpublish_utils.js
packages/sol-coverage/test/fixtures/artifacts
.pytest_cache
.mypy_cache
.tox

View File

@@ -1,38 +0,0 @@
# See https://help.github.com/articles/about-codeowners/
# for more info about CODEOWNERS file
# It uses the same pattern rule for gitignore file
# https://git-scm.com/docs/gitignore#_pattern_format
# Website
packages/asset-buyer/ @BMillman19 @fragosti @steveklebanoff
packages/instant/ @BMillman19 @fragosti @steveklebanoff
packages/website/ @BMillman19 @fragosti @fabioberger @steveklebanoff
# Dev tools & setup
.circleci/ @LogvinovLeon
packages/abi-gen/ @LogvinovLeon
packages/base-contract/ @LogvinovLeon
packages/connect/ @fragosti
packages/abi-gen-templates/ @LogvinovLeon
packages/contract-addresses/ @albrow
packages/contract-artifacts/ @albrow
packages/dev-utils/ @LogvinovLeon @fabioberger
packages/devnet/ @albrow
packages/ethereum-types/ @LogvinovLeon
packages/metacoin/ @LogvinovLeon
packages/monorepo-scripts/ @fabioberger
packages/order-utils/ @fabioberger @LogvinovLeon
packages/sol-compiler/ @LogvinovLeon
packages/sol-coverage/ @LogvinovLeon
packages/sol-profiler/ @LogvinovLeon
packages/sol-trace/ @LogvinovLeon
packages/sol-tracing-utils/ @LogvinovLeon
packages/sol-resolver/ @LogvinovLeon
packages/subproviders/ @fabioberger @dekz
packages/verdaccio/ @albrow
packages/web3-wrapper/ @LogvinovLeon @fabioberger
python-packages/ @feuGeneA
# Protocol/smart contracts
contracts/core/test/ @albrow

View File

@@ -8,19 +8,19 @@ In the interest of fostering an open and welcoming environment, we as contributo
Examples of behavior that contributes to creating a positive environment include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities

View File

@@ -1,105 +1,61 @@
## 0x Contribution Guide
We welcome contributions from anyone on the internet and are grateful for even the smallest contributions. This document will help get you setup to start contributing back to 0x.
Thank you for your interest in contributing to 0x protocol! We welcome contributions from anyone on the internet, and are grateful for even the smallest of fixes!
### Getting started
### How to contribute
1. Fork `0xproject/0x-monorepo`
2. Clone your fork
3. Follow the [installation & build steps](https://github.com/0xProject/0x-monorepo#install-dependencies) in the repo's top-level README.
4. Setup the recommended [Development Tooling](#development-tooling).
5. Open a PR with the `[WIP]` flag against the `development` branch and describe the change you are intending to undertake in the PR description. (see [our branch naming conventions](#branch-structure))
If you'd like to contribute to 0x protocol, please fork the repo, fix, commit and send a pull request against the `development` branch for the maintainers to review and merge into the main code base. If you wish to submit more complex changes though, please check with a core dev first on [our RocketChat #dev channel](http://chat.0xproject.com) to ensure those changes are in-line with the general philosophy of the project and/or to get some early feedback which can make both your efforts easier as well as our review and merge procedures quick and simple.
Before removing the `[WIP]` tag and submitting the PR for review, make sure:
We encourage a “PR early” approach so create the PR as early as possible even without the fix/feature ready, so that devs and other contributors know you have picked up the issue. These early PRs should indicate an 'in progress' status by adding the '[WIP]' prefix to the PR title. Please make sure your contributions adhere to our coding guidelines:
- It passes our linter checks (`yarn lint`)
- It is properly formatted with Prettier (`yarn prettier`)
- It passes our continuous integration tests (See: [Enabling code coverage checks on your fork](#enabling-code-coverage-checks-on-your-fork) for instructions on getting the `submit-coverage` test to pass on forks)
- You've created/updated the corresponding [CHANGELOG](#CHANGELOGs) entries.
- Your changes have sufficient test coverage (e.g regression tests have been added for bug fixes)
* Pull requests adding features or refactoring should be opened against the `development` branch
* Pull requests fixing bugs in the latest release version should be opened again the `master` branch
* Write [good commit messages](https://chris.beams.io/posts/git-commit/)
### Branch structure
### Code quality
We have two main branches:
Because 0x.js is used by multiple relayers in production and their businesses depend on it, we strive for exceptional code quality. Please follow the existing code standards and conventions. `tslint` and `prettier` (described below) will help you.
- `master` represents the most recently released (published on npm) version of the codebase.
- `development` represents the current development state of the codebase.
If you're adding functionality, please also add tests and make sure they pass. We have an automatic coverage reporting tool, so we'll see it if they are missing ;)
If you're adding a new public function/member, make sure you document it with Java doc-style comments. We use typedoc to generate [awesome documentation](https://0xproject.com/docs/0xjs) from the comments within our source code.
ALL PRs should be opened against `development`.
If the sub-package you are modifying has a `CHANGELOG.md` file, make sure to add an entry in it for the change made to the package. For published packages, only changes that modify the public interface or behavior of the package need a CHANGELOG entry.
Branch names should be prefixed with `fix`, `feature` or `refactor`.
#### Enabling code coverage checks on your fork
- e.g `fix/broken-wiki-link`
- If the PR only edits a single package, add it's name too
- e.g `fix/website/broken-wiki-link`
### CHANGELOGs
At 0x we use [Semantic Versioning](http://semver.org/) for all our published packages. If a change you make corresponds to a semver bump, you must modify the package's `CHANGELOG.json` file accordingly.
Each CHANGELOG entry that corresponds to a published package will have a `timestamp`. If no entry exists without a `timestamp`, you must first create a new one:
```
{
"version": "1.0.1", <- The updated package version
"changes": [
{
"note": "", <- Describe your change
"PR": 100 <- Your PR number
}
]
},
```
If an entry without a `timestamp` already exists, this means other changes have been introduced by other collaborators since the last publish. Add your changes to the list of notes and adjust the version if your PR introduces a greater semver change (i.e current changes required a patch bump, but your changes require a major version bump).
### Development Tooling
We strongly recommend you use the [VSCode](https://code.visualstudio.com/) text editor since most of our code is written in Typescript and it offers amazing support for the language.
#### Linter
We use [TSLint](https://palantir.github.io/tslint/) with [custom configs](https://github.com/0xProject/0x-monorepo/tree/development/packages/tslint-config) to keep our code-style consistent.
Use `yarn:lint` to lint the entire monorepo, and `PKG={PACKAGE_NAME} yarn lint` to lint a specific package.
If you want to change a rule, or add a custom rule, please make these changes to our [tslint-config](https://github.com/0xProject/0x-monorepo/tree/development/packages/tslint-config) package. All other packages have it as a dependency.
Integrate it into your text editor:
- VSCode: [vscode-tslint](https://marketplace.visualstudio.com/items?itemName=eg2.tslint)
- Atom: [linter-tslint](https://atom.io/packages/linter-tslint)
#### Auto-formatter
We use [Prettier](https://prettier.io/) to auto-format our code. Be sure to either add a [text editor integration](https://prettier.io/docs/en/editors.html) or a [pre-commit hook](https://prettier.io/docs/en/precommit.html) to properly format your code changes.
If using the Atom text editor, we recommend you install the following packages:
- VSCode: [prettier-vscode](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)
- Atom: [prettier-atom](https://atom.io/packages/prettier-atom)
## Unenforced coding conventions
A few of our coding conventions are not yet enforced by the linter/auto-formatter. Be careful to follow these conventions in your PR's.
1. Unused anonymous function parameters should be named with an underscore + number (e.g \_1, \_2, etc...)
1. There should be a new-line between methods in a class and between test cases.
1. If a string literal has the same value in two or more places, it should be a single constant referenced in both places.
1. Do not import from a project's `index.ts` (e.g import { Token } from '../src';). Always import from the source file itself.
1. Generic error variables should be named `err` instead of `e` or `error`.
1. If you _must_ cast a variable to any - try to type it back as fast as possible. (e.g., `const cw = ((zeroEx as any)._contractWrappers as ContractWrappers);`). This ensures subsequent code is type-safe.
1. Our enum conventions coincide with the recommended Typescript conventions, using capitalized keys, and all-caps snake-case values. Eg `GetStats = 'GET_STATS'`
1. All public, exported methods/functions/classes must have associated Javadoc-style comments.
### Fix `submit-coverage` CI failure
If you simply fork the repo and then create a PR from it, your PR will fail the `submit-coverage` check on CI. This is because the 0x CircleCI configuration sets the `COVERALLS_REPO_TOKEN` environment variable to the token for `0xProject/0x-monorepo`, but when running the check against your fork the token needs to match your repo's name `your-username/0x-monorepo`.
If you simply fork the repo and then create a PR sourced from it, your PR will fail its test coverage check. This is because the 0x CircleCI configuration sets the `COVERALLS_REPO_TOKEN` environment variable to the token for 0xProject/0x-monorepo, but when running the check against your fork the token needs to match the repo that is your fork, rather than the 0x repo.
To facilitate this check, after creating your fork, but before creating the branch for your PR, do the following:
1. Log in to [coveralls.io](https://coveralls.io/), go to `Add Repos`, and enable your fork. Then go to the settings for that repo, and copy the `Repo Token` identifier.
2. Log in to [CircleCI](https://circleci.com/login), go to `Add Projects`, click the `Set Up Project` button corresponding to your fork, and then click `Start Building`. (Aside from step 3 below, no actual set up is needed, since it will use the `.circleci/config.yml` file in 0x-monorepo, so you can ignore all of the instruction/explanation given on the page with the `Start Building` button.)
3. In CircleCI, configure your project to add an environment variable, with name `COVERALLS_REPO_TOKEN`, and for the value paste in the `Repo Token` you copied in step 1.
1. Log in to [coveralls.io](https://coveralls.io/), go to Add Repos, and enable your fork. Then go to the settings for that repo, and copy the Repo Token identifier.
2. Log in to [CircleCI](https://circleci.com/login), go to Add Projects, click the Set Up Project button corresponding to your fork, and then click Start Building. (Aside from step 3 below, no actual set up is needed, since it will use the `.circleci/config.yml` file in 0x-monorepo, so you can ignore all of the instruction/explanation given on the page with the Start Building button.)
3. In CircleCI, configure your project to add an Environment Variable, with name `COVERALLS_REPO_TOKEN`, and for the value paste in the Repo Token you copied in step 1.
Now, when you push to your branch, CircleCI will automatically run all of the checks in your own instance, and the coverage check will work since it has the proper `Repo Token`, and the PR will magically refer to your own checks rather than running them in the 0x CircleCI instance.
Now, when you push to your branch, CircleCI will automatically run all of the checks in your own instance, and the coverage check will work since it has the proper Repo Token, and the PR will magically refer to your own checks rather than running them in the 0x CircleCI instance.
### Styleguide
We use [TSLint](https://palantir.github.io/tslint/) with [custom configs](https://github.com/0xProject/0x-monorepo/tree/development/packages/tslint-config) to keep our code style consistent.
To lint your code just run: `yarn lint`
We also use [Prettier](https://prettier.io/) to auto-format our code. Be sure to either add a [text editor integration](https://prettier.io/docs/en/editors.html) or a [pre-commit hook](https://prettier.io/docs/en/precommit.html) to properly format your code changes.
If using the Atom text editor, we recommend you install the following packages:
* [atom-typescript](https://atom.io/packages/atom-typescript)
* [linter-tslint](https://atom.io/packages/linter-tslint)
* [prettier-atom](https://atom.io/packages/prettier-atom)
* [language-ethereum](https://atom.io/packages/language-ethereum)
Our CI will also run TSLint and Prettier as a part of the test run when you submit your PR. Make sure that the CI tests pass for your contribution.
### Branch structure & versioning
We use [semantic versioning](http://semver.org/), but before a package reaches v1.0.0 all breaking changes as well as new features will be minor version bumps.
We have two main branches: `master` and `development`.
`master` represents the most recent released (published on npm) version.
`development` represents the development state and is a default branch to which you will submit a PR. We use this structure so that we can push hotfixes to the currently released version without needing to publish all the changes made towards the next release. If a hotfix is implemented on `master`, it is back-ported to `development`.

View File

@@ -46,14 +46,10 @@
<!--- Include as many relevant details about the environment you experienced the bug in -->
| Package | Version |
| ------: | :------ |
<!-- For example:
| `0x.js` | 2.0.4 |
| `Exchange Contract` | v2 |
-->
| Package | Version |
| ------------------: | :------ |
| `0x.js` | 0.25.0 |
| `Exchange Contract` | v1 |
| Network |
| ------- |

View File

@@ -1,4 +1,4 @@
Copyright 2017 ZeroEx Intl.
Copyright 2017 ZeroEx Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -10,4 +10,4 @@ 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.
limitations under the License.

View File

@@ -20,7 +20,8 @@
<!--- The following points should be used to indicate the progress of your PR. Put an `x` in all the boxes that apply right now, and come back over time and check them off as you make progress. If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] Prefix PR title with `[WIP]` if necessary.
- [ ] Add tests to cover changes as needed.
- [ ] Update documentation as needed.
- [ ] Add new entries to the relevant CHANGELOG.jsons.
* [ ] Prefixed the title of this PR with `[WIP]` if it is a work in progress.
* [ ] Prefixed the title of this PR with bracketed package name(s) corresponding to the changed package(s). For example: `[sol-cov] Fixed bug`.
* [ ] Added tests to cover my changes, or decided that tests would be too impractical.
* [ ] Updated documentation, or decided that no doc change is needed.
* [ ] Added new entries to the relevant CHANGELOG.jsons.

128
README.md
View File

@@ -1,14 +1,14 @@
<img src="https://github.com/0xProject/branding/blob/master/0x%20Logo/PNG/0x-Logo-Black.png" width="150px" >
<img src="https://github.com/0xProject/branding/blob/master/0x_Black_CMYK.png" width="200px" >
---
[0x][website-url] is an open protocol that facilitates trustless, low friction exchange of Ethereum-based assets. For more information on how it works, check out the [0x protocol specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md).
[0x][website-url] is an open protocol that facilitates trustless, low friction exchange of Ethereum-based assets. A full description of the protocol may be found in our [whitepaper][whitepaper-url].
This repository is a monorepo including the 0x protocol smart contracts and numerous developer tools. Each public sub-package is independently published to NPM.
If you're developing on 0x now or are interested in using 0x infrastructure in the future, please join our [developer mailing list][dev-mailing-list-url] for updates.
[website-url]: https://0xproject.com
[website-url]: https://0xproject.com/
[whitepaper-url]: https://0xproject.com/pdfs/0x_white_paper.pdf
[dev-mailing-list-url]: http://eepurl.com/dx4cPf
@@ -18,86 +18,60 @@ If you're developing on 0x now or are interested in using 0x infrastructure in t
[![Join the chat at https://gitter.im/0xProject/Lobby](https://badges.gitter.im/0xProject/Lobby.svg)](https://gitter.im/0xProject/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
## Packages
### Published Packages
Visit our [developer portal](https://0xproject.com/docs/order-utils) for a comprehensive list of core & community maintained packages. All packages maintained with this monorepo are listed below.
| Package | Version | Description |
| --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| [`0x.js`](/packages/0x.js) | [![npm](https://img.shields.io/npm/v/0x.js.svg)](https://www.npmjs.com/package/0x.js) | A Javascript library for interacting with the 0x protocol |
| [`@0xproject/abi-gen`](/packages/abi-gen) | [![npm](https://img.shields.io/npm/v/@0xproject/abi-gen.svg)](https://www.npmjs.com/package/@0xproject/abi-gen) | Tool to generate TS wrappers from smart contract ABIs |
| [`@0xproject/assert`](/packages/assert) | [![npm](https://img.shields.io/npm/v/@0xproject/assert.svg)](https://www.npmjs.com/package/@0xproject/assert) | Type and schema assertions used by our packages |
| [`@0xproject/base-contract`](/packages/base-contract) | [![npm](https://img.shields.io/npm/v/@0xproject/base-contract.svg)](https://www.npmjs.com/package/@0xproject/base-contract) | BaseContract used by auto-generated `abi-gen` wrapper contracts |
| [`@0xproject/connect`](/packages/connect) | [![npm](https://img.shields.io/npm/v/@0xproject/connect.svg)](https://www.npmjs.com/package/@0xproject/connect) | A Javascript library for interacting with the Standard Relayer API |
| [`@0xproject/sol-compiler`](/packages/sol-compiler) | [![npm](https://img.shields.io/npm/v/@0xproject/sol-compiler.svg)](https://www.npmjs.com/package/@0xproject/sol-compiler) | A thin wrapper around Solc.js that outputs artifacts, resolves imports, only re-compiles when needed, and other niceties. |
| [`@0xproject/dev-utils`](/packages/dev-utils) | [![npm](https://img.shields.io/npm/v/@0xproject/dev-utils.svg)](https://www.npmjs.com/package/@0xproject/dev-utils) | Dev utils to be shared across 0x projects and packages |
| [`@0xproject/json-schemas`](/packages/json-schemas) | [![npm](https://img.shields.io/npm/v/@0xproject/json-schemas.svg)](https://www.npmjs.com/package/@0xproject/json-schemas) | 0x-related json schemas |
| [`@0xproject/monorepo-scripts`](/packages/monorepo-scripts) | [![npm](https://img.shields.io/npm/v/@0xproject/monorepo-scripts.svg)](https://www.npmjs.com/package/@0xproject/monorepo-scripts) | Monorepo scripts |
| [`@0xproject/react-docs`](/packages/react-docs) | [![npm](https://img.shields.io/npm/v/@0xproject/react-docs.svg)](https://www.npmjs.com/package/@0xproject/react-docs) | React documentation component for rendering TypeDoc & Doxity generated JSON |
| [`@0xproject/react-shared`](/packages/react-shared) | [![npm](https://img.shields.io/npm/v/@0xproject/react-shared.svg)](https://www.npmjs.com/package/@0xproject/react-shared) | 0x shared react components |
| [`@0xproject/sra-report`](/packages/sra-report) | [![npm](https://img.shields.io/npm/v/@0xproject/sra-report.svg)](https://www.npmjs.com/package/@0xproject/sra-report) | Generate reports for standard relayer API compliance |
| [`@0xproject/sol-cov`](/packages/sol-cov) | [![npm](https://img.shields.io/npm/v/@0xproject/sol-cov.svg)](https://www.npmjs.com/package/@0xproject/sol-cov) | Solidity test coverage tool |
| [`@0xproject/subproviders`](/packages/subproviders) | [![npm](https://img.shields.io/npm/v/@0xproject/subproviders.svg)](https://www.npmjs.com/package/@0xproject/subproviders) | Useful web3 subproviders (e.g LedgerSubprovider) |
| [`@0xproject/tslint-config`](/packages/tslint-config) | [![npm](https://img.shields.io/npm/v/@0xproject/tslint-config.svg)](https://www.npmjs.com/package/@0xproject/tslint-config) | Custom 0x development TSLint rules |
| [`@0xproject/types`](/packages/types) | [![npm](https://img.shields.io/npm/v/@0xproject/types.svg)](https://www.npmjs.com/package/@0xproject/types) | Shared type declarations |
| [`@0xproject/typescript-typings`](/packages/typescript-typings) | [![npm](https://img.shields.io/npm/v/@0xproject/typescript-typings.svg)](https://www.npmjs.com/package/@0xproject/typescript-typings) | Repository of types for external packages |
| [`@0xproject/utils`](/packages/utils) | [![npm](https://img.shields.io/npm/v/@0xproject/utils.svg)](https://www.npmjs.com/package/@0xproject/utils) | Shared utilities |
| [`@0xproject/web3-wrapper`](/packages/web3-wrapper) | [![npm](https://img.shields.io/npm/v/@0xproject/web3-wrapper.svg)](https://www.npmjs.com/package/@0xproject/web3-wrapper) | Web3 wrapper |
### Python Packages
### Private Packages
| Package | Version | Description |
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| [`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-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 |
### Typescript/Javascript Packages
#### 0x-specific packages
| Package | Version | Description |
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| [`0x.js`](/packages/0x.js) | [![npm](https://img.shields.io/npm/v/0x.js.svg)](https://www.npmjs.com/package/0x.js) | An aggregate package combining many smaller utility packages for interacting with the 0x protocol |
| [`@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/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` |
| [`@0x/sra-spec`](/packages/sra-spec) | [![npm](https://img.shields.io/npm/v/@0x/sra-spec.svg)](https://www.npmjs.com/package/@0x/sra-spec) | OpenAPI specification for the Standard Relayer API |
| [`@0x/connect`](/packages/connect) | [![npm](https://img.shields.io/npm/v/@0x/connect.svg)](https://www.npmjs.com/package/@0x/connect) | An HTTP/WS client for interacting with the Standard Relayer API |
| [`@0x/asset-buyer`](/packages/asset-buyer) | [![npm](https://img.shields.io/npm/v/@0x/asset-buyer.svg)](https://www.npmjs.com/package/@0x/asset-buyer) | Convenience package for discovering and buying assets with Ether |
#### Ethereum tooling
| Package | Version | Description |
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`@0x/web3-wrapper`](/packages/web3-wrapper) | [![npm](https://img.shields.io/npm/v/@0x/web3-wrapper.svg)](https://www.npmjs.com/package/@0x/web3-wrapper) | An Ethereum JSON RPC client |
| [`@0x/sol-compiler`](/packages/sol-compiler) | [![npm](https://img.shields.io/npm/v/@0x/sol-compiler.svg)](https://www.npmjs.com/package/@0x/sol-compiler) | A wrapper around solc-js that adds smart re-compilation, ability to compile an entire project, Solidity version specific compilation, standard input description support and much more. |
| [`@0x/sol-coverage`](/packages/sol-coverage) | [![npm](https://img.shields.io/npm/v/@0x/sol-coverage.svg)](https://www.npmjs.com/package/@0x/sol-coverage) | A solidity test coverage tool |
| [`@0x/sol-profiler`](/packages/sol-profiler) | [![npm](https://img.shields.io/npm/v/@0x/sol-profiler.svg)](https://www.npmjs.com/package/@0x/sol-profiler) | A solidity gas cost profiler |
| [`@0x/sol-trace`](/packages/sol-trace) | [![npm](https://img.shields.io/npm/v/@0x/sol-trace.svg)](https://www.npmjs.com/package/@0x/sol-trace) | A solidity stack trace tool |
| [`@0x/sol-resolver`](/packages/sol-resolver) | [![npm](https://img.shields.io/npm/v/@0x/sol-resolver.svg)](https://www.npmjs.com/package/@0x/sol-resolver) | Import resolver for smart contracts dependencies |
| [`@0x/subproviders`](/packages/subproviders) | [![npm](https://img.shields.io/npm/v/@0x/subproviders.svg)](https://www.npmjs.com/package/@0x/subproviders) | Web3 provider middlewares (e.g. LedgerSubprovider) |
| [`@0x/sol-doc`](/packages/sol-doc) | [![npm](https://img.shields.io/npm/v/@0x/sol-doc.svg)](https://www.npmjs.com/package/@0x/sol-doc) | Solidity documentation generator |
#### 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 |
#### Private Packages
| Package | Description |
| -------------------------------------------------- | -------------------------------------------------------------------------------- |
| [`@0x/contracts`](/contracts/core) | 0x protocol solidity smart contracts & tests |
| [`@0x/instant`](/packages/instant) | A free and flexible way to offer simple crypto purchasing in any app or website. |
| [`@0x/testnet-faucets`](/packages/testnet-faucets) | A faucet micro-service that dispenses test ERC20 tokens or Ether |
| [`@0x/website`](/packages/website) | 0x website |
| Package | Description |
| --------------------------------------------------------------- | ---------------------------------------------------------------- |
| [`@0xproject/contracts`](/packages/contracts) | 0x solidity smart contracts & tests |
| [`@0xproject/react-docs-example`](/packages/react-docs-example) | Example documentation site created with `@0xproject/react-docs` |
| [`@0xproject/testnet-faucets`](/packages/testnet-faucets) | A faucet micro-service that dispenses test ERC20 tokens or Ether |
| [`@0xproject/website`](/packages/website) | 0x website & Portal DApp |
## Usage
Dedicated documentation pages:
* [0x.js Library](https://0xproject.com/docs/0xjs)
* [0x Connect](https://0xproject.com/docs/connect)
* [Smart contracts](https://0xproject.com/docs/contracts)
* [Subproviders](https://0xproject.com/docs/subproviders)
* [Sol Compiler](https://0xproject.com/docs/sol-compiler)
* [Web3-wrapper](https://0xproject.com/docs/web3-wrapper)
* [JSON-schemas](https://0xproject.com/docs/json-schemas)
* [Sol-cov](https://0xproject.com/docs/sol-cov)
* [Standard Relayer API](https://github.com/0xProject/standard-relayer-api/blob/master/README.md)
Node version >= 6.12 is required.
Most of the packages require additional typings for external dependencies.
You can include those by prepending the `@0x/typescript-typings` package to your [`typeRoots`](http://www.typescriptlang.org/docs/handbook/tsconfig-json.html) config.
You can include those by prepending @0xproject/typescript-typings package to your [`typeRoots`](http://www.typescriptlang.org/docs/handbook/tsconfig-json.html) config.
```json
"typeRoots": ["node_modules/@0x/typescript-typings/types", "node_modules/@types"],
"typeRoots": ["node_modules/@0xproject/typescript-typings/types", "node_modules/@types"],
```
## Contributing
@@ -108,10 +82,10 @@ We strongly recommend that the community help us make improvements and determine
### Install dependencies
Make sure you are using Yarn v1.9.4. To install using brew:
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
```bash
brew install yarn@1.9.4
yarn config set workspaces-experimental true
```
Then install dependencies
@@ -131,7 +105,7 @@ yarn build
To build a specific package:
```bash
PKG=@0x/web3-wrapper yarn build
PKG=@0xproject/web3-wrapper yarn build
```
### Watch
@@ -148,7 +122,7 @@ To watch a specific package and all it's dependent packages:
PKG=[NPM_PACKAGE_NAME] yarn watch
e.g
PKG=@0x/web3-wrapper yarn watch
PKG=@0xproject/web3-wrapper yarn watch
```
### Clean
@@ -204,5 +178,5 @@ yarn test
Run a specific package's test:
```bash
PKG=@0x/web3-wrapper yarn test
PKG=@0xproject/web3-wrapper yarn test
```

View File

@@ -1,48 +0,0 @@
# Contracts testing options
## Revert stack traces
If you want to see helpful stack traces (incl. line number, code snippet) for smart contract reverts, run the tests with:
```
yarn test:trace
```
**Note:** This currently slows down the test runs and is therefore not enabled by default.
## Backing Ethereum node
By default, our tests run against an in-process [Ganache](https://github.com/trufflesuite/ganache-core) instance. In order to run the tests against [Geth](https://github.com/ethereum/go-ethereum), first follow the instructions in the README for the devnet package to start the devnet Geth node. Then run:
```bash
TEST_PROVIDER=geth yarn test
```
## Code coverage
In order to see the Solidity code coverage output generated by `@0x/sol-coverage`, run:
```
yarn test:coverage
```
## Gas profiler
In order to profile the gas costs for a specific smart contract call/transaction, you can run the tests in `profiler` mode.
**Note:** Traces emitted by ganache have incorrect gas costs so we recommend using Geth for profiling.
```
TEST_PROVIDER=geth yarn test:profiler
```
You'll see a warning that you need to explicitly enable and disable the profiler before and after the block of code you want to profile.
```typescript
import { profiler } from './utils/profiler';
profiler.start();
// Some call to a smart contract
profiler.stop();
```
Without explicitly starting and stopping the profiler, the profiler output will be too busy, and therefore unusable.

View File

@@ -1,29 +0,0 @@
[
{
"timestamp": 1547225310,
"version": "1.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1547040760,
"version": "1.0.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1544741676,
"version": "1.0.2",
"changes": [
{
"note": "Dependencies updated"
}
]
}
]

View File

@@ -1,18 +0,0 @@
<!--
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
Edit the package's CHANGELOG.json file only.
-->
CHANGELOG
## v1.0.4 - _January 11, 2019_
* Dependencies updated
## v1.0.3 - _January 9, 2019_
* Dependencies updated
## v1.0.2 - _December 13, 2018_
* Dependencies updated

View File

@@ -1,56 +0,0 @@
## Contract examples
Example smart contracts that interact with 0x protocol.
## Usage
Contracts can be found in the [contracts](./contracts) directory.
This package contains example implementations of contracts that interact with the protocol but are _not_ intended for use in production. Examples include [filter](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#filter-contracts) contracts, a [Wallet](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#wallet) contract, and a [Validator](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#validator) contract, among others.
## 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.
For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
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/contracts-examples yarn build
```
Or continuously rebuild on change:
```bash
PKG=@0x/contracts-examples yarn watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash
yarn lint
```

View File

@@ -1,81 +0,0 @@
{
"name": "@0x/contracts-examples",
"version": "1.0.4",
"engines": {
"node": ">=6.12"
},
"description": "Smart contract examples of 0x protocol",
"main": "lib/src/index.js",
"directories": {
"test": "test"
},
"scripts": {
"build": "yarn pre_build && tsc -b",
"build:ci": "yarn build",
"pre_build": "run-s compile generate_contract_wrappers",
"compile": "sol-compiler",
"watch": "sol-compiler -w",
"clean": "shx rm -rf lib generated-artifacts 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 generated-wrappers --backend ethers",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
},
"config": {
"abis": "generated-artifacts/@(ExchangeWrapper|Validator|Wallet|Whitelist).json"
},
"repository": {
"type": "git",
"url": "https://github.com/0xProject/0x-monorepo.git"
},
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/0xProject/0x-monorepo/issues"
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/examples/README.md",
"devDependencies": {
"@0x/abi-gen": "^1.0.21",
"@0x/contracts-test-utils": "^1.0.4",
"@0x/dev-utils": "^1.0.23",
"@0x/sol-compiler": "^2.0.1",
"@0x/subproviders": "^2.1.10",
"@0x/tslint-config": "^2.0.1",
"@types/bn.js": "^4.11.0",
"@types/lodash": "4.14.104",
"@types/node": "*",
"@types/yargs": "^10.0.0",
"chai": "^4.0.1",
"chai-as-promised": "^7.1.0",
"chai-bignumber": "^2.0.1",
"dirty-chai": "^2.0.1",
"ethereumjs-abi": "0.6.5",
"make-promises-safe": "^1.1.0",
"mocha": "^4.1.0",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"solhint": "^1.4.1",
"tslint": "5.11.0",
"typescript": "3.0.1",
"yargs": "^10.0.3"
},
"dependencies": {
"@0x/base-contract": "^3.0.12",
"@0x/contracts-interfaces": "^1.0.4",
"@0x/contracts-libs": "^1.0.4",
"@0x/contracts-multisig": "^1.0.4",
"@0x/contracts-tokens": "^1.0.4",
"@0x/contracts-utils": "^1.0.4",
"@0x/order-utils": "^3.1.1",
"@0x/types": "^1.5.1",
"@0x/typescript-typings": "^3.0.7",
"@0x/utils": "^3.0.0",
"@0x/web3-wrapper": "^3.2.3",
"@types/js-combinatorics": "^0.5.29",
"bn.js": "^4.11.8",
"ethereum-types": "^1.1.5",
"ethereumjs-util": "^5.1.1",
"lodash": "^4.17.5"
},
"publishConfig": {
"access": "public"
}
}

View File

@@ -1,13 +0,0 @@
import { ContractArtifact } from 'ethereum-types';
import * as ExchangeWrapper from '../../generated-artifacts/ExchangeWrapper.json';
import * as Validator from '../../generated-artifacts/Validator.json';
import * as Wallet from '../../generated-artifacts/Wallet.json';
import * as Whitelist from '../../generated-artifacts/Whitelist.json';
export const artifacts = {
ExchangeWrapper: ExchangeWrapper as ContractArtifact,
Validator: Validator as ContractArtifact,
Wallet: Wallet as ContractArtifact,
Whitelist: Whitelist as ContractArtifact,
};

View File

@@ -1,2 +0,0 @@
export * from './artifacts';
export * from './wrappers';

View File

@@ -1,4 +0,0 @@
export * from '../../generated-wrappers/exchange_wrapper';
export * from '../../generated-wrappers/validator';
export * from '../../generated-wrappers/wallet';
export * from '../../generated-wrappers/whitelist';

View File

@@ -1,16 +0,0 @@
{
"extends": "../../tsconfig",
"compilerOptions": {
"outDir": "lib",
"rootDir": ".",
"resolveJsonModule": true
},
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
"files": [
"./generated-artifacts/ExchangeWrapper.json",
"./generated-artifacts/Validator.json",
"./generated-artifacts/Wallet.json",
"./generated-artifacts/Whitelist.json"
],
"exclude": ["./deploy/solc/solc_bin"]
}

View File

@@ -1,47 +0,0 @@
[
{
"timestamp": 1547225310,
"version": "1.2.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "1.2.0",
"changes": [
{
"note": "Added Dutch Auction Wrapper",
"pr": 1465
}
],
"timestamp": 1547040760
},
{
"version": "1.1.0",
"changes": [
{
"note": "Added Balance Threshold Filter",
"pr": 1383
},
{
"note": "Add OrderMatcher",
"pr": 1117
},
{
"note": "Add OrderValidator",
"pr": 1464
}
]
},
{
"timestamp": 1544741676,
"version": "1.0.2",
"changes": [
{
"note": "Dependencies updated"
}
]
}
]

View File

@@ -1,24 +0,0 @@
<!--
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
Edit the package's CHANGELOG.json file only.
-->
CHANGELOG
## v1.2.1 - _January 11, 2019_
* Dependencies updated
## v1.2.0 - _January 9, 2019_
* Added Dutch Auction Wrapper (#1465)
## v1.1.0 - _Invalid date_
* Added Balance Threshold Filter (#1383)
* Add OrderMatcher (#1117)
* Add OrderValidator (#1464)
## v1.0.2 - _December 13, 2018_
* Dependencies updated

View File

@@ -1,31 +0,0 @@
[
{
"name": "Forwarder",
"version": "1.1.0",
"changes": [
{
"note": "Round up when calculating remaining amounts in marketBuy functions",
"pr": 1162,
"networks": {
"1": "0x5468a1dc173652ee28d249c271fa9933144746b1",
"3": "0x2240dab907db71e64d3e0dba4800c83b5c502d4e",
"42": "0x17992e4ffb22730138e4b62aaa6367fa9d3699a6"
}
}
]
},
{
"name": "Forwarder",
"version": "1.0.0",
"changes": [
{
"note": "protocol v2 deploy",
"networks": {
"1": "0x7afc2d5107af94c462a194d2c21b5bdd238709d6",
"3": "0x3983e204b12b3c02fb0638caf2cd406a62e0ead3",
"42": "0xd85e2fa7e7e252b27b01bf0d65c946959d2f45b8"
}
}
]
}
]

View File

@@ -1,69 +0,0 @@
## Contract extensions
Smart contracts that implement extensions for the 0x protocol.
## Usage
Contract extensions of the protocol can be found in the [contracts](./contracts) directory. This directory contains contracts that interact with the 2.0.0 contracts and will be used in production, such as the [Forwarder](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/forwarder-specification.md) contract.
## Bug bounty
A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0xproject.com/wiki#Bug-Bounty).
## 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.
For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
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/contracts-extensions yarn build
```
Or continuously rebuild on change:
```bash
PKG=@0x/contracts-extensions yarn watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash
yarn lint
```
### Run Tests
```bash
yarn test
```
#### Testing options
Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md).

View File

@@ -1,22 +0,0 @@
{
"artifactsDir": "./generated-artifacts",
"contractsDir": "./contracts",
"compilerSettings": {
"optimizer": {
"enabled": true,
"runs": 1000000
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode.object",
"evm.bytecode.sourceMap",
"evm.deployedBytecode.object",
"evm.deployedBytecode.sourceMap"
]
}
}
},
"contracts": ["BalanceThresholdFilter", "DutchAuction", "Forwarder", "OrderMatcher", "OrderValidator"]
}

View File

@@ -1,45 +0,0 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity 0.4.24;
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
import "./interfaces/IThresholdAsset.sol";
import "./MixinBalanceThresholdFilterCore.sol";
contract BalanceThresholdFilter is
MixinBalanceThresholdFilterCore
{
/// @dev Constructs BalanceThresholdFilter.
/// @param exchange Address of 0x exchange.
/// @param thresholdAsset The asset that must be held by makers/takers.
/// @param balanceThreshold The minimum balance of `thresholdAsset` that must be held by makers/takers.
constructor(
address exchange,
address thresholdAsset,
uint256 balanceThreshold
)
public
{
EXCHANGE = IExchange(exchange);
THRESHOLD_ASSET = IThresholdAsset(thresholdAsset);
BALANCE_THRESHOLD = balanceThreshold;
}
}

View File

@@ -1,135 +0,0 @@
/*
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/LICENSE2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.4.24;
import "@0x/contracts-libs/contracts/libs/LibExchangeSelectors.sol";
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
import "./mixins/MBalanceThresholdFilterCore.sol";
import "./MixinExchangeCalldata.sol";
contract MixinBalanceThresholdFilterCore is
MBalanceThresholdFilterCore,
MixinExchangeCalldata,
LibOrder,
LibExchangeSelectors
{
/// @dev Executes an Exchange transaction iff the maker and taker meet
/// the hold at least `BALANCE_THRESHOLD` of the asset `THRESHOLD_ASSET` OR
/// the exchange function is a cancellation.
/// Supported Exchange functions:
/// batchFillOrders
/// batchFillOrdersNoThrow
/// batchFillOrKillOrders
/// fillOrder
/// fillOrderNoThrow
/// fillOrKillOrder
/// marketBuyOrders
/// marketBuyOrdersNoThrow
/// marketSellOrders
/// marketSellOrdersNoThrow
/// matchOrders
/// cancelOrder
/// batchCancelOrders
/// cancelOrdersUpTo
/// Trying to call any other exchange function will throw.
/// @param salt Arbitrary number to ensure uniqueness of transaction hash.
/// @param signerAddress Address of transaction signer.
/// @param signedExchangeTransaction AbiV2 encoded calldata.
/// @param signature Proof of signer transaction by signer.
function executeTransaction(
uint256 salt,
address signerAddress,
bytes signedExchangeTransaction,
bytes signature
)
external
{
// Get accounts whose balances must be validated
address[] memory addressesToValidate = getAddressesToValidate(signerAddress);
// Validate account balances
uint256 balanceThreshold = BALANCE_THRESHOLD;
IThresholdAsset thresholdAsset = THRESHOLD_ASSET;
for (uint256 i = 0; i < addressesToValidate.length; ++i) {
uint256 addressBalance = thresholdAsset.balanceOf(addressesToValidate[i]);
require(
addressBalance >= balanceThreshold,
"AT_LEAST_ONE_ADDRESS_DOES_NOT_MEET_BALANCE_THRESHOLD"
);
}
emit ValidatedAddresses(addressesToValidate);
// All addresses are valid. Execute exchange function.
EXCHANGE.executeTransaction(
salt,
signerAddress,
signedExchangeTransaction,
signature
);
}
/// @dev Constructs an array of addresses to be validated.
/// Addresses depend on which Exchange function is to be called
/// (defined by `signedExchangeTransaction` above).
/// @param signerAddress Address of transaction signer.
/// @return addressesToValidate Array of addresses to validate.
function getAddressesToValidate(address signerAddress)
internal pure
returns (address[] memory addressesToValidate)
{
bytes4 exchangeFunctionSelector = bytes4(exchangeCalldataload(0));
// solhint-disable expression-indent
if (
exchangeFunctionSelector == BATCH_FILL_ORDERS_SELECTOR ||
exchangeFunctionSelector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR ||
exchangeFunctionSelector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR ||
exchangeFunctionSelector == MARKET_BUY_ORDERS_SELECTOR ||
exchangeFunctionSelector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR ||
exchangeFunctionSelector == MARKET_SELL_ORDERS_SELECTOR ||
exchangeFunctionSelector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR
) {
addressesToValidate = loadMakerAddressesFromOrderArray(0);
addressesToValidate = addressesToValidate.append(signerAddress);
} else if (
exchangeFunctionSelector == FILL_ORDER_SELECTOR ||
exchangeFunctionSelector == FILL_ORDER_NO_THROW_SELECTOR ||
exchangeFunctionSelector == FILL_OR_KILL_ORDER_SELECTOR
) {
address makerAddress = loadMakerAddressFromOrder(0);
addressesToValidate = addressesToValidate.append(makerAddress);
addressesToValidate = addressesToValidate.append(signerAddress);
} else if (exchangeFunctionSelector == MATCH_ORDERS_SELECTOR) {
address leftMakerAddress = loadMakerAddressFromOrder(0);
addressesToValidate = addressesToValidate.append(leftMakerAddress);
address rightMakerAddress = loadMakerAddressFromOrder(1);
addressesToValidate = addressesToValidate.append(rightMakerAddress);
addressesToValidate = addressesToValidate.append(signerAddress);
} else if (
exchangeFunctionSelector != CANCEL_ORDER_SELECTOR &&
exchangeFunctionSelector != BATCH_CANCEL_ORDERS_SELECTOR &&
exchangeFunctionSelector != CANCEL_ORDERS_UP_TO_SELECTOR
) {
revert("INVALID_OR_BLOCKED_EXCHANGE_SELECTOR");
}
// solhint-enable expression-indent
return addressesToValidate;
}
}

View File

@@ -1,103 +0,0 @@
/*
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/LICENSE2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.4.24;
import "./mixins/MExchangeCalldata.sol";
import "@0x/contracts-libs/contracts/libs/LibAddressArray.sol";
contract MixinExchangeCalldata is
MExchangeCalldata
{
using LibAddressArray for address[];
/// @dev Emulates the `calldataload` opcode on the embedded Exchange calldata,
/// which is accessed through `signedExchangeTransaction`.
/// @param offset Offset into the Exchange calldata.
/// @return value Corresponding 32 byte value stored at `offset`.
function exchangeCalldataload(uint256 offset)
internal pure
returns (bytes32 value)
{
assembly {
// Pointer to exchange transaction
// 0x04 for calldata selector
// 0x40 to access `signedExchangeTransaction`, which is the third parameter
let exchangeTxPtr := calldataload(0x44)
// Offset into Exchange calldata
// We compute this by adding 0x24 to the `exchangeTxPtr` computed above.
// 0x04 for calldata selector
// 0x20 for length field of `signedExchangeTransaction`
let exchangeCalldataOffset := add(exchangeTxPtr, add(0x24, offset))
value := calldataload(exchangeCalldataOffset)
}
return value;
}
/// @dev Convenience function that skips the 4 byte selector when loading
/// from the embedded Exchange calldata.
/// @param offset Offset into the Exchange calldata (minus the 4 byte selector)
/// @return value Corresponding 32 byte value stored at `offset` + 4.
function loadExchangeData(uint256 offset)
internal pure
returns (bytes32 value)
{
value = exchangeCalldataload(offset + 4);
return value;
}
/// @dev Extracts the maker address from an order stored in the Exchange calldata
/// (which is embedded in `signedExchangeTransaction`).
/// @param orderParamIndex Index of the order in the Exchange function's signature.
/// @return makerAddress The extracted maker address.
function loadMakerAddressFromOrder(uint256 orderParamIndex)
internal pure
returns (address makerAddress)
{
uint256 orderOffsetInBytes = orderParamIndex * 32;
uint256 orderPtr = uint256(loadExchangeData(orderOffsetInBytes));
makerAddress = address(loadExchangeData(orderPtr));
return makerAddress;
}
/// @dev Extracts the maker addresses from an array of orders stored in the Exchange calldata
/// (which is embedded in `signedExchangeTransaction`).
/// @param orderArrayParamIndex Index of the order array in the Exchange function's signature
/// @return makerAddresses The extracted maker addresses.
function loadMakerAddressesFromOrderArray(uint256 orderArrayParamIndex)
internal pure
returns (address[] makerAddresses)
{
uint256 orderArrayOffsetInBytes = orderArrayParamIndex * 32;
uint256 orderArrayPtr = uint256(loadExchangeData(orderArrayOffsetInBytes));
uint256 orderArrayLength = uint256(loadExchangeData(orderArrayPtr));
uint256 orderArrayLengthInBytes = orderArrayLength * 32;
uint256 orderArrayElementPtr = orderArrayPtr + 32;
uint256 orderArrayElementEndPtr = orderArrayElementPtr + orderArrayLengthInBytes;
for (uint orderPtrOffset = orderArrayElementPtr; orderPtrOffset < orderArrayElementEndPtr; orderPtrOffset += 32) {
uint256 orderPtr = uint256(loadExchangeData(orderPtrOffset));
address makerAddress = address(loadExchangeData(orderPtr + orderArrayElementPtr));
makerAddresses = makerAddresses.append(makerAddress);
}
return makerAddresses;
}
}

View File

@@ -1,55 +0,0 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.4.24;
contract IBalanceThresholdFilterCore {
/// @dev Executes an Exchange transaction iff the maker and taker meet
/// the hold at least `BALANCE_THRESHOLD` of the asset `THRESHOLD_ASSET` OR
/// the exchange function is a cancellation.
/// Supported Exchange functions:
/// - batchFillOrders
/// - batchFillOrdersNoThrow
/// - batchFillOrKillOrders
/// - fillOrder
/// - fillOrderNoThrow
/// - fillOrKillOrder
/// - marketBuyOrders
/// - marketBuyOrdersNoThrow
/// - marketSellOrders
/// - marketSellOrdersNoThrow
/// - matchOrders
/// - cancelOrder
/// - batchCancelOrders
/// - cancelOrdersUpTo
/// Trying to call any other exchange function will throw.
/// @param salt Arbitrary number to ensure uniqueness of transaction hash.
/// @param signerAddress Address of transaction signer.
/// @param signedExchangeTransaction AbiV2 encoded calldata.
/// @param signature Proof of signer transaction by signer.
function executeTransaction(
uint256 salt,
address signerAddress,
bytes signedExchangeTransaction,
bytes signature
)
external;
}

View File

@@ -1,31 +0,0 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.4.24;
contract IThresholdAsset {
/// @param _owner The address from which the balance will be retrieved
/// @return Balance of owner
function balanceOf(address _owner)
external
view
returns (uint256);
}

View File

@@ -1,54 +0,0 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.4.24;
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
import "../interfaces/IThresholdAsset.sol";
import "../interfaces/IBalanceThresholdFilterCore.sol";
contract MBalanceThresholdFilterCore is
IBalanceThresholdFilterCore
{
// Points to 0x exchange contract
// solhint-disable var-name-mixedcase
IExchange internal EXCHANGE;
// The asset that must be held by makers/takers
IThresholdAsset internal THRESHOLD_ASSET;
// The minimum balance of `THRESHOLD_ASSET` that must be held by makers/takers
uint256 internal BALANCE_THRESHOLD;
// solhint-enable var-name-mixedcase
// Addresses that hold at least `BALANCE_THRESHOLD` of `THRESHOLD_ASSET`
event ValidatedAddresses (
address[] addresses
);
/// @dev Constructs an array of addresses to be validated.
/// Addresses depend on which Exchange function is to be called
/// (defined by `signedExchangeTransaction` above).
/// @param signerAddress Address of transaction signer.
/// @return addressesToValidate Array of addresses to validate.
function getAddressesToValidate(address signerAddress)
internal pure
returns (address[] memory addressesToValidate);
}

View File

@@ -1,56 +0,0 @@
/*
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/LICENSE2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.4.24;
contract MExchangeCalldata {
/// @dev Emulates the `calldataload` opcode on the embedded Exchange calldata,
/// which is accessed through `signedExchangeTransaction`.
/// @param offset Offset into the Exchange calldata.
/// @return value Corresponding 32 byte value stored at `offset`.
function exchangeCalldataload(uint256 offset)
internal pure
returns (bytes32 value);
/// @dev Convenience function that skips the 4 byte selector when loading
/// from the embedded Exchange calldata.
/// @param offset Offset into the Exchange calldata (minus the 4 byte selector)
/// @return value Corresponding 32 byte value stored at `offset` + 4.
function loadExchangeData(uint256 offset)
internal pure
returns (bytes32 value);
/// @dev Extracts the maker address from an order stored in the Exchange calldata
/// (which is embedded in `signedExchangeTransaction`).
/// @param orderParamIndex Index of the order in the Exchange function's signature.
/// @return makerAddress The extracted maker address.
function loadMakerAddressFromOrder(uint256 orderParamIndex)
internal pure
returns (address makerAddress);
/// @dev Extracts the maker addresses from an array of orders stored in the Exchange calldata
/// (which is embedded in `signedExchangeTransaction`).
/// @param orderArrayParamIndex Index of the order array in the Exchange function's signature
/// @return makerAddresses The extracted maker addresses.
function loadMakerAddressesFromOrderArray(uint256 orderArrayParamIndex)
internal pure
returns (address[] makerAddresses);
}

View File

@@ -1,205 +0,0 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity 0.4.24;
pragma experimental ABIEncoderV2;
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
import "@0x/contracts-tokens/contracts/tokens/ERC20Token/IERC20Token.sol";
import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
import "@0x/contracts-utils/contracts/utils/SafeMath/SafeMath.sol";
contract DutchAuction is
SafeMath
{
using LibBytes for bytes;
// solhint-disable var-name-mixedcase
IExchange internal EXCHANGE;
struct AuctionDetails {
uint256 beginTimeSeconds; // Auction begin unix timestamp: sellOrder.makerAssetData
uint256 endTimeSeconds; // Auction end unix timestamp: sellOrder.expiryTimeSeconds
uint256 beginAmount; // Auction begin amount: sellOrder.makerAssetData
uint256 endAmount; // Auction end amount: sellOrder.takerAssetAmount
uint256 currentAmount; // Calculated amount given block.timestamp
uint256 currentTimeSeconds; // block.timestamp
}
constructor (address _exchange)
public
{
EXCHANGE = IExchange(_exchange);
}
/// @dev 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
/// @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.
/// @return matchedFillResults amounts filled and fees paid by maker and taker of matched orders.
function matchOrders(
LibOrder.Order memory buyOrder,
LibOrder.Order memory sellOrder,
bytes memory buySignature,
bytes memory sellSignature
)
public
returns (LibFillResults.MatchedFillResults memory matchedFillResults)
{
AuctionDetails memory auctionDetails = getAuctionDetails(sellOrder);
// Ensure the auction has not yet started
require(
auctionDetails.currentTimeSeconds >= auctionDetails.beginTimeSeconds,
"AUCTION_NOT_STARTED"
);
// Ensure the auction has not expired. This will fail later in 0x but we can save gas by failing early
require(
sellOrder.expirationTimeSeconds > auctionDetails.currentTimeSeconds,
"AUCTION_EXPIRED"
);
// Validate the buyer amount is greater than the current auction amount
require(
buyOrder.makerAssetAmount >= auctionDetails.currentAmount,
"INVALID_AMOUNT"
);
// Match orders, maximally filling `buyOrder`
matchedFillResults = EXCHANGE.matchOrders(
buyOrder,
sellOrder,
buySignature,
sellSignature
);
// The difference in sellOrder.takerAssetAmount and current amount is given as spread to the matcher
// This may include additional spread from the buyOrder.makerAssetAmount and the currentAmount.
// e.g currentAmount is 30, sellOrder.takerAssetAmount is 10 and buyOrder.makerAssetamount is 40.
// 10 (40-30) is returned to the buyer, 20 (30-10) sent to the seller and 10 has previously
// been transferred to the seller during matchOrders
uint256 leftMakerAssetSpreadAmount = matchedFillResults.leftMakerAssetSpreadAmount;
if (leftMakerAssetSpreadAmount > 0) {
// ERC20 Asset data itself is encoded as follows:
//
// | Area | Offset | Length | Contents |
// |----------|--------|---------|-------------------------------------|
// | Header | 0 | 4 | function selector |
// | Params | | 1 * 32 | function parameters: |
// | | 4 | 12 | 1. token address padding |
// | | 16 | 20 | 2. token address |
bytes memory assetData = sellOrder.takerAssetData;
address token = assetData.readAddress(16);
// Calculate the excess from the buy order. This can occur if the buyer sends in a higher
// amount than the calculated current amount
uint256 buyerExcessAmount = safeSub(buyOrder.makerAssetAmount, auctionDetails.currentAmount);
uint256 sellerExcessAmount = safeSub(leftMakerAssetSpreadAmount, buyerExcessAmount);
// Return the difference between auctionDetails.currentAmount and sellOrder.takerAssetAmount
// to the seller
if (sellerExcessAmount > 0) {
IERC20Token(token).transfer(sellOrder.makerAddress, sellerExcessAmount);
}
// Return the difference between buyOrder.makerAssetAmount and auctionDetails.currentAmount
// to the buyer
if (buyerExcessAmount > 0) {
IERC20Token(token).transfer(buyOrder.makerAddress, buyerExcessAmount);
}
}
return matchedFillResults;
}
/// @dev Calculates the Auction Details for the given order
/// @param order The sell order
/// @return AuctionDetails
function getAuctionDetails(
LibOrder.Order memory order
)
public
returns (AuctionDetails memory auctionDetails)
{
uint256 makerAssetDataLength = order.makerAssetData.length;
// It is unknown the encoded data of makerAssetData, we assume the last 64 bytes
// are the Auction Details encoding.
// Auction Details is encoded as follows:
//
// | Area | Offset | Length | Contents |
// |----------|--------|---------|-------------------------------------|
// | Params | | 2 * 32 | parameters: |
// | | -64 | 32 | 1. auction begin unix timestamp |
// | | -32 | 32 | 2. auction begin begin amount |
// ERC20 asset data length is 4+32, 64 for auction details results in min length 100
require(
makerAssetDataLength >= 100,
"INVALID_ASSET_DATA"
);
uint256 auctionBeginTimeSeconds = order.makerAssetData.readUint256(makerAssetDataLength - 64);
uint256 auctionBeginAmount = order.makerAssetData.readUint256(makerAssetDataLength - 32);
// Ensure the auction has a valid begin time
require(
order.expirationTimeSeconds > auctionBeginTimeSeconds,
"INVALID_BEGIN_TIME"
);
uint256 auctionDurationSeconds = order.expirationTimeSeconds-auctionBeginTimeSeconds;
// Ensure the auction goes from high to low
uint256 minAmount = order.takerAssetAmount;
require(
auctionBeginAmount > minAmount,
"INVALID_AMOUNT"
);
uint256 amountDelta = auctionBeginAmount-minAmount;
// solhint-disable-next-line not-rely-on-time
uint256 timestamp = block.timestamp;
auctionDetails.beginTimeSeconds = auctionBeginTimeSeconds;
auctionDetails.endTimeSeconds = order.expirationTimeSeconds;
auctionDetails.beginAmount = auctionBeginAmount;
auctionDetails.endAmount = minAmount;
auctionDetails.currentTimeSeconds = timestamp;
uint256 remainingDurationSeconds = order.expirationTimeSeconds-timestamp;
if (timestamp < auctionBeginTimeSeconds) {
// If the auction has not yet begun the current amount is the auctionBeginAmount
auctionDetails.currentAmount = auctionBeginAmount;
} else if (timestamp >= order.expirationTimeSeconds) {
// If the auction has ended the current amount is the minAmount.
// Auction end time is guaranteed by 0x Exchange due to the order expiration
auctionDetails.currentAmount = minAmount;
} else {
auctionDetails.currentAmount = safeAdd(
minAmount,
safeDiv(
safeMul(remainingDurationSeconds, amountDelta),
auctionDurationSeconds
)
);
}
return auctionDetails;
}
}

View File

@@ -1,195 +0,0 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.4.24;
import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol";
import "@0x/contracts-tokens/contracts/tokens/ERC20Token/IERC20Token.sol";
import "@0x/contracts-tokens/contracts/tokens/ERC721Token/IERC721Token.sol";
import "./mixins/MAssets.sol";
import "./libs/LibConstants.sol";
contract MixinAssets is
MAssets,
Ownable,
LibConstants
{
using LibBytes for bytes;
/// @dev 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.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of asset to withdraw.
function withdrawAsset(
bytes assetData,
uint256 amount
)
external
onlyOwner
{
transferAssetToSender(assetData, amount);
}
/// @dev Approves or disapproves an AssetProxy to spend asset.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of asset to approve for respective proxy.
function approveAssetProxy(
bytes assetData,
uint256 amount
)
external
onlyOwner
{
bytes4 proxyId = assetData.readBytes4(0);
if (proxyId == ERC20_DATA_ID) {
approveERC20Token(assetData, amount);
} else if (proxyId == ERC721_DATA_ID) {
approveERC721Token(assetData, amount);
} else {
revert("UNSUPPORTED_ASSET_PROXY");
}
}
/// @dev Transfers given amount of asset to sender.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of asset to transfer to sender.
function transferAssetToSender(
bytes memory assetData,
uint256 amount
)
internal
{
bytes4 proxyId = assetData.readBytes4(0);
if (proxyId == ERC20_DATA_ID) {
transferERC20Token(assetData, amount);
} else if (proxyId == ERC721_DATA_ID) {
transferERC721Token(assetData, amount);
} else {
revert("UNSUPPORTED_ASSET_PROXY");
}
}
/// @dev Decodes ERC20 assetData and transfers given amount to sender.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of asset to transfer to sender.
function transferERC20Token(
bytes memory assetData,
uint256 amount
)
internal
{
// 4 byte id + 12 0 bytes before ABI encoded token address.
address token = assetData.readAddress(16);
// Transfer tokens.
// We do a raw call so we can check the success separate
// from the return data.
bool success = token.call(abi.encodeWithSelector(
ERC20_TRANSFER_SELECTOR,
msg.sender,
amount
));
require(
success,
"TRANSFER_FAILED"
);
// Check return data.
// If there is no return data, we assume the token incorrectly
// does not return a bool. In this case we expect it to revert
// on failure, which was handled above.
// If the token does return data, we require that it is a single
// value that evaluates to true.
assembly {
if returndatasize {
success := 0
if eq(returndatasize, 32) {
// First 64 bytes of memory are reserved scratch space
returndatacopy(0, 0, 32)
success := mload(0)
}
}
}
require(
success,
"TRANSFER_FAILED"
);
}
/// @dev Decodes ERC721 assetData and transfers given amount to sender.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of asset to transfer to sender.
function transferERC721Token(
bytes memory assetData,
uint256 amount
)
internal
{
require(
amount == 1,
"INVALID_AMOUNT"
);
// Decode asset data.
// 4 byte id + 12 0 bytes before ABI encoded token address.
address token = assetData.readAddress(16);
// 4 byte id + 32 byte ABI encoded token address before token id.
uint256 tokenId = assetData.readUint256(36);
// Perform transfer.
IERC721Token(token).transferFrom(
address(this),
msg.sender,
tokenId
);
}
/// @dev Sets approval for ERC20 AssetProxy.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of asset to approve for respective proxy.
function approveERC20Token(
bytes memory assetData,
uint256 amount
)
internal
{
address token = assetData.readAddress(16);
require(
IERC20Token(token).approve(ERC20_PROXY_ADDRESS, amount),
"APPROVAL_FAILED"
);
}
/// @dev Sets approval for ERC721 AssetProxy.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of asset to approve for respective proxy.
function approveERC721Token(
bytes memory assetData,
uint256 amount
)
internal
{
address token = assetData.readAddress(16);
bool approval = amount >= 1;
IERC721Token(token).setApprovalForAll(ERC721_PROXY_ADDRESS, approval);
}
}

View File

@@ -1,86 +0,0 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
import "./libs/LibConstants.sol";
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
import "@0x/contracts-libs/contracts/libs/LibFillResults.sol";
import "@0x/contracts-utils/contracts/utils/Ownable/Ownable.sol";
contract MixinMatchOrders is
Ownable,
LibConstants
{
/// @dev 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 is then used to fill the right order as much as possible.
/// This results in a spread being taken in terms of both assets. The spread is held within this contract.
/// @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.
function matchOrders(
LibOrder.Order memory leftOrder,
LibOrder.Order memory rightOrder,
bytes memory leftSignature,
bytes memory rightSignature
)
public
onlyOwner
{
// Match orders, maximally filling `leftOrder`
LibFillResults.MatchedFillResults memory matchedFillResults = EXCHANGE.matchOrders(
leftOrder,
rightOrder,
leftSignature,
rightSignature
);
uint256 leftMakerAssetSpreadAmount = matchedFillResults.leftMakerAssetSpreadAmount;
uint256 rightOrderTakerAssetAmount = rightOrder.takerAssetAmount;
// Do not attempt to call `fillOrder` if no spread was taken or `rightOrder` has been completely filled
if (leftMakerAssetSpreadAmount == 0 || matchedFillResults.right.takerAssetFilledAmount == rightOrderTakerAssetAmount) {
return;
}
// The `assetData` fields of the `rightOrder` could have been null for the `matchOrders` call. We reassign them before calling `fillOrder`.
rightOrder.makerAssetData = leftOrder.takerAssetData;
rightOrder.takerAssetData = leftOrder.makerAssetData;
// Query `rightOrder` info to check if it has been completely filled
// We need to make this check in case the `rightOrder` was partially filled before the `matchOrders` call
LibOrder.OrderInfo memory orderInfo = EXCHANGE.getOrderInfo(rightOrder);
// Do not attempt to call `fillOrder` if order has been completely filled
if (orderInfo.orderTakerAssetFilledAmount == rightOrderTakerAssetAmount) {
return;
}
// We do not need to pass in a signature since it was already validated in the `matchOrders` call
EXCHANGE.fillOrder(
rightOrder,
leftMakerAssetSpreadAmount,
""
);
}
}

View File

@@ -1,43 +0,0 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.4.24;
contract IAssets {
/// @dev 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.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of asset to withdraw.
function withdrawAsset(
bytes assetData,
uint256 amount
)
external;
/// @dev Approves or disapproves an AssetProxy to spend asset.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of asset to approve for respective proxy.
function approveAssetProxy(
bytes assetData,
uint256 amount
)
external;
}

View File

@@ -1,43 +0,0 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
contract IMatchOrders {
/// @dev 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 is then used to fill the right order as much as possible.
/// This results in a spread being taken in terms of both assets. The spread is held within this contract.
/// @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.
function matchOrders(
LibOrder.Order memory leftOrder,
LibOrder.Order memory rightOrder,
bytes memory leftSignature,
bytes memory rightSignature
)
public;
}

View File

@@ -1,31 +0,0 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.4.24;
import "@0x/contract-utils/contracts/utils/Ownable/IOwnable.sol";
import "./IMatchOrders.sol";
import "./IAssets.sol";
// solhint-disable no-empty-blocks
contract IOrderMatcher is
IOwnable,
IMatchOrders,
IAssets
{}

View File

@@ -1,56 +0,0 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.4.24;
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
contract LibConstants {
// bytes4(keccak256("transfer(address,uint256)"))
bytes4 constant internal ERC20_TRANSFER_SELECTOR = 0xa9059cbb;
// bytes4(keccak256("ERC20Token(address)"))
bytes4 constant internal ERC20_DATA_ID = 0xf47261b0;
// bytes4(keccak256("ERC721Token(address,uint256)"))
bytes4 constant internal ERC721_DATA_ID = 0x02571792;
// solhint-disable var-name-mixedcase
IExchange internal EXCHANGE;
address internal ERC20_PROXY_ADDRESS;
address internal ERC721_PROXY_ADDRESS;
// solhint-enable var-name-mixedcase
constructor (address _exchange)
public
{
EXCHANGE = IExchange(_exchange);
ERC20_PROXY_ADDRESS = EXCHANGE.getAssetProxy(ERC20_DATA_ID);
require(
ERC20_PROXY_ADDRESS != address(0),
"UNREGISTERED_ASSET_PROXY"
);
ERC721_PROXY_ADDRESS = EXCHANGE.getAssetProxy(ERC721_DATA_ID);
require(
ERC721_PROXY_ADDRESS != address(0),
"UNREGISTERED_ASSET_PROXY"
);
}
}

View File

@@ -1,71 +0,0 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.4.24;
import "../interfaces/IAssets.sol";
contract MAssets is
IAssets
{
/// @dev Transfers given amount of asset to sender.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of asset to transfer to sender.
function transferAssetToSender(
bytes memory assetData,
uint256 amount
)
internal;
/// @dev Decodes ERC20 assetData and transfers given amount to sender.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of asset to transfer to sender.
function transferERC20Token(
bytes memory assetData,
uint256 amount
)
internal;
/// @dev Decodes ERC721 assetData and transfers given amount to sender.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of asset to transfer to sender.
function transferERC721Token(
bytes memory assetData,
uint256 amount
)
internal;
/// @dev Sets approval for ERC20 AssetProxy.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of asset to approve for respective proxy.
function approveERC20Token(
bytes memory assetData,
uint256 amount
)
internal;
/// @dev Sets approval for ERC721 AssetProxy.
/// @param assetData Byte array encoded for the respective asset proxy.
/// @param amount Amount of asset to approve for respective proxy.
function approveERC721Token(
bytes memory assetData,
uint256 amount
)
internal;
}

View File

@@ -1,218 +0,0 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity 0.4.24;
pragma experimental ABIEncoderV2;
import "@0x/contracts-interfaces/contracts/protocol/Exchange/IExchange.sol";
import "@0x/contracts-libs/contracts/libs/LibOrder.sol";
import "@0x/contracts-tokens/contracts/tokens/ERC20Token/IERC20Token.sol";
import "@0x/contracts-tokens/contracts/tokens/ERC721Token/IERC721Token.sol";
import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
contract OrderValidator {
using LibBytes for bytes;
bytes4 constant internal ERC20_DATA_ID = bytes4(keccak256("ERC20Token(address)"));
bytes4 constant internal ERC721_DATA_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
struct TraderInfo {
uint256 makerBalance; // Maker's balance of makerAsset
uint256 makerAllowance; // Maker's allowance to corresponding AssetProxy
uint256 takerBalance; // Taker's balance of takerAsset
uint256 takerAllowance; // Taker's allowance to corresponding AssetProxy
uint256 makerZrxBalance; // Maker's balance of ZRX
uint256 makerZrxAllowance; // Maker's allowance of ZRX to ERC20Proxy
uint256 takerZrxBalance; // Taker's balance of ZRX
uint256 takerZrxAllowance; // Taker's allowance of ZRX to ERC20Proxy
}
// solhint-disable var-name-mixedcase
IExchange internal EXCHANGE;
bytes internal ZRX_ASSET_DATA;
// solhint-enable var-name-mixedcase
constructor (address _exchange, bytes memory _zrxAssetData)
public
{
EXCHANGE = IExchange(_exchange);
ZRX_ASSET_DATA = _zrxAssetData;
}
/// @dev Fetches information for order and maker/taker of order.
/// @param order The order structure.
/// @param takerAddress Address that will be filling the order.
/// @return OrderInfo and TraderInfo instances for given order.
function getOrderAndTraderInfo(LibOrder.Order memory order, address takerAddress)
public
view
returns (LibOrder.OrderInfo memory orderInfo, TraderInfo memory traderInfo)
{
orderInfo = EXCHANGE.getOrderInfo(order);
traderInfo = getTraderInfo(order, takerAddress);
return (orderInfo, traderInfo);
}
/// @dev Fetches information for all passed in orders and the makers/takers of each order.
/// @param orders Array of order specifications.
/// @param takerAddresses Array of taker addresses corresponding to each order.
/// @return Arrays of OrderInfo and TraderInfo instances that correspond to each order.
function getOrdersAndTradersInfo(LibOrder.Order[] memory orders, address[] memory takerAddresses)
public
view
returns (LibOrder.OrderInfo[] memory ordersInfo, TraderInfo[] memory tradersInfo)
{
ordersInfo = EXCHANGE.getOrdersInfo(orders);
tradersInfo = getTradersInfo(orders, takerAddresses);
return (ordersInfo, tradersInfo);
}
/// @dev Fetches balance and allowances for maker and taker of order.
/// @param order The order structure.
/// @param takerAddress Address that will be filling the order.
/// @return Balances and allowances of maker and taker of order.
function getTraderInfo(LibOrder.Order memory order, address takerAddress)
public
view
returns (TraderInfo memory traderInfo)
{
(traderInfo.makerBalance, traderInfo.makerAllowance) = getBalanceAndAllowance(order.makerAddress, order.makerAssetData);
(traderInfo.takerBalance, traderInfo.takerAllowance) = getBalanceAndAllowance(takerAddress, order.takerAssetData);
bytes memory zrxAssetData = ZRX_ASSET_DATA;
(traderInfo.makerZrxBalance, traderInfo.makerZrxAllowance) = getBalanceAndAllowance(order.makerAddress, zrxAssetData);
(traderInfo.takerZrxBalance, traderInfo.takerZrxAllowance) = getBalanceAndAllowance(takerAddress, zrxAssetData);
return traderInfo;
}
/// @dev Fetches balances and allowances of maker and taker for each provided order.
/// @param orders Array of order specifications.
/// @param takerAddresses Array of taker addresses corresponding to each order.
/// @return Array of balances and allowances for maker and taker of each order.
function getTradersInfo(LibOrder.Order[] memory orders, address[] memory takerAddresses)
public
view
returns (TraderInfo[] memory)
{
uint256 ordersLength = orders.length;
TraderInfo[] memory tradersInfo = new TraderInfo[](ordersLength);
for (uint256 i = 0; i != ordersLength; i++) {
tradersInfo[i] = getTraderInfo(orders[i], takerAddresses[i]);
}
return tradersInfo;
}
/// @dev Fetches token balances and allowances of an address to given assetProxy. Supports ERC20 and ERC721.
/// @param target Address to fetch balances and allowances of.
/// @param assetData Encoded data that can be decoded by a specified proxy contract when transferring asset.
/// @return Balance of asset and allowance set to given proxy of asset.
/// For ERC721 tokens, these values will always be 1 or 0.
function getBalanceAndAllowance(address target, bytes memory assetData)
public
view
returns (uint256 balance, uint256 allowance)
{
bytes4 assetProxyId = assetData.readBytes4(0);
address token = assetData.readAddress(16);
address assetProxy = EXCHANGE.getAssetProxy(assetProxyId);
if (assetProxyId == ERC20_DATA_ID) {
// Query balance
balance = IERC20Token(token).balanceOf(target);
// Query allowance
allowance = IERC20Token(token).allowance(target, assetProxy);
} else if (assetProxyId == ERC721_DATA_ID) {
uint256 tokenId = assetData.readUint256(36);
// Query owner of tokenId
address owner = getERC721TokenOwner(token, tokenId);
// Set balance to 1 if tokenId is owned by target
balance = target == owner ? 1 : 0;
// Check if ERC721Proxy is approved to spend tokenId
bool isApproved = IERC721Token(token).isApprovedForAll(target, assetProxy);
// Set alowance to 1 if ERC721Proxy is approved to spend tokenId
allowance = isApproved ? 1 : 0;
} else {
revert("UNSUPPORTED_ASSET_PROXY");
}
return (balance, allowance);
}
/// @dev Fetches token balances and allowances of an address for each given assetProxy. Supports ERC20 and ERC721.
/// @param target Address to fetch balances and allowances of.
/// @param assetData Array of encoded byte arrays that can be decoded by a specified proxy contract when transferring asset.
/// @return Balances and allowances of assets.
/// For ERC721 tokens, these values will always be 1 or 0.
function getBalancesAndAllowances(address target, bytes[] memory assetData)
public
view
returns (uint256[] memory, uint256[] memory)
{
uint256 length = assetData.length;
uint256[] memory balances = new uint256[](length);
uint256[] memory allowances = new uint256[](length);
for (uint256 i = 0; i != length; i++) {
(balances[i], allowances[i]) = getBalanceAndAllowance(target, assetData[i]);
}
return (balances, allowances);
}
/// @dev Calls `token.ownerOf(tokenId)`, but returns a null owner instead of reverting on an unowned token.
/// @param token Address of ERC721 token.
/// @param tokenId The identifier for the specific NFT.
/// @return Owner of tokenId or null address if unowned.
function getERC721TokenOwner(address token, uint256 tokenId)
public
view
returns (address owner)
{
assembly {
// load free memory pointer
let cdStart := mload(64)
// bytes4(keccak256(ownerOf(uint256))) = 0x6352211e
mstore(cdStart, 0x6352211e00000000000000000000000000000000000000000000000000000000)
mstore(add(cdStart, 4), tokenId)
// staticcall `ownerOf(tokenId)`
// `ownerOf` will revert if tokenId is not owned
let success := staticcall(
gas, // forward all gas
token, // call token contract
cdStart, // start of calldata
36, // length of input is 36 bytes
cdStart, // write output over input
32 // size of output is 32 bytes
)
// Success implies that tokenId is owned
// Copy owner from return data if successful
if success {
owner := mload(cdStart)
}
}
// Owner initialized to address(0), no need to modify if call is unsuccessful
return owner;
}
}

View File

@@ -1,93 +0,0 @@
{
"name": "@0x/contracts-extensions",
"version": "1.2.1",
"engines": {
"node": ">=6.12"
},
"description": "Smart contract extensions of 0x protocol",
"main": "lib/src/index.js",
"directories": {
"test": "test"
},
"scripts": {
"build": "yarn pre_build && tsc -b",
"build:ci": "yarn build",
"pre_build": "run-s compile generate_contract_wrappers",
"test": "yarn run_mocha",
"rebuild_and_test": "run-s build test",
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
"test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
"compile": "sol-compiler",
"watch": "sol-compiler -w",
"clean": "shx rm -rf lib generated-artifacts 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 generated-wrappers --backend ethers",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
"coverage:report:text": "istanbul report text",
"coverage:report:html": "istanbul report html && open coverage/index.html",
"profiler:report:html": "istanbul report html && open coverage/index.html",
"coverage:report:lcov": "istanbul report lcov",
"test:circleci": "yarn test",
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
},
"config": {
"abis": "generated-artifacts/@(BalanceThresholdFilter|DutchAuction|Forwarder|OrderMatcher|OrderValidator).json"
},
"repository": {
"type": "git",
"url": "https://github.com/0xProject/0x-monorepo.git"
},
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/0xProject/0x-monorepo/issues"
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/extensions/README.md",
"devDependencies": {
"@0x/abi-gen": "^1.0.21",
"@0x/contract-wrappers": "^4.2.1",
"@0x/contracts-test-utils": "^1.0.4",
"@0x/dev-utils": "^1.0.23",
"@0x/sol-compiler": "^2.0.1",
"@0x/subproviders": "^2.1.10",
"@0x/tslint-config": "^2.0.1",
"@types/bn.js": "^4.11.0",
"@types/lodash": "4.14.104",
"@types/node": "*",
"@types/yargs": "^10.0.0",
"chai": "^4.0.1",
"chai-as-promised": "^7.1.0",
"chai-bignumber": "^2.0.1",
"dirty-chai": "^2.0.1",
"ethereumjs-abi": "0.6.5",
"make-promises-safe": "^1.1.0",
"mocha": "^4.1.0",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"solhint": "^1.4.1",
"tslint": "5.11.0",
"typescript": "3.0.1",
"yargs": "^10.0.3"
},
"dependencies": {
"@0x/base-contract": "^3.0.12",
"@0x/contracts-interfaces": "^1.0.4",
"@0x/contracts-libs": "^1.0.4",
"@0x/contracts-protocol": "^2.2.1",
"@0x/contracts-tokens": "^1.0.4",
"@0x/contracts-utils": "^1.0.4",
"@0x/order-utils": "^3.1.1",
"@0x/types": "^1.5.1",
"@0x/typescript-typings": "^3.0.7",
"@0x/utils": "^3.0.0",
"@0x/web3-wrapper": "^3.2.3",
"@types/js-combinatorics": "^0.5.29",
"bn.js": "^4.11.8",
"ethereum-types": "^1.1.5",
"ethereumjs-util": "^5.1.1",
"lodash": "^4.17.5"
},
"publishConfig": {
"access": "public"
}
}

View File

@@ -1,15 +0,0 @@
import { ContractArtifact } from 'ethereum-types';
import * as BalanceThresholdFilter from '../../generated-artifacts/BalanceThresholdFilter.json';
import * as DutchAuction from '../../generated-artifacts/DutchAuction.json';
import * as Forwarder from '../../generated-artifacts/Forwarder.json';
import * as OrderMatcher from '../../generated-artifacts/OrderMatcher.json';
import * as OrderValidator from '../../generated-artifacts/OrderValidator.json';
export const artifacts = {
BalanceThresholdFilter: BalanceThresholdFilter as ContractArtifact,
DutchAuction: DutchAuction as ContractArtifact,
Forwarder: Forwarder as ContractArtifact,
OrderMatcher: OrderMatcher as ContractArtifact,
OrderValidator: OrderValidator as ContractArtifact,
};

View File

@@ -1,2 +0,0 @@
export * from './artifacts';
export * from './wrappers';

View File

@@ -1,5 +0,0 @@
export * from '../../generated-wrappers/balance_threshold_filter';
export * from '../../generated-wrappers/dutch_auction';
export * from '../../generated-wrappers/forwarder';
export * from '../../generated-wrappers/order_matcher';
export * from '../../generated-wrappers/order_validator';

View File

@@ -1,378 +0,0 @@
import { DutchAuctionWrapper } from '@0x/contract-wrappers';
import {
artifacts as protocolArtifacts,
ERC20Wrapper,
ERC721Wrapper,
ExchangeContract,
ExchangeWrapper,
} from '@0x/contracts-protocol';
import {
chaiSetup,
constants,
ContractName,
ERC20BalancesByOwner,
expectTransactionFailedAsync,
getLatestBlockTimestampAsync,
OrderFactory,
provider,
txDefaults,
web3Wrapper,
} from '@0x/contracts-test-utils';
import {
artifacts as tokensArtifacts,
DummyERC20TokenContract,
DummyERC721TokenContract,
WETH9Contract,
} from '@0x/contracts-tokens';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { assetDataUtils, generatePseudoRandomSalt } 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 * as _ from 'lodash';
import { DutchAuctionContract } from '../../generated-wrappers/dutch_auction';
import { artifacts } from '../../src/artifacts';
import { DutchAuctionTestWrapper } from '../utils/dutch_auction_test_wrapper';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
const DECIMALS_DEFAULT = 18;
describe(ContractName.DutchAuction, () => {
let makerAddress: string;
let owner: string;
let takerAddress: string;
let feeRecipientAddress: string;
let defaultMakerAssetAddress: string;
let zrxToken: DummyERC20TokenContract;
let erc20TokenA: DummyERC20TokenContract;
let erc721Token: DummyERC721TokenContract;
let dutchAuctionContract: DutchAuctionContract;
let wethContract: WETH9Contract;
let sellerOrderFactory: OrderFactory;
let buyerOrderFactory: OrderFactory;
let erc20Wrapper: ERC20Wrapper;
let erc20Balances: ERC20BalancesByOwner;
let currentBlockTimestamp: number;
let auctionBeginTimeSeconds: BigNumber;
let auctionEndTimeSeconds: BigNumber;
let auctionBeginAmount: BigNumber;
let auctionEndAmount: BigNumber;
let sellOrder: SignedOrder;
let buyOrder: SignedOrder;
let erc721MakerAssetIds: BigNumber[];
const tenMinutesInSeconds = 10 * 60;
let dutchAuctionTestWrapper: DutchAuctionTestWrapper;
let defaultERC20MakerAssetData: string;
before(async () => {
await blockchainLifecycle.startAsync();
const accounts = await web3Wrapper.getAvailableAddressesAsync();
const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = accounts);
erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
const numDummyErc20ToDeploy = 2;
[erc20TokenA, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
numDummyErc20ToDeploy,
constants.DUMMY_TOKEN_DECIMALS,
);
const erc20Proxy = await erc20Wrapper.deployProxyAsync();
await erc20Wrapper.setBalancesAndAllowancesAsync();
const erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
[erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
const erc721Proxy = await erc721Wrapper.deployProxyAsync();
await erc721Wrapper.setBalancesAndAllowancesAsync();
const erc721Balances = await erc721Wrapper.getBalancesAsync();
erc721MakerAssetIds = erc721Balances[makerAddress][erc721Token.address];
wethContract = await WETH9Contract.deployFrom0xArtifactAsync(tokensArtifacts.WETH9, provider, txDefaults);
erc20Wrapper.addDummyTokenContract(wethContract as any);
const zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
protocolArtifacts.Exchange,
provider,
txDefaults,
zrxAssetData,
);
const exchangeWrapper = new ExchangeWrapper(exchangeInstance, provider);
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, {
from: owner,
});
await erc721Proxy.addAuthorizedAddress.sendTransactionAsync(exchangeInstance.address, {
from: owner,
});
const dutchAuctionInstance = await DutchAuctionContract.deployFrom0xArtifactAsync(
artifacts.DutchAuction,
provider,
txDefaults,
exchangeInstance.address,
);
dutchAuctionContract = new DutchAuctionContract(
dutchAuctionInstance.abi,
dutchAuctionInstance.address,
provider,
);
dutchAuctionTestWrapper = new DutchAuctionTestWrapper(dutchAuctionInstance, provider);
defaultMakerAssetAddress = erc20TokenA.address;
const defaultTakerAssetAddress = wethContract.address;
// Set up taker WETH balance and allowance
await web3Wrapper.awaitTransactionSuccessAsync(
await wethContract.deposit.sendTransactionAsync({
from: takerAddress,
value: Web3Wrapper.toBaseUnitAmount(new BigNumber(50), DECIMALS_DEFAULT),
}),
);
await web3Wrapper.awaitTransactionSuccessAsync(
await wethContract.approve.sendTransactionAsync(
erc20Proxy.address,
constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS,
{ from: takerAddress },
),
);
web3Wrapper.abiDecoder.addABI(exchangeInstance.abi);
web3Wrapper.abiDecoder.addABI(zrxToken.abi);
erc20Wrapper.addTokenOwnerAddress(dutchAuctionContract.address);
currentBlockTimestamp = await getLatestBlockTimestampAsync();
// Default auction begins 10 minutes ago
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp).minus(tenMinutesInSeconds);
// Default auction ends 10 from now
auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp).plus(tenMinutesInSeconds);
auctionBeginAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(10), DECIMALS_DEFAULT);
auctionEndAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), DECIMALS_DEFAULT);
// Default sell order and buy order are exact mirrors
const sellerDefaultOrderParams = {
salt: generatePseudoRandomSalt(),
exchangeAddress: exchangeInstance.address,
makerAddress,
feeRecipientAddress,
// taker address or sender address should be set to the ducth auction contract
takerAddress: dutchAuctionContract.address,
makerAssetData: DutchAuctionWrapper.encodeDutchAuctionAssetData(
assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
auctionBeginTimeSeconds,
auctionBeginAmount,
),
takerAssetData: assetDataUtils.encodeERC20AssetData(defaultTakerAssetAddress),
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(200), DECIMALS_DEFAULT),
takerAssetAmount: auctionEndAmount,
expirationTimeSeconds: auctionEndTimeSeconds,
makerFee: constants.ZERO_AMOUNT,
takerFee: constants.ZERO_AMOUNT,
};
// Default buy order is for the auction begin price
const buyerDefaultOrderParams = {
...sellerDefaultOrderParams,
makerAddress: takerAddress,
makerAssetData: sellerDefaultOrderParams.takerAssetData,
takerAssetData: sellerDefaultOrderParams.makerAssetData,
makerAssetAmount: auctionBeginAmount,
takerAssetAmount: sellerDefaultOrderParams.makerAssetAmount,
};
const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)];
sellerOrderFactory = new OrderFactory(makerPrivateKey, sellerDefaultOrderParams);
buyerOrderFactory = new OrderFactory(takerPrivateKey, buyerDefaultOrderParams);
defaultERC20MakerAssetData = assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress);
});
after(async () => {
await blockchainLifecycle.revertAsync();
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
erc20Balances = await erc20Wrapper.getBalancesAsync();
sellOrder = await sellerOrderFactory.newSignedOrderAsync();
buyOrder = await buyerOrderFactory.newSignedOrderAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
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(
defaultERC20MakerAssetData,
auctionBeginTimeSeconds,
auctionBeginAmount,
);
sellOrder = await sellerOrderFactory.newSignedOrderAsync({ makerAssetData });
const auctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
expect(auctionDetails.currentTimeSeconds).to.be.bignumber.lte(auctionBeginTimeSeconds);
expect(auctionDetails.currentAmount).to.be.bignumber.equal(auctionBeginAmount);
expect(auctionDetails.beginAmount).to.be.bignumber.equal(auctionBeginAmount);
});
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(
defaultERC20MakerAssetData,
auctionBeginTimeSeconds,
auctionBeginAmount,
);
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
makerAssetData,
expirationTimeSeconds: auctionEndTimeSeconds,
});
const auctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
expect(auctionDetails.currentTimeSeconds).to.be.bignumber.gte(auctionEndTimeSeconds);
expect(auctionDetails.currentAmount).to.be.bignumber.equal(auctionEndAmount);
expect(auctionDetails.beginAmount).to.be.bignumber.equal(auctionBeginAmount);
});
it('should match orders at current amount and send excess to buyer', async () => {
const beforeAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
buyOrder = await buyerOrderFactory.newSignedOrderAsync({
makerAssetAmount: beforeAuctionDetails.currentAmount.times(2),
});
await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
const newBalances = await erc20Wrapper.getBalancesAsync();
expect(newBalances[dutchAuctionContract.address][wethContract.address]).to.be.bignumber.equal(
constants.ZERO_AMOUNT,
);
// HACK gte used here due to a bug in ganache where the timestamp can change
// between multiple calls to the same block. Which can move the amount in our case
// ref: https://github.com/trufflesuite/ganache-core/issues/111
expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte(
erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount),
);
expect(newBalances[takerAddress][wethContract.address]).to.be.bignumber.gte(
erc20Balances[takerAddress][wethContract.address].minus(beforeAuctionDetails.currentAmount),
);
});
it('maker fees on sellOrder are paid to the fee receipient', async () => {
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
makerFee: new BigNumber(1),
});
await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
const newBalances = await erc20Wrapper.getBalancesAsync();
expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte(
erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount),
);
expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
erc20Balances[feeRecipientAddress][zrxToken.address].plus(sellOrder.makerFee),
);
});
it('maker fees on buyOrder are paid to the fee receipient', async () => {
buyOrder = await buyerOrderFactory.newSignedOrderAsync({
makerFee: new BigNumber(1),
});
await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
const newBalances = await erc20Wrapper.getBalancesAsync();
const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte(
erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount),
);
expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal(
erc20Balances[feeRecipientAddress][zrxToken.address].plus(buyOrder.makerFee),
);
});
it('should revert when auction expires', async () => {
auctionBeginTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds * 2);
auctionEndTimeSeconds = new BigNumber(currentBlockTimestamp - tenMinutesInSeconds);
const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData(
defaultERC20MakerAssetData,
auctionBeginTimeSeconds,
auctionBeginAmount,
);
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
expirationTimeSeconds: auctionEndTimeSeconds,
makerAssetData,
});
return expectTransactionFailedAsync(
dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
RevertReason.AuctionExpired,
);
});
it('cannot be filled for less than the current price', async () => {
buyOrder = await buyerOrderFactory.newSignedOrderAsync({
makerAssetAmount: sellOrder.takerAssetAmount,
});
return expectTransactionFailedAsync(
dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
RevertReason.AuctionInvalidAmount,
);
});
it('auction begin amount must be higher than final amount ', async () => {
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
takerAssetAmount: auctionBeginAmount.plus(1),
});
return expectTransactionFailedAsync(
dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
RevertReason.AuctionInvalidAmount,
);
});
it('begin time is less than end time', async () => {
auctionBeginTimeSeconds = new BigNumber(auctionEndTimeSeconds).plus(tenMinutesInSeconds);
const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData(
defaultERC20MakerAssetData,
auctionBeginTimeSeconds,
auctionBeginAmount,
);
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
expirationTimeSeconds: auctionEndTimeSeconds,
makerAssetData,
});
return expectTransactionFailedAsync(
dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
RevertReason.AuctionInvalidBeginTime,
);
});
it('asset data contains auction parameters', async () => {
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
makerAssetData: assetDataUtils.encodeERC20AssetData(defaultMakerAssetAddress),
});
return expectTransactionFailedAsync(
dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress),
RevertReason.InvalidAssetData,
);
});
describe('ERC721', () => {
it('should match orders when ERC721', async () => {
const makerAssetId = erc721MakerAssetIds[0];
const erc721MakerAssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, makerAssetId);
const makerAssetData = DutchAuctionWrapper.encodeDutchAuctionAssetData(
erc721MakerAssetData,
auctionBeginTimeSeconds,
auctionBeginAmount,
);
sellOrder = await sellerOrderFactory.newSignedOrderAsync({
makerAssetAmount: new BigNumber(1),
makerAssetData,
});
buyOrder = await buyerOrderFactory.newSignedOrderAsync({
takerAssetAmount: new BigNumber(1),
takerAssetData: sellOrder.makerAssetData,
});
await dutchAuctionTestWrapper.matchOrdersAsync(buyOrder, sellOrder, takerAddress);
const afterAuctionDetails = await dutchAuctionTestWrapper.getAuctionDetailsAsync(sellOrder);
const newBalances = await erc20Wrapper.getBalancesAsync();
// HACK gte used here due to a bug in ganache where the timestamp can change
// between multiple calls to the same block. Which can move the amount in our case
// ref: https://github.com/trufflesuite/ganache-core/issues/111
expect(newBalances[makerAddress][wethContract.address]).to.be.bignumber.gte(
erc20Balances[makerAddress][wethContract.address].plus(afterAuctionDetails.currentAmount),
);
const newOwner = await erc721Token.ownerOf.callAsync(makerAssetId);
expect(newOwner).to.be.bignumber.equal(takerAddress);
});
});
});
});

View File

@@ -1,818 +0,0 @@
import {
artifacts as protocolArtifacts,
ERC20ProxyContract,
ERC20Wrapper,
ERC721ProxyContract,
ExchangeContract,
ExchangeFillEventArgs,
ExchangeWrapper,
} from '@0x/contracts-protocol';
import {
chaiSetup,
constants,
ERC20BalancesByOwner,
expectContractCreationFailedAsync,
expectTransactionFailedAsync,
LogDecoder,
OrderFactory,
provider,
sendTransactionResult,
txDefaults,
web3Wrapper,
} from '@0x/contracts-test-utils';
import { artifacts as tokenArtifacts, DummyERC20TokenContract, DummyERC721TokenContract } from '@0x/contracts-tokens';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { assetDataUtils } from '@0x/order-utils';
import { RevertReason } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import * as chai from 'chai';
import { LogWithDecodedArgs } from 'ethereum-types';
import * as _ from 'lodash';
import { OrderMatcherContract } from '../../generated-wrappers/order_matcher';
import { artifacts } from '../../src/artifacts';
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
chaiSetup.configure();
const expect = chai.expect;
// tslint:disable:no-unnecessary-type-assertion
describe('OrderMatcher', () => {
let makerAddressLeft: string;
let makerAddressRight: string;
let owner: string;
let takerAddress: string;
let feeRecipientAddressLeft: string;
let feeRecipientAddressRight: string;
let erc20TokenA: DummyERC20TokenContract;
let erc20TokenB: DummyERC20TokenContract;
let zrxToken: DummyERC20TokenContract;
let exchange: ExchangeContract;
let erc20Proxy: ERC20ProxyContract;
let erc721Proxy: ERC721ProxyContract;
let orderMatcher: OrderMatcherContract;
let erc20BalancesByOwner: ERC20BalancesByOwner;
let exchangeWrapper: ExchangeWrapper;
let erc20Wrapper: ERC20Wrapper;
let orderFactoryLeft: OrderFactory;
let orderFactoryRight: OrderFactory;
let leftMakerAssetData: string;
let leftTakerAssetData: string;
let defaultERC20MakerAssetAddress: string;
let defaultERC20TakerAssetAddress: string;
before(async () => {
await blockchainLifecycle.startAsync();
});
after(async () => {
await blockchainLifecycle.revertAsync();
});
before(async () => {
// Create accounts
const accounts = await web3Wrapper.getAvailableAddressesAsync();
// Hack(albrow): Both Prettier and TSLint insert a trailing comma below
// but that is invalid syntax as of TypeScript version >= 2.8. We don't
// have the right fine-grained configuration options in TSLint,
// Prettier, or TypeScript, to reconcile this, so we will just have to
// wait for them to sort it out. We disable TSLint and Prettier for
// this part of the code for now. This occurs several times in this
// file. See https://github.com/prettier/prettier/issues/4624.
// prettier-ignore
const usedAddresses = ([
owner,
makerAddressLeft,
makerAddressRight,
takerAddress,
feeRecipientAddressLeft,
// tslint:disable-next-line:trailing-comma
feeRecipientAddressRight
] = _.slice(accounts, 0, 6));
// Create wrappers
erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
// Deploy ERC20 token & ERC20 proxy
const numDummyErc20ToDeploy = 3;
[erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
numDummyErc20ToDeploy,
constants.DUMMY_TOKEN_DECIMALS,
);
erc20Proxy = await erc20Wrapper.deployProxyAsync();
await erc20Wrapper.setBalancesAndAllowancesAsync();
// Deploy ERC721 proxy
erc721Proxy = await ERC721ProxyContract.deployFrom0xArtifactAsync(
protocolArtifacts.ERC721Proxy,
provider,
txDefaults,
);
// Depoy exchange
exchange = await ExchangeContract.deployFrom0xArtifactAsync(
protocolArtifacts.Exchange,
provider,
txDefaults,
assetDataUtils.encodeERC20AssetData(zrxToken.address),
);
exchangeWrapper = new ExchangeWrapper(exchange, provider);
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
// Authorize ERC20 trades by exchange
await web3Wrapper.awaitTransactionSuccessAsync(
await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, {
from: owner,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
// Deploy OrderMatcher
orderMatcher = await OrderMatcherContract.deployFrom0xArtifactAsync(
artifacts.OrderMatcher,
provider,
txDefaults,
exchange.address,
);
// Set default addresses
defaultERC20MakerAssetAddress = erc20TokenA.address;
defaultERC20TakerAssetAddress = erc20TokenB.address;
leftMakerAssetData = assetDataUtils.encodeERC20AssetData(defaultERC20MakerAssetAddress);
leftTakerAssetData = assetDataUtils.encodeERC20AssetData(defaultERC20TakerAssetAddress);
// Set OrderMatcher balances and allowances
await web3Wrapper.awaitTransactionSuccessAsync(
await erc20TokenA.setBalance.sendTransactionAsync(orderMatcher.address, constants.INITIAL_ERC20_BALANCE, {
from: owner,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc20TokenB.setBalance.sendTransactionAsync(orderMatcher.address, constants.INITIAL_ERC20_BALANCE, {
from: owner,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await orderMatcher.approveAssetProxy.sendTransactionAsync(
leftMakerAssetData,
constants.INITIAL_ERC20_ALLOWANCE,
),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await orderMatcher.approveAssetProxy.sendTransactionAsync(
leftTakerAssetData,
constants.INITIAL_ERC20_ALLOWANCE,
),
constants.AWAIT_TRANSACTION_MINED_MS,
);
// Create default order parameters
const defaultOrderParamsLeft = {
...constants.STATIC_ORDER_PARAMS,
makerAddress: makerAddressLeft,
exchangeAddress: exchange.address,
makerAssetData: leftMakerAssetData,
takerAssetData: leftTakerAssetData,
feeRecipientAddress: feeRecipientAddressLeft,
makerFee: constants.ZERO_AMOUNT,
takerFee: constants.ZERO_AMOUNT,
};
const defaultOrderParamsRight = {
...constants.STATIC_ORDER_PARAMS,
makerAddress: makerAddressRight,
exchangeAddress: exchange.address,
makerAssetData: leftTakerAssetData,
takerAssetData: leftMakerAssetData,
feeRecipientAddress: feeRecipientAddressRight,
makerFee: constants.ZERO_AMOUNT,
takerFee: constants.ZERO_AMOUNT,
};
const privateKeyLeft = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressLeft)];
orderFactoryLeft = new OrderFactory(privateKeyLeft, defaultOrderParamsLeft);
const privateKeyRight = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddressRight)];
orderFactoryRight = new OrderFactory(privateKeyRight, defaultOrderParamsRight);
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('constructor', () => {
it('should revert if assetProxy is unregistered', async () => {
const exchangeInstance = await ExchangeContract.deployFrom0xArtifactAsync(
protocolArtifacts.Exchange,
provider,
txDefaults,
constants.NULL_BYTES,
);
return expectContractCreationFailedAsync(
(OrderMatcherContract.deployFrom0xArtifactAsync(
artifacts.OrderMatcher,
provider,
txDefaults,
exchangeInstance.address,
) as any) as sendTransactionResult,
RevertReason.UnregisteredAssetProxy,
);
});
});
describe('matchOrders', () => {
beforeEach(async () => {
erc20BalancesByOwner = await erc20Wrapper.getBalancesAsync();
});
it('should revert if not called by owner', async () => {
// Create orders to match
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
});
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
});
const data = exchange.matchOrders.getABIEncodedTransactionData(
signedOrderLeft,
signedOrderRight,
signedOrderLeft.signature,
signedOrderRight.signature,
);
await expectTransactionFailedAsync(
web3Wrapper.sendTransactionAsync({
data,
to: orderMatcher.address,
from: takerAddress,
gas: constants.MAX_MATCH_ORDERS_GAS,
}),
RevertReason.OnlyContractOwner,
);
});
it('should transfer the correct amounts when orders completely fill each other', async () => {
// Create orders to match
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
});
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
});
// Match signedOrderLeft with signedOrderRight
const expectedTransferAmounts = {
// Left Maker
amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
// Right Maker
amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
// Taker
leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount),
};
const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
const data = exchange.matchOrders.getABIEncodedTransactionData(
signedOrderLeft,
signedOrderRight,
signedOrderLeft.signature,
signedOrderRight.signature,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await web3Wrapper.sendTransactionAsync({
data,
to: orderMatcher.address,
from: owner,
gas: constants.MAX_MATCH_ORDERS_GAS,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
const newErc20Balances = await erc20Wrapper.getBalancesAsync();
expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
expectedTransferAmounts.amountSoldByLeftMaker,
),
);
expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
expectedTransferAmounts.amountSoldByRightMaker,
),
);
expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
expectedTransferAmounts.amountBoughtByLeftMaker,
),
);
expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
expectedTransferAmounts.amountBoughtByRightMaker,
),
);
expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
);
});
it('should transfer the correct amounts when orders completely fill each other and taker doesnt take a profit', async () => {
// Create orders to match
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
});
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
});
// Match signedOrderLeft with signedOrderRight
const expectedTransferAmounts = {
// Left Maker
amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
// Right Maker
amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
};
const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
const data = exchange.matchOrders.getABIEncodedTransactionData(
signedOrderLeft,
signedOrderRight,
signedOrderLeft.signature,
signedOrderRight.signature,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await web3Wrapper.sendTransactionAsync({
data,
to: orderMatcher.address,
from: owner,
gas: constants.MAX_MATCH_ORDERS_GAS,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
const newErc20Balances = await erc20Wrapper.getBalancesAsync();
expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
expectedTransferAmounts.amountSoldByLeftMaker,
),
);
expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
expectedTransferAmounts.amountSoldByRightMaker,
),
);
expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
expectedTransferAmounts.amountBoughtByLeftMaker,
),
);
expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
expectedTransferAmounts.amountBoughtByRightMaker,
),
);
expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(initialLeftMakerAssetTakerBalance);
});
it('should transfer the correct amounts when left order is completely filled and right order would be partially filled', async () => {
// Create orders to match
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
});
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
});
// Match signedOrderLeft with signedOrderRight
const expectedTransferAmounts = {
// Left Maker
amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
// Right Maker
amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
// Taker
leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount),
leftTakerAssetSpreadAmount: signedOrderRight.makerAssetAmount.minus(signedOrderLeft.takerAssetAmount),
};
const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
// Match signedOrderLeft with signedOrderRight
const data = exchange.matchOrders.getABIEncodedTransactionData(
signedOrderLeft,
signedOrderRight,
signedOrderLeft.signature,
signedOrderRight.signature,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await web3Wrapper.sendTransactionAsync({
data,
to: orderMatcher.address,
from: owner,
gas: constants.MAX_MATCH_ORDERS_GAS,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
const newErc20Balances = await erc20Wrapper.getBalancesAsync();
expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
expectedTransferAmounts.amountSoldByLeftMaker,
),
);
expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
expectedTransferAmounts.amountSoldByRightMaker,
),
);
expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
expectedTransferAmounts.amountBoughtByLeftMaker,
),
);
expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
expectedTransferAmounts.amountBoughtByRightMaker,
),
);
expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
);
expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal(
initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount),
);
});
it('should not call fillOrder when rightOrder is completely filled after matchOrders call and orders were never partially filled', async () => {
// Create orders to match
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
});
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
});
const data = exchange.matchOrders.getABIEncodedTransactionData(
signedOrderLeft,
signedOrderRight,
signedOrderLeft.signature,
signedOrderRight.signature,
);
const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokenArtifacts, ...protocolArtifacts });
const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
await web3Wrapper.sendTransactionAsync({
data,
to: orderMatcher.address,
from: owner,
gas: constants.MAX_MATCH_ORDERS_GAS,
}),
);
const fillLogs = _.filter(
txReceipt.logs,
log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
);
// Only 2 Fill logs should exist for `matchOrders` call. `fillOrder` should not have been called and should not have emitted a Fill event.
expect(fillLogs.length).to.be.equal(2);
});
it('should not call fillOrder when rightOrder is completely filled after matchOrders call and orders were initially partially filled', async () => {
// Create orders to match
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
});
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(2), 18),
});
await exchangeWrapper.fillOrderAsync(signedOrderLeft, takerAddress, {
takerAssetFillAmount: signedOrderLeft.takerAssetAmount.dividedToIntegerBy(5),
});
await exchangeWrapper.fillOrderAsync(signedOrderRight, takerAddress, {
takerAssetFillAmount: signedOrderRight.takerAssetAmount.dividedToIntegerBy(5),
});
const data = exchange.matchOrders.getABIEncodedTransactionData(
signedOrderLeft,
signedOrderRight,
signedOrderLeft.signature,
signedOrderRight.signature,
);
const logDecoder = new LogDecoder(web3Wrapper, { ...artifacts, ...tokenArtifacts, ...protocolArtifacts });
const txReceipt = await logDecoder.getTxWithDecodedLogsAsync(
await web3Wrapper.sendTransactionAsync({
data,
to: orderMatcher.address,
from: owner,
gas: constants.MAX_MATCH_ORDERS_GAS,
}),
);
const fillLogs = _.filter(
txReceipt.logs,
log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
);
// Only 2 Fill logs should exist for `matchOrders` call. `fillOrder` should not have been called and should not have emitted a Fill event.
expect(fillLogs.length).to.be.equal(2);
});
it('should only take a spread in rightMakerAsset if entire leftMakerAssetSpread amount can be used to fill rightOrder after matchOrders call', async () => {
// Create orders to match
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(0.9), 18),
});
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(100), 18),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(990), 18),
});
const initialLeftMakerAssetSpreadAmount = Web3Wrapper.toBaseUnitAmount(new BigNumber(1.09), 18);
const leftTakerAssetSpreadAmount = initialLeftMakerAssetSpreadAmount
.times(signedOrderRight.makerAssetAmount)
.dividedToIntegerBy(signedOrderRight.takerAssetAmount);
// Match signedOrderLeft with signedOrderRight
const expectedTransferAmounts = {
// Left Maker
amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
// Right Maker
amountSoldByRightMaker: signedOrderLeft.takerAssetAmount.plus(leftTakerAssetSpreadAmount),
amountBoughtByRightMaker: signedOrderLeft.makerAssetAmount,
// Taker
leftMakerAssetSpreadAmount: constants.ZERO_AMOUNT,
leftTakerAssetSpreadAmount,
};
const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
// Match signedOrderLeft with signedOrderRight
const data = exchange.matchOrders.getABIEncodedTransactionData(
signedOrderLeft,
signedOrderRight,
signedOrderLeft.signature,
signedOrderRight.signature,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await web3Wrapper.sendTransactionAsync({
data,
to: orderMatcher.address,
from: owner,
gas: constants.MAX_MATCH_ORDERS_GAS,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
const newErc20Balances = await erc20Wrapper.getBalancesAsync();
expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
expectedTransferAmounts.amountSoldByLeftMaker,
),
);
expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
expectedTransferAmounts.amountSoldByRightMaker,
),
);
expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
expectedTransferAmounts.amountBoughtByLeftMaker,
),
);
expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
expectedTransferAmounts.amountBoughtByRightMaker,
),
);
expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
);
expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal(
initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount),
);
});
it("should succeed if rightOrder's makerAssetData and takerAssetData are not provided", async () => {
// Create orders to match
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
});
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
});
// Match signedOrderLeft with signedOrderRight
const expectedTransferAmounts = {
// Left Maker
amountSoldByLeftMaker: signedOrderLeft.makerAssetAmount,
amountBoughtByLeftMaker: signedOrderLeft.takerAssetAmount,
// Right Maker
amountSoldByRightMaker: signedOrderRight.makerAssetAmount,
amountBoughtByRightMaker: signedOrderRight.takerAssetAmount,
// Taker
leftMakerAssetSpreadAmount: signedOrderLeft.makerAssetAmount.minus(signedOrderRight.takerAssetAmount),
leftTakerAssetSpreadAmount: signedOrderRight.makerAssetAmount.minus(signedOrderLeft.takerAssetAmount),
};
const initialLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
const initialLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
// Match signedOrderLeft with signedOrderRight
signedOrderRight.makerAssetData = constants.NULL_BYTES;
signedOrderRight.takerAssetData = constants.NULL_BYTES;
const data = exchange.matchOrders.getABIEncodedTransactionData(
signedOrderLeft,
signedOrderRight,
signedOrderLeft.signature,
signedOrderRight.signature,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await web3Wrapper.sendTransactionAsync({
data,
to: orderMatcher.address,
from: owner,
gas: constants.MAX_MATCH_ORDERS_GAS,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const newLeftMakerAssetTakerBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
const newLeftTakerAssetTakerBalance = await erc20TokenB.balanceOf.callAsync(orderMatcher.address);
const newErc20Balances = await erc20Wrapper.getBalancesAsync();
expect(newErc20Balances[makerAddressLeft][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
erc20BalancesByOwner[makerAddressLeft][defaultERC20MakerAssetAddress].minus(
expectedTransferAmounts.amountSoldByLeftMaker,
),
);
expect(newErc20Balances[makerAddressRight][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
erc20BalancesByOwner[makerAddressRight][defaultERC20TakerAssetAddress].minus(
expectedTransferAmounts.amountSoldByRightMaker,
),
);
expect(newErc20Balances[makerAddressLeft][defaultERC20TakerAssetAddress]).to.be.bignumber.equal(
erc20BalancesByOwner[makerAddressLeft][defaultERC20TakerAssetAddress].plus(
expectedTransferAmounts.amountBoughtByLeftMaker,
),
);
expect(newErc20Balances[makerAddressRight][defaultERC20MakerAssetAddress]).to.be.bignumber.equal(
erc20BalancesByOwner[makerAddressRight][defaultERC20MakerAssetAddress].plus(
expectedTransferAmounts.amountBoughtByRightMaker,
),
);
expect(newLeftMakerAssetTakerBalance).to.be.bignumber.equal(
initialLeftMakerAssetTakerBalance.plus(expectedTransferAmounts.leftMakerAssetSpreadAmount),
);
expect(newLeftTakerAssetTakerBalance).to.be.bignumber.equal(
initialLeftTakerAssetTakerBalance.plus(expectedTransferAmounts.leftTakerAssetSpreadAmount),
);
});
it('should revert with the correct reason if matchOrders call reverts', async () => {
// Create orders to match
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
});
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
});
signedOrderRight.signature = `0xff${signedOrderRight.signature.slice(4)}`;
const data = exchange.matchOrders.getABIEncodedTransactionData(
signedOrderLeft,
signedOrderRight,
signedOrderLeft.signature,
signedOrderRight.signature,
);
await expectTransactionFailedAsync(
web3Wrapper.sendTransactionAsync({
data,
to: orderMatcher.address,
from: owner,
gas: constants.MAX_MATCH_ORDERS_GAS,
}),
RevertReason.InvalidOrderSignature,
);
});
it('should revert with the correct reason if fillOrder call reverts', async () => {
// Create orders to match
const signedOrderLeft = await orderFactoryLeft.newSignedOrderAsync({
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(5), 18),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(10), 18),
});
const signedOrderRight = await orderFactoryRight.newSignedOrderAsync({
makerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(20), 18),
takerAssetAmount: Web3Wrapper.toBaseUnitAmount(new BigNumber(4), 18),
});
// Matcher will not have enough allowance to fill rightOrder
await web3Wrapper.awaitTransactionSuccessAsync(
await orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, constants.ZERO_AMOUNT, {
from: owner,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const data = exchange.matchOrders.getABIEncodedTransactionData(
signedOrderLeft,
signedOrderRight,
signedOrderLeft.signature,
signedOrderRight.signature,
);
await expectTransactionFailedAsync(
web3Wrapper.sendTransactionAsync({
data,
to: orderMatcher.address,
from: owner,
gas: constants.MAX_MATCH_ORDERS_GAS,
}),
RevertReason.TransferFailed,
);
});
});
describe('withdrawAsset', () => {
it('should allow owner to withdraw ERC20 tokens', async () => {
const erc20AWithdrawAmount = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
expect(erc20AWithdrawAmount).to.be.bignumber.gt(constants.ZERO_AMOUNT);
await web3Wrapper.awaitTransactionSuccessAsync(
await orderMatcher.withdrawAsset.sendTransactionAsync(leftMakerAssetData, erc20AWithdrawAmount, {
from: owner,
}),
);
const newBalance = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
expect(newBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
});
it('should allow owner to withdraw ERC721 tokens', async () => {
const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
tokenArtifacts.DummyERC721Token,
provider,
txDefaults,
constants.DUMMY_TOKEN_NAME,
constants.DUMMY_TOKEN_SYMBOL,
);
const tokenId = new BigNumber(1);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc721Token.mint.sendTransactionAsync(orderMatcher.address, tokenId, { from: owner }),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId);
const withdrawAmount = new BigNumber(1);
await web3Wrapper.awaitTransactionSuccessAsync(
await orderMatcher.withdrawAsset.sendTransactionAsync(assetData, withdrawAmount, { from: owner }),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const erc721Owner = await erc721Token.ownerOf.callAsync(tokenId);
expect(erc721Owner).to.be.equal(owner);
});
it('should revert if not called by owner', async () => {
const erc20AWithdrawAmount = await erc20TokenA.balanceOf.callAsync(orderMatcher.address);
expect(erc20AWithdrawAmount).to.be.bignumber.gt(constants.ZERO_AMOUNT);
await expectTransactionFailedAsync(
orderMatcher.withdrawAsset.sendTransactionAsync(leftMakerAssetData, erc20AWithdrawAmount, {
from: takerAddress,
}),
RevertReason.OnlyContractOwner,
);
});
});
describe('approveAssetProxy', () => {
it('should be able to set an allowance for ERC20 tokens', async () => {
const allowance = new BigNumber(55465465426546);
await web3Wrapper.awaitTransactionSuccessAsync(
await orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, allowance, {
from: owner,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const newAllowance = await erc20TokenA.allowance.callAsync(orderMatcher.address, erc20Proxy.address);
expect(newAllowance).to.be.bignumber.equal(allowance);
});
it('should be able to approve an ERC721 token by passing in allowance = 1', async () => {
const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
tokenArtifacts.DummyERC721Token,
provider,
txDefaults,
constants.DUMMY_TOKEN_NAME,
constants.DUMMY_TOKEN_SYMBOL,
);
const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, constants.ZERO_AMOUNT);
const allowance = new BigNumber(1);
await web3Wrapper.awaitTransactionSuccessAsync(
await orderMatcher.approveAssetProxy.sendTransactionAsync(assetData, allowance, { from: owner }),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const isApproved = await erc721Token.isApprovedForAll.callAsync(orderMatcher.address, erc721Proxy.address);
expect(isApproved).to.be.equal(true);
});
it('should be able to approve an ERC721 token by passing in allowance > 1', async () => {
const erc721Token = await DummyERC721TokenContract.deployFrom0xArtifactAsync(
tokenArtifacts.DummyERC721Token,
provider,
txDefaults,
constants.DUMMY_TOKEN_NAME,
constants.DUMMY_TOKEN_SYMBOL,
);
const assetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, constants.ZERO_AMOUNT);
const allowance = new BigNumber(2);
await web3Wrapper.awaitTransactionSuccessAsync(
await orderMatcher.approveAssetProxy.sendTransactionAsync(assetData, allowance, { from: owner }),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const isApproved = await erc721Token.isApprovedForAll.callAsync(orderMatcher.address, erc721Proxy.address);
expect(isApproved).to.be.equal(true);
});
it('should revert if not called by owner', async () => {
const approval = new BigNumber(1);
await expectTransactionFailedAsync(
orderMatcher.approveAssetProxy.sendTransactionAsync(leftMakerAssetData, approval, {
from: takerAddress,
}),
RevertReason.OnlyContractOwner,
);
});
});
});
// tslint:disable:max-file-line-count
// tslint:enable:no-unnecessary-type-assertion

View File

@@ -1,609 +0,0 @@
import {
artifacts as protocolArtifacts,
ERC20ProxyContract,
ERC20Wrapper,
ERC721ProxyContract,
ERC721Wrapper,
ExchangeContract,
ExchangeWrapper,
} from '@0x/contracts-protocol';
import {
chaiSetup,
constants,
OrderFactory,
OrderStatus,
provider,
txDefaults,
web3Wrapper,
} from '@0x/contracts-test-utils';
import { DummyERC20TokenContract, DummyERC721TokenContract } from '@0x/contracts-tokens';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
import { SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
import * as _ from 'lodash';
import { OrderValidatorContract } from '../../generated-wrappers/order_validator';
import { artifacts } from '../../src/artifacts/index';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
describe('OrderValidator', () => {
let makerAddress: string;
let owner: string;
let takerAddress: string;
let erc20AssetData: string;
let erc721AssetData: string;
let erc20Token: DummyERC20TokenContract;
let zrxToken: DummyERC20TokenContract;
let erc721Token: DummyERC721TokenContract;
let exchange: ExchangeContract;
let orderValidator: OrderValidatorContract;
let erc20Proxy: ERC20ProxyContract;
let erc721Proxy: ERC721ProxyContract;
let signedOrder: SignedOrder;
let signedOrder2: SignedOrder;
let orderFactory: OrderFactory;
const tokenId = new BigNumber(123456789);
const tokenId2 = new BigNumber(987654321);
const ERC721_BALANCE = new BigNumber(1);
const ERC721_ALLOWANCE = new BigNumber(1);
before(async () => {
await blockchainLifecycle.startAsync();
});
after(async () => {
await blockchainLifecycle.revertAsync();
});
before(async () => {
const accounts = await web3Wrapper.getAvailableAddressesAsync();
const usedAddresses = ([owner, makerAddress, takerAddress] = _.slice(accounts, 0, 3));
const erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
const erc721Wrapper = new ERC721Wrapper(provider, usedAddresses, owner);
const numDummyErc20ToDeploy = 2;
[erc20Token, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
numDummyErc20ToDeploy,
constants.DUMMY_TOKEN_DECIMALS,
);
erc20Proxy = await erc20Wrapper.deployProxyAsync();
[erc721Token] = await erc721Wrapper.deployDummyTokensAsync();
erc721Proxy = await erc721Wrapper.deployProxyAsync();
const zrxAssetData = assetDataUtils.encodeERC20AssetData(zrxToken.address);
exchange = await ExchangeContract.deployFrom0xArtifactAsync(
protocolArtifacts.Exchange,
provider,
txDefaults,
zrxAssetData,
);
const exchangeWrapper = new ExchangeWrapper(exchange, provider);
await exchangeWrapper.registerAssetProxyAsync(erc20Proxy.address, owner);
await exchangeWrapper.registerAssetProxyAsync(erc721Proxy.address, owner);
orderValidator = await OrderValidatorContract.deployFrom0xArtifactAsync(
artifacts.OrderValidator,
provider,
txDefaults,
exchange.address,
zrxAssetData,
);
erc20AssetData = assetDataUtils.encodeERC20AssetData(erc20Token.address);
erc721AssetData = assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId);
const defaultOrderParams = {
...constants.STATIC_ORDER_PARAMS,
exchangeAddress: exchange.address,
makerAddress,
feeRecipientAddress: constants.NULL_ADDRESS,
makerAssetData: erc20AssetData,
takerAssetData: erc721AssetData,
};
const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
orderFactory = new OrderFactory(privateKey, defaultOrderParams);
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('getBalanceAndAllowance', () => {
describe('getERC721TokenOwner', async () => {
it('should return the null address when tokenId is not owned', async () => {
const tokenOwner = await orderValidator.getERC721TokenOwner.callAsync(makerAddress, tokenId);
expect(tokenOwner).to.be.equal(constants.NULL_ADDRESS);
});
it('should return the owner address when tokenId is owned', async () => {
await web3Wrapper.awaitTransactionSuccessAsync(
await erc721Token.mint.sendTransactionAsync(makerAddress, tokenId),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const tokenOwner = await orderValidator.getERC721TokenOwner.callAsync(erc721Token.address, tokenId);
expect(tokenOwner).to.be.equal(makerAddress);
});
});
describe('ERC20 assetData', () => {
it('should return the correct balances and allowances when both values are 0', async () => {
const [newBalance, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync(
makerAddress,
erc20AssetData,
);
expect(constants.ZERO_AMOUNT).to.be.bignumber.equal(newBalance);
expect(constants.ZERO_AMOUNT).to.be.bignumber.equal(newAllowance);
});
it('should return the correct balance and allowance when both values are non-zero', async () => {
const balance = new BigNumber(123);
const allowance = new BigNumber(456);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc20Token.setBalance.sendTransactionAsync(makerAddress, balance),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, allowance, {
from: makerAddress,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const [newBalance, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync(
makerAddress,
erc20AssetData,
);
expect(balance).to.be.bignumber.equal(newBalance);
expect(allowance).to.be.bignumber.equal(newAllowance);
});
});
describe('ERC721 assetData', () => {
it('should return a balance of 0 when the tokenId is not owned by target', async () => {
const [newBalance] = await orderValidator.getBalanceAndAllowance.callAsync(
makerAddress,
erc721AssetData,
);
expect(newBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
});
it('should return an allowance of 0 when no approval is set', async () => {
const [, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync(
makerAddress,
erc721AssetData,
);
expect(newAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
});
it('should return a balance of 1 when the tokenId is owned by target', async () => {
await web3Wrapper.awaitTransactionSuccessAsync(
await erc721Token.mint.sendTransactionAsync(makerAddress, tokenId),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const [newBalance] = await orderValidator.getBalanceAndAllowance.callAsync(
makerAddress,
erc721AssetData,
);
expect(newBalance).to.be.bignumber.equal(ERC721_BALANCE);
});
it('should return an allowance of 1 when ERC721Proxy is approved for all', async () => {
const isApproved = true;
await web3Wrapper.awaitTransactionSuccessAsync(
await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, {
from: makerAddress,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const [, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync(
makerAddress,
erc721AssetData,
);
expect(newAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
});
it('should return an allowance of 0 when ERC721Proxy is approved for specific tokenId', async () => {
await web3Wrapper.awaitTransactionSuccessAsync(
await erc721Token.mint.sendTransactionAsync(makerAddress, tokenId),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc721Token.approve.sendTransactionAsync(erc721Proxy.address, tokenId, {
from: makerAddress,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const [, newAllowance] = await orderValidator.getBalanceAndAllowance.callAsync(
makerAddress,
erc721AssetData,
);
expect(newAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
});
});
});
describe('getBalancesAndAllowances', () => {
it('should return the correct balances and allowances when all values are 0', async () => {
const [
[erc20Balance, erc721Balance],
[erc20Allowance, erc721Allowance],
] = await orderValidator.getBalancesAndAllowances.callAsync(makerAddress, [
erc20AssetData,
erc721AssetData,
]);
expect(erc20Balance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(erc721Balance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(erc20Allowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(erc721Allowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
});
it('should return the correct balances and allowances when balances and allowances are non-zero', async () => {
const balance = new BigNumber(123);
const allowance = new BigNumber(456);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc20Token.setBalance.sendTransactionAsync(makerAddress, balance),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, allowance, {
from: makerAddress,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc721Token.mint.sendTransactionAsync(makerAddress, tokenId),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const isApproved = true;
await web3Wrapper.awaitTransactionSuccessAsync(
await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, {
from: makerAddress,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const [
[erc20Balance, erc721Balance],
[erc20Allowance, erc721Allowance],
] = await orderValidator.getBalancesAndAllowances.callAsync(makerAddress, [
erc20AssetData,
erc721AssetData,
]);
expect(erc20Balance).to.be.bignumber.equal(balance);
expect(erc721Balance).to.be.bignumber.equal(ERC721_BALANCE);
expect(erc20Allowance).to.be.bignumber.equal(allowance);
expect(erc721Allowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
});
});
describe('getTraderInfo', () => {
beforeEach(async () => {
signedOrder = await orderFactory.newSignedOrderAsync();
});
it('should return the correct info when no balances or allowances are set', async () => {
const traderInfo = await orderValidator.getTraderInfo.callAsync(signedOrder, takerAddress);
expect(traderInfo.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
});
it('should return the correct info when balances and allowances are set', async () => {
const makerBalance = new BigNumber(123);
const makerAllowance = new BigNumber(456);
const makerZrxBalance = new BigNumber(789);
const takerZrxAllowance = new BigNumber(987);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc20Token.setBalance.sendTransactionAsync(makerAddress, makerBalance),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, makerAllowance, {
from: makerAddress,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await zrxToken.setBalance.sendTransactionAsync(makerAddress, makerZrxBalance),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await zrxToken.approve.sendTransactionAsync(erc20Proxy.address, takerZrxAllowance, {
from: takerAddress,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc721Token.mint.sendTransactionAsync(takerAddress, tokenId),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const isApproved = true;
await web3Wrapper.awaitTransactionSuccessAsync(
await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, {
from: takerAddress,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const traderInfo = await orderValidator.getTraderInfo.callAsync(signedOrder, takerAddress);
expect(traderInfo.makerBalance).to.be.bignumber.equal(makerBalance);
expect(traderInfo.makerAllowance).to.be.bignumber.equal(makerAllowance);
expect(traderInfo.takerBalance).to.be.bignumber.equal(ERC721_BALANCE);
expect(traderInfo.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
expect(traderInfo.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance);
expect(traderInfo.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance);
});
});
describe('getTradersInfo', () => {
beforeEach(async () => {
signedOrder = await orderFactory.newSignedOrderAsync();
signedOrder2 = await orderFactory.newSignedOrderAsync({
takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId2),
});
});
it('should return the correct info when no balances or allowances have been set', async () => {
const orders = [signedOrder, signedOrder2];
const takers = [takerAddress, takerAddress];
const [traderInfo1, traderInfo2] = await orderValidator.getTradersInfo.callAsync(orders, takers);
expect(traderInfo1.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo2.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo2.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo2.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo2.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo2.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo2.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo2.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo2.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
});
it('should return the correct info when balances and allowances are set', async () => {
const makerBalance = new BigNumber(123);
const makerAllowance = new BigNumber(456);
const makerZrxBalance = new BigNumber(789);
const takerZrxAllowance = new BigNumber(987);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc20Token.setBalance.sendTransactionAsync(makerAddress, makerBalance),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, makerAllowance, {
from: makerAddress,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await zrxToken.setBalance.sendTransactionAsync(makerAddress, makerZrxBalance),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await zrxToken.approve.sendTransactionAsync(erc20Proxy.address, takerZrxAllowance, {
from: takerAddress,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const isApproved = true;
await web3Wrapper.awaitTransactionSuccessAsync(
await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, {
from: takerAddress,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc721Token.mint.sendTransactionAsync(takerAddress, tokenId2),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const orders = [signedOrder, signedOrder2];
const takers = [takerAddress, takerAddress];
const [traderInfo1, traderInfo2] = await orderValidator.getTradersInfo.callAsync(orders, takers);
expect(traderInfo1.makerBalance).to.be.bignumber.equal(makerBalance);
expect(traderInfo1.makerAllowance).to.be.bignumber.equal(makerAllowance);
expect(traderInfo1.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
expect(traderInfo1.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance);
expect(traderInfo1.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance);
expect(traderInfo2.makerBalance).to.be.bignumber.equal(makerBalance);
expect(traderInfo2.makerAllowance).to.be.bignumber.equal(makerAllowance);
expect(traderInfo2.takerBalance).to.be.bignumber.equal(ERC721_BALANCE);
expect(traderInfo2.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
expect(traderInfo2.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance);
expect(traderInfo2.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo2.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo2.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance);
});
});
describe('getOrderAndTraderInfo', () => {
beforeEach(async () => {
signedOrder = await orderFactory.newSignedOrderAsync();
});
it('should return the correct info when no balances or allowances are set', async () => {
const [orderInfo, traderInfo] = await orderValidator.getOrderAndTraderInfo.callAsync(
signedOrder,
takerAddress,
);
const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FILLABLE);
expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
});
it('should return the correct info when balances and allowances are set', async () => {
const makerBalance = new BigNumber(123);
const makerAllowance = new BigNumber(456);
const makerZrxBalance = new BigNumber(789);
const takerZrxAllowance = new BigNumber(987);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc20Token.setBalance.sendTransactionAsync(makerAddress, makerBalance),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, makerAllowance, {
from: makerAddress,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await zrxToken.setBalance.sendTransactionAsync(makerAddress, makerZrxBalance),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await zrxToken.approve.sendTransactionAsync(erc20Proxy.address, takerZrxAllowance, {
from: takerAddress,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc721Token.mint.sendTransactionAsync(takerAddress, tokenId),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const isApproved = true;
await web3Wrapper.awaitTransactionSuccessAsync(
await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, {
from: takerAddress,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const [orderInfo, traderInfo] = await orderValidator.getOrderAndTraderInfo.callAsync(
signedOrder,
takerAddress,
);
const expectedOrderHash = orderHashUtils.getOrderHashHex(signedOrder);
expect(orderInfo.orderStatus).to.be.equal(OrderStatus.FILLABLE);
expect(orderInfo.orderHash).to.be.equal(expectedOrderHash);
expect(orderInfo.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo.makerBalance).to.be.bignumber.equal(makerBalance);
expect(traderInfo.makerAllowance).to.be.bignumber.equal(makerAllowance);
expect(traderInfo.takerBalance).to.be.bignumber.equal(ERC721_BALANCE);
expect(traderInfo.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
expect(traderInfo.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance);
expect(traderInfo.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance);
});
});
describe('getOrdersAndTradersInfo', () => {
beforeEach(async () => {
signedOrder = await orderFactory.newSignedOrderAsync();
signedOrder2 = await orderFactory.newSignedOrderAsync({
takerAssetData: assetDataUtils.encodeERC721AssetData(erc721Token.address, tokenId2),
});
});
it('should return the correct info when no balances or allowances have been set', async () => {
const orders = [signedOrder, signedOrder2];
const takers = [takerAddress, takerAddress];
const [
[orderInfo1, orderInfo2],
[traderInfo1, traderInfo2],
] = await orderValidator.getOrdersAndTradersInfo.callAsync(orders, takers);
const expectedOrderHash1 = orderHashUtils.getOrderHashHex(signedOrder);
const expectedOrderHash2 = orderHashUtils.getOrderHashHex(signedOrder2);
expect(orderInfo1.orderStatus).to.be.equal(OrderStatus.FILLABLE);
expect(orderInfo1.orderHash).to.be.equal(expectedOrderHash1);
expect(orderInfo1.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(orderInfo2.orderStatus).to.be.equal(OrderStatus.FILLABLE);
expect(orderInfo2.orderHash).to.be.equal(expectedOrderHash2);
expect(orderInfo2.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo2.makerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo2.makerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo2.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo2.takerAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo2.makerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo2.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo2.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo2.takerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
});
it('should return the correct info when balances and allowances are set', async () => {
const makerBalance = new BigNumber(123);
const makerAllowance = new BigNumber(456);
const makerZrxBalance = new BigNumber(789);
const takerZrxAllowance = new BigNumber(987);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc20Token.setBalance.sendTransactionAsync(makerAddress, makerBalance),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc20Token.approve.sendTransactionAsync(erc20Proxy.address, makerAllowance, {
from: makerAddress,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await zrxToken.setBalance.sendTransactionAsync(makerAddress, makerZrxBalance),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await zrxToken.approve.sendTransactionAsync(erc20Proxy.address, takerZrxAllowance, {
from: takerAddress,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const isApproved = true;
await web3Wrapper.awaitTransactionSuccessAsync(
await erc721Token.setApprovalForAll.sendTransactionAsync(erc721Proxy.address, isApproved, {
from: takerAddress,
}),
constants.AWAIT_TRANSACTION_MINED_MS,
);
await web3Wrapper.awaitTransactionSuccessAsync(
await erc721Token.mint.sendTransactionAsync(takerAddress, tokenId2),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const orders = [signedOrder, signedOrder2];
const takers = [takerAddress, takerAddress];
const [
[orderInfo1, orderInfo2],
[traderInfo1, traderInfo2],
] = await orderValidator.getOrdersAndTradersInfo.callAsync(orders, takers);
const expectedOrderHash1 = orderHashUtils.getOrderHashHex(signedOrder);
const expectedOrderHash2 = orderHashUtils.getOrderHashHex(signedOrder2);
expect(orderInfo1.orderStatus).to.be.equal(OrderStatus.FILLABLE);
expect(orderInfo1.orderHash).to.be.equal(expectedOrderHash1);
expect(orderInfo1.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(orderInfo2.orderStatus).to.be.equal(OrderStatus.FILLABLE);
expect(orderInfo2.orderHash).to.be.equal(expectedOrderHash2);
expect(orderInfo2.orderTakerAssetFilledAmount).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.makerBalance).to.be.bignumber.equal(makerBalance);
expect(traderInfo1.makerAllowance).to.be.bignumber.equal(makerAllowance);
expect(traderInfo1.takerBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
expect(traderInfo1.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance);
expect(traderInfo1.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo1.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance);
expect(traderInfo2.makerBalance).to.be.bignumber.equal(makerBalance);
expect(traderInfo2.makerAllowance).to.be.bignumber.equal(makerAllowance);
expect(traderInfo2.takerBalance).to.be.bignumber.equal(ERC721_BALANCE);
expect(traderInfo2.takerAllowance).to.be.bignumber.equal(ERC721_ALLOWANCE);
expect(traderInfo2.makerZrxBalance).to.be.bignumber.equal(makerZrxBalance);
expect(traderInfo2.makerZrxAllowance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo2.takerZrxBalance).to.be.bignumber.equal(constants.ZERO_AMOUNT);
expect(traderInfo2.takerZrxAllowance).to.be.bignumber.equal(takerZrxAllowance);
});
});
});
// tslint:disable:max-file-line-count

View File

@@ -1,17 +0,0 @@
import { env, EnvVars } from '@0x/dev-utils';
import { coverage, profiler, provider } from '@0x/contracts-test-utils';
before('start web3 provider', () => {
provider.start();
});
after('generate coverage report', async () => {
if (env.parseBoolean(EnvVars.SolidityCoverage)) {
const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
await coverageSubprovider.writeCoverageAsync();
}
if (env.parseBoolean(EnvVars.SolidityProfiler)) {
const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
await profilerSubprovider.writeProfilerOutputAsync();
}
provider.stop();
});

View File

@@ -1,283 +0,0 @@
import { artifacts as protocolArtifacts, ExchangeContract } from '@0x/contracts-protocol';
import {
FillResults,
formatters,
LogDecoder,
OrderInfo,
orderUtils,
TransactionFactory,
} from '@0x/contracts-test-utils';
import { artifacts as tokensArtifacts } from '@0x/contracts-tokens';
import { SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
import * as _ from 'lodash';
import { BalanceThresholdFilterContract } from '../../generated-wrappers/balance_threshold_filter';
import { artifacts } from '../../src/artifacts';
export class BalanceThresholdWrapper {
private readonly _balanceThresholdFilter: BalanceThresholdFilterContract;
private readonly _signerTransactionFactory: TransactionFactory;
private readonly _exchange: ExchangeContract;
private readonly _web3Wrapper: Web3Wrapper;
private readonly _logDecoder: LogDecoder;
constructor(
balanceThresholdFilter: BalanceThresholdFilterContract,
exchangeContract: ExchangeContract,
signerTransactionFactory: TransactionFactory,
provider: Provider,
) {
this._balanceThresholdFilter = balanceThresholdFilter;
this._exchange = exchangeContract;
this._signerTransactionFactory = signerTransactionFactory;
this._web3Wrapper = new Web3Wrapper(provider);
this._logDecoder = new LogDecoder(this._web3Wrapper, {
...artifacts,
...tokensArtifacts,
...protocolArtifacts,
});
}
public async fillOrderAsync(
signedOrder: SignedOrder,
from: string,
opts: { takerAssetFillAmount?: BigNumber } = {},
): Promise<TransactionReceiptWithDecodedLogs> {
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
const data = this._exchange.fillOrder.getABIEncodedTransactionData(
params.order,
params.takerAssetFillAmount,
params.signature,
);
const txReceipt = this._executeTransactionAsync(data, from);
return txReceipt;
}
public async fillOrKillOrderAsync(
signedOrder: SignedOrder,
from: string,
opts: { takerAssetFillAmount?: BigNumber } = {},
): Promise<TransactionReceiptWithDecodedLogs> {
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
const data = this._exchange.fillOrKillOrder.getABIEncodedTransactionData(
params.order,
params.takerAssetFillAmount,
params.signature,
);
const txReceipt = this._executeTransactionAsync(data, from);
return txReceipt;
}
public async fillOrderNoThrowAsync(
signedOrder: SignedOrder,
from: string,
opts: { takerAssetFillAmount?: BigNumber; gas?: number } = {},
): Promise<TransactionReceiptWithDecodedLogs> {
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
const data = this._exchange.fillOrderNoThrow.getABIEncodedTransactionData(
params.order,
params.takerAssetFillAmount,
params.signature,
);
const txReceipt = this._executeTransactionAsync(data, from, opts.gas);
return txReceipt;
}
public async batchFillOrdersAsync(
orders: SignedOrder[],
from: string,
opts: { takerAssetFillAmounts?: BigNumber[] } = {},
): Promise<TransactionReceiptWithDecodedLogs> {
const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
const data = this._exchange.batchFillOrders.getABIEncodedTransactionData(
params.orders,
params.takerAssetFillAmounts,
params.signatures,
);
const txReceipt = this._executeTransactionAsync(data, from);
return txReceipt;
}
public async batchFillOrKillOrdersAsync(
orders: SignedOrder[],
from: string,
opts: { takerAssetFillAmounts?: BigNumber[] } = {},
): Promise<TransactionReceiptWithDecodedLogs> {
const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
const data = this._exchange.batchFillOrKillOrders.getABIEncodedTransactionData(
params.orders,
params.takerAssetFillAmounts,
params.signatures,
);
const txReceipt = this._executeTransactionAsync(data, from);
return txReceipt;
}
public async batchFillOrdersNoThrowAsync(
orders: SignedOrder[],
from: string,
opts: { takerAssetFillAmounts?: BigNumber[]; gas?: number } = {},
): Promise<TransactionReceiptWithDecodedLogs> {
const params = formatters.createBatchFill(orders, opts.takerAssetFillAmounts);
const data = this._exchange.batchFillOrKillOrders.getABIEncodedTransactionData(
params.orders,
params.takerAssetFillAmounts,
params.signatures,
);
const txReceipt = this._executeTransactionAsync(data, from, opts.gas);
return txReceipt;
}
public async marketSellOrdersAsync(
orders: SignedOrder[],
from: string,
opts: { takerAssetFillAmount: BigNumber },
): Promise<TransactionReceiptWithDecodedLogs> {
const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount);
const data = this._exchange.marketSellOrders.getABIEncodedTransactionData(
params.orders,
params.takerAssetFillAmount,
params.signatures,
);
const txReceipt = this._executeTransactionAsync(data, from);
return txReceipt;
}
public async marketSellOrdersNoThrowAsync(
orders: SignedOrder[],
from: string,
opts: { takerAssetFillAmount: BigNumber; gas?: number },
): Promise<TransactionReceiptWithDecodedLogs> {
const params = formatters.createMarketSellOrders(orders, opts.takerAssetFillAmount);
const data = this._exchange.marketSellOrdersNoThrow.getABIEncodedTransactionData(
params.orders,
params.takerAssetFillAmount,
params.signatures,
);
const txReceipt = this._executeTransactionAsync(data, from, opts.gas);
return txReceipt;
}
public async marketBuyOrdersAsync(
orders: SignedOrder[],
from: string,
opts: { makerAssetFillAmount: BigNumber },
): Promise<TransactionReceiptWithDecodedLogs> {
const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount);
const data = this._exchange.marketBuyOrders.getABIEncodedTransactionData(
params.orders,
params.makerAssetFillAmount,
params.signatures,
);
const txReceipt = this._executeTransactionAsync(data, from);
return txReceipt;
}
public async marketBuyOrdersNoThrowAsync(
orders: SignedOrder[],
from: string,
opts: { makerAssetFillAmount: BigNumber; gas?: number },
): Promise<TransactionReceiptWithDecodedLogs> {
const params = formatters.createMarketBuyOrders(orders, opts.makerAssetFillAmount);
const data = this._exchange.marketBuyOrdersNoThrow.getABIEncodedTransactionData(
params.orders,
params.makerAssetFillAmount,
params.signatures,
);
const txReceipt = this._executeTransactionAsync(data, from, opts.gas);
return txReceipt;
}
public async cancelOrderAsync(signedOrder: SignedOrder, from: string): Promise<TransactionReceiptWithDecodedLogs> {
const params = orderUtils.createCancel(signedOrder);
const data = this._exchange.cancelOrder.getABIEncodedTransactionData(params.order);
const txReceipt = this._executeTransactionAsync(data, from);
return txReceipt;
}
public async batchCancelOrdersAsync(
orders: SignedOrder[],
from: string,
): Promise<TransactionReceiptWithDecodedLogs> {
const params = formatters.createBatchCancel(orders);
const data = this._exchange.batchCancelOrders.getABIEncodedTransactionData(params.orders);
const txReceipt = this._executeTransactionAsync(data, from);
return txReceipt;
}
public async cancelOrdersUpToAsync(salt: BigNumber, from: string): Promise<TransactionReceiptWithDecodedLogs> {
const data = this._exchange.cancelOrdersUpTo.getABIEncodedTransactionData(salt);
const txReceipt = this._executeTransactionAsync(data, from);
return txReceipt;
}
public async getTakerAssetFilledAmountAsync(orderHashHex: string): Promise<BigNumber> {
const filledAmount = await this._exchange.filled.callAsync(orderHashHex);
return filledAmount;
}
public async isCancelledAsync(orderHashHex: string): Promise<boolean> {
const isCancelled = await this._exchange.cancelled.callAsync(orderHashHex);
return isCancelled;
}
public async getOrderEpochAsync(makerAddress: string, senderAddress: string): Promise<BigNumber> {
const orderEpoch = await this._exchange.orderEpoch.callAsync(makerAddress, senderAddress);
return orderEpoch;
}
public async getOrderInfoAsync(signedOrder: SignedOrder): Promise<OrderInfo> {
const orderInfo = await this._exchange.getOrderInfo.callAsync(signedOrder);
return orderInfo;
}
public async getOrdersInfoAsync(signedOrders: SignedOrder[]): Promise<OrderInfo[]> {
const ordersInfo = (await this._exchange.getOrdersInfo.callAsync(signedOrders)) as OrderInfo[];
return ordersInfo;
}
public async matchOrdersAsync(
signedOrderLeft: SignedOrder,
signedOrderRight: SignedOrder,
from: string,
): Promise<TransactionReceiptWithDecodedLogs> {
const params = orderUtils.createMatchOrders(signedOrderLeft, signedOrderRight);
const data = await this._exchange.matchOrders.getABIEncodedTransactionData(
params.left,
params.right,
params.leftSignature,
params.rightSignature,
);
const txReceipt = this._executeTransactionAsync(data, from);
return txReceipt;
}
public async getFillOrderResultsAsync(
signedOrder: SignedOrder,
from: string,
opts: { takerAssetFillAmount?: BigNumber } = {},
): Promise<FillResults> {
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
const fillResults = await this._exchange.fillOrder.callAsync(
params.order,
params.takerAssetFillAmount,
params.signature,
{ from },
);
return fillResults;
}
public abiEncodeFillOrder(signedOrder: SignedOrder, opts: { takerAssetFillAmount?: BigNumber } = {}): string {
const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount);
const data = this._exchange.fillOrder.getABIEncodedTransactionData(
params.order,
params.takerAssetFillAmount,
params.signature,
);
return data;
}
public getBalanceThresholdAddress(): string {
return this._balanceThresholdFilter.address;
}
public getExchangeAddress(): string {
return this._exchange.address;
}
private async _executeTransactionAsync(
abiEncodedExchangeTxData: string,
from: string,
gas?: number,
): Promise<TransactionReceiptWithDecodedLogs> {
const signedExchangeTx = this._signerTransactionFactory.newSignedTransaction(abiEncodedExchangeTxData);
const txOpts = _.isUndefined(gas) ? { from } : { from, gas };
const txHash = await this._balanceThresholdFilter.executeTransaction.sendTransactionAsync(
signedExchangeTx.salt,
signedExchangeTx.signerAddress,
signedExchangeTx.data,
signedExchangeTx.signature,
txOpts,
);
const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
return txReceipt;
}
}

View File

@@ -1,62 +0,0 @@
import { artifacts as protocolArtifacts } from '@0x/contracts-protocol';
import { LogDecoder } from '@0x/contracts-test-utils';
import { artifacts as tokensArtifacts } from '@0x/contracts-tokens';
import { DutchAuctionDetails, SignedOrder } from '@0x/types';
import { Web3Wrapper } from '@0x/web3-wrapper';
import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
import * as _ from 'lodash';
import { DutchAuctionContract } from '../../generated-wrappers/dutch_auction';
import { artifacts } from '../../src/artifacts';
export class DutchAuctionTestWrapper {
private readonly _dutchAuctionContract: DutchAuctionContract;
private readonly _web3Wrapper: Web3Wrapper;
private readonly _logDecoder: LogDecoder;
constructor(contractInstance: DutchAuctionContract, provider: Provider) {
this._dutchAuctionContract = contractInstance;
this._web3Wrapper = new Web3Wrapper(provider);
this._logDecoder = new LogDecoder(this._web3Wrapper, {
...artifacts,
...tokensArtifacts,
...protocolArtifacts,
});
}
/**
* 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 from Address the transaction is being sent from.
* @return Transaction receipt with decoded logs.
*/
public async matchOrdersAsync(
buyOrder: SignedOrder,
sellOrder: SignedOrder,
from: string,
): Promise<TransactionReceiptWithDecodedLogs> {
const txHash = await this._dutchAuctionContract.matchOrders.sendTransactionAsync(
buyOrder,
sellOrder,
buyOrder.signature,
sellOrder.signature,
{
from,
},
);
const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
return tx;
}
/**
* Calculates 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<DutchAuctionDetails> {
const auctionDetails = await this._dutchAuctionContract.getAuctionDetails.callAsync(sellOrder);
return auctionDetails;
}
}

View File

@@ -1,17 +0,0 @@
{
"extends": "../../tsconfig",
"compilerOptions": {
"outDir": "lib",
"rootDir": ".",
"resolveJsonModule": true
},
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
"files": [
"./generated-artifacts/BalanceThresholdFilter.json",
"./generated-artifacts/DutchAuction.json",
"./generated-artifacts/Forwarder.json",
"./generated-artifacts/OrderMatcher.json",
"./generated-artifacts/OrderValidator.json"
],
"exclude": ["./deploy/solc/solc_bin"]
}

View File

@@ -1,6 +0,0 @@
{
"extends": ["@0x/tslint-config"],
"rules": {
"custom-no-magic-numbers": false
}
}

View File

@@ -1,29 +0,0 @@
[
{
"timestamp": 1547225310,
"version": "1.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1547040760,
"version": "1.0.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1544741676,
"version": "1.0.2",
"changes": [
{
"note": "Dependencies updated"
}
]
}
]

View File

@@ -1,18 +0,0 @@
<!--
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
Edit the package's CHANGELOG.json file only.
-->
CHANGELOG
## v1.0.4 - _January 11, 2019_
* Dependencies updated
## v1.0.3 - _January 9, 2019_
* Dependencies updated
## v1.0.2 - _December 13, 2018_
* Dependencies updated

View File

@@ -1,72 +0,0 @@
## Contract interfaces
Smart contract interfaces of the 0x protocol.
## Usage
Contracts that make up and interact with version 2.0.0 of the protocol can be found in the [contracts](./contracts) directory. The contents of this directory are broken down into the following subdirectories:
- [protocol](./contracts/protocol)
- This directory contains the contract interfaces that make up version 2.0.0. A full specification can be found [here](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md).
## Bug bounty
A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0xproject.com/wiki#Bug-Bounty).
## 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.
For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
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/contracts-interfaces yarn build
```
Or continuously rebuild on change:
```bash
PKG=@0x/contracts-interfaces yarn watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash
yarn lint
```
### Run Tests
```bash
yarn test
```
#### Testing options
Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md).

View File

@@ -1,35 +0,0 @@
{
"artifactsDir": "./generated-artifacts",
"contractsDir": "./contracts",
"compilerSettings": {
"optimizer": {
"enabled": true,
"runs": 1000000
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode.object",
"evm.bytecode.sourceMap",
"evm.deployedBytecode.object",
"evm.deployedBytecode.sourceMap"
]
}
}
},
"contracts": [
"IAssetData",
"IAssetProxy",
"IAuthorizable",
"IAssetProxyDispatcher",
"IExchange",
"IExchangeCore",
"IMatchOrders",
"ISignatureValidator",
"ITransactions",
"IValidator",
"IWallet",
"IWrapperFunctions"
]
}

View File

@@ -1,57 +0,0 @@
{
"name": "@0x/contracts-interfaces",
"version": "1.0.4",
"engines": {
"node": ">=6.12"
},
"description": "Smart contract interfaces of 0x protocol",
"main": "lib/src/index.js",
"scripts": {
"build": "yarn pre_build && tsc -b",
"build:ci": "yarn build",
"pre_build": "run-s compile generate_contract_wrappers",
"compile": "sol-compiler",
"watch": "sol-compiler -w",
"clean": "shx rm -rf lib generated-artifacts 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 generated-wrappers --backend ethers",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
},
"config": {
"abis": "generated-artifacts/@(IAssetData|IAssetProxy|IAuthorizable|IAssetProxyDispatcher|IExchange|IExchangeCore|IMatchOrders|ISignatureValidator|ITransactions|IValidator|IWallet|IWrapperFunctions).json"
},
"repository": {
"type": "git",
"url": "https://github.com/0xProject/0x-monorepo.git"
},
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/0xProject/0x-monorepo/issues"
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/interfaces/README.md",
"devDependencies": {
"@0x/abi-gen": "^1.0.21",
"@0x/sol-compiler": "^2.0.1",
"@0x/tslint-config": "^2.0.1",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"solhint": "^1.4.1",
"tslint": "5.11.0",
"typescript": "3.0.1",
"yargs": "^10.0.3"
},
"dependencies": {
"@0x/base-contract": "^3.0.12",
"@0x/contracts-libs": "^1.0.4",
"@0x/contracts-utils": "^1.0.4",
"@0x/types": "^1.5.1",
"@0x/typescript-typings": "^3.0.7",
"@0x/utils": "^3.0.0",
"@0x/web3-wrapper": "^3.2.3",
"ethereum-types": "^1.1.5",
"lodash": "^4.17.5"
},
"publishConfig": {
"access": "public"
}
}

View File

@@ -1,29 +0,0 @@
import { ContractArtifact } from 'ethereum-types';
import * as IAssetData from '../../generated-artifacts/IAssetData.json';
import * as IAssetProxy from '../../generated-artifacts/IAssetProxy.json';
import * as IAssetProxyDispatcher from '../../generated-artifacts/IAssetProxyDispatcher.json';
import * as IAuthorizable from '../../generated-artifacts/IAuthorizable.json';
import * as IExchange from '../../generated-artifacts/IExchange.json';
import * as IExchangeCore from '../../generated-artifacts/IExchangeCore.json';
import * as IMatchOrders from '../../generated-artifacts/IMatchOrders.json';
import * as ISignatureValidator from '../../generated-artifacts/ISignatureValidator.json';
import * as ITransactions from '../../generated-artifacts/ITransactions.json';
import * as IValidator from '../../generated-artifacts/IValidator.json';
import * as IWallet from '../../generated-artifacts/IWallet.json';
import * as IWrapperFunctions from '../../generated-artifacts/IWrapperFunctions.json';
export const artifacts = {
IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
IAuthorizable: IAuthorizable as ContractArtifact,
IExchange: IExchange as ContractArtifact,
IExchangeCore: IExchangeCore as ContractArtifact,
IMatchOrders: IMatchOrders as ContractArtifact,
ISignatureValidator: ISignatureValidator as ContractArtifact,
ITransactions: ITransactions as ContractArtifact,
IWrapperFunctions: IWrapperFunctions as ContractArtifact,
IAssetData: IAssetData as ContractArtifact,
IAssetProxy: IAssetProxy as ContractArtifact,
IValidator: IValidator as ContractArtifact,
IWallet: IWallet as ContractArtifact,
};

View File

@@ -1,2 +0,0 @@
export * from './artifacts';
export * from './wrappers';

View File

@@ -1,12 +0,0 @@
export * from '../../generated-wrappers/i_asset_data';
export * from '../../generated-wrappers/i_asset_proxy';
export * from '../../generated-wrappers/i_asset_proxy_dispatcher';
export * from '../../generated-wrappers/i_exchange';
export * from '../../generated-wrappers/i_exchange_core';
export * from '../../generated-wrappers/i_match_orders';
export * from '../../generated-wrappers/i_signature_validator';
export * from '../../generated-wrappers/i_transactions';
export * from '../../generated-wrappers/i_authorizable';
export * from '../../generated-wrappers/i_wrapper_functions';
export * from '../../generated-wrappers/i_validator';
export * from '../../generated-wrappers/i_wallet';

View File

@@ -1,24 +0,0 @@
{
"extends": "../../tsconfig",
"compilerOptions": {
"outDir": "lib",
"rootDir": ".",
"resolveJsonModule": true
},
"include": ["./src/**/*", "./generated-wrappers/**/*"],
"files": [
"./generated-artifacts/IAssetData.json",
"./generated-artifacts/IAssetProxy.json",
"./generated-artifacts/IAuthorizable.json",
"./generated-artifacts/IAssetProxyDispatcher.json",
"./generated-artifacts/IExchange.json",
"./generated-artifacts/IExchangeCore.json",
"./generated-artifacts/IMatchOrders.json",
"./generated-artifacts/ISignatureValidator.json",
"./generated-artifacts/ITransactions.json",
"./generated-artifacts/IValidator.json",
"./generated-artifacts/IWallet.json",
"./generated-artifacts/IWrapperFunctions.json"
],
"exclude": ["./deploy/solc/solc_bin"]
}

View File

@@ -1,6 +0,0 @@
{
"extends": ["@0x/tslint-config"],
"rules": {
"custom-no-magic-numbers": false
}
}

View File

@@ -1,29 +0,0 @@
[
{
"timestamp": 1547225310,
"version": "1.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1547040760,
"version": "1.0.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1544741676,
"version": "1.0.2",
"changes": [
{
"note": "Dependencies updated"
}
]
}
]

View File

@@ -1,18 +0,0 @@
<!--
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
Edit the package's CHANGELOG.json file only.
-->
CHANGELOG
## v1.0.4 - _January 11, 2019_
* Dependencies updated
## v1.0.3 - _January 9, 2019_
* Dependencies updated
## v1.0.2 - _December 13, 2018_
* Dependencies updated

View File

@@ -1,70 +0,0 @@
## Contracts libs
Smart contracts libs used in the 0x protocol.
## Usage
Contracts can be found in the [contracts](./contracts) directory. The contents of this directory are broken down into the following subdirectories:
- [libs](./contracts/protocol)
- This directory contains the libs.
- [test](./contracts/test)
- This directory contains mocks and other contracts that are used solely for testing contracts within the other directories.
## 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.
For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
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/contracts-libs yarn build
```
Or continuously rebuild on change:
```bash
PKG=@0x/contracts-libs yarn watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash
yarn lint
```
### Run Tests
```bash
yarn test
```
#### Testing options
Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md).

View File

@@ -1,31 +0,0 @@
{
"artifactsDir": "./generated-artifacts",
"contractsDir": "./contracts",
"compilerSettings": {
"optimizer": {
"enabled": true,
"runs": 1000000
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode.object",
"evm.bytecode.sourceMap",
"evm.deployedBytecode.object",
"evm.deployedBytecode.sourceMap"
]
}
}
},
"contracts": [
"TestLibs",
"LibOrder",
"LibMath",
"LibFillResults",
"LibAbiEncoder",
"LibEIP712",
"LibAssetProxyErrors",
"LibConstants"
]
}

View File

@@ -1,84 +0,0 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.4.24;
import "@0x/contracts-utils/contracts/utils/LibBytes/LibBytes.sol";
library LibAddressArray {
/// @dev Append a new address to an array of addresses.
/// The `addressArray` may need to be reallocated to make space
/// for the new address. Because of this we return the resulting
/// memory location of `addressArray`.
/// @param addressToAppend Address to append.
/// @return Array of addresses: [... addressArray, addressToAppend]
function append(address[] memory addressArray, address addressToAppend)
internal pure
returns (address[])
{
// Get stats on address array and free memory
uint256 freeMemPtr = 0;
uint256 addressArrayBeginPtr = 0;
uint256 addressArrayEndPtr = 0;
uint256 addressArrayLength = addressArray.length;
uint256 addressArrayMemSizeInBytes = 32 + (32 * addressArrayLength);
assembly {
freeMemPtr := mload(0x40)
addressArrayBeginPtr := addressArray
addressArrayEndPtr := add(addressArray, addressArrayMemSizeInBytes)
}
// Cases for `freeMemPtr`:
// `freeMemPtr` == `addressArrayEndPtr`: Nothing occupies memory after `addressArray`
// `freeMemPtr` > `addressArrayEndPtr`: Some value occupies memory after `addressArray`
// `freeMemPtr` < `addressArrayEndPtr`: Memory has not been managed properly.
require(
freeMemPtr >= addressArrayEndPtr,
"INVALID_FREE_MEMORY_PTR"
);
// If free memory begins at the end of `addressArray`
// then we can append `addressToAppend` directly.
// Otherwise, we must copy the array to free memory
// before appending new values to it.
if (freeMemPtr > addressArrayEndPtr) {
LibBytes.memCopy(freeMemPtr, addressArrayBeginPtr, addressArrayMemSizeInBytes);
assembly {
addressArray := freeMemPtr
addressArrayBeginPtr := addressArray
}
}
// Append `addressToAppend`
addressArrayLength += 1;
addressArrayMemSizeInBytes += 32;
addressArrayEndPtr = addressArrayBeginPtr + addressArrayMemSizeInBytes;
freeMemPtr = addressArrayEndPtr;
assembly {
// Store new array length
mstore(addressArray, addressArrayLength)
// Update `freeMemPtr`
mstore(0x40, freeMemPtr)
}
addressArray[addressArrayLength - 1] = addressToAppend;
return addressArray;
}
}

View File

@@ -1,152 +0,0 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.4.24;
contract LibExchangeSelectors {
// solhint-disable max-line-length
// allowedValidators
bytes4 constant public ALLOWED_VALIDATORS_SELECTOR = 0x7b8e3514;
bytes4 constant public ALLOWED_VALIDATORS_SELECTOR_GENERATOR = bytes4(keccak256("allowedValidators(address,address)"));
// assetProxies
bytes4 constant public ASSET_PROXIES_SELECTOR = 0x3fd3c997;
bytes4 constant public ASSET_PROXIES_SELECTOR_GENERATOR = bytes4(keccak256("assetProxies(bytes4)"));
// batchCancelOrders
bytes4 constant public BATCH_CANCEL_ORDERS_SELECTOR = 0x4ac14782;
bytes4 constant public BATCH_CANCEL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("batchCancelOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])"));
// batchFillOrKillOrders
bytes4 constant public BATCH_FILL_OR_KILL_ORDERS_SELECTOR = 0x4d0ae546;
bytes4 constant public BATCH_FILL_OR_KILL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("batchFillOrKillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])"));
// batchFillOrders
bytes4 constant public BATCH_FILL_ORDERS_SELECTOR = 0x297bb70b;
bytes4 constant public BATCH_FILL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("batchFillOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])"));
// batchFillOrdersNoThrow
bytes4 constant public BATCH_FILL_ORDERS_NO_THROW_SELECTOR = 0x50dde190;
bytes4 constant public BATCH_FILL_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256("batchFillOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256[],bytes[])"));
// cancelOrder
bytes4 constant public CANCEL_ORDER_SELECTOR = 0xd46b02c3;
bytes4 constant public CANCEL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256("cancelOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))"));
// cancelOrdersUpTo
bytes4 constant public CANCEL_ORDERS_UP_TO_SELECTOR = 0x4f9559b1;
bytes4 constant public CANCEL_ORDERS_UP_TO_SELECTOR_GENERATOR = bytes4(keccak256("cancelOrdersUpTo(uint256)"));
// cancelled
bytes4 constant public CANCELLED_SELECTOR = 0x2ac12622;
bytes4 constant public CANCELLED_SELECTOR_GENERATOR = bytes4(keccak256("cancelled(bytes32)"));
// currentContextAddress
bytes4 constant public CURRENT_CONTEXT_ADDRESS_SELECTOR = 0xeea086ba;
bytes4 constant public CURRENT_CONTEXT_ADDRESS_SELECTOR_GENERATOR = bytes4(keccak256("currentContextAddress()"));
// executeTransaction
bytes4 constant public EXECUTE_TRANSACTION_SELECTOR = 0xbfc8bfce;
bytes4 constant public EXECUTE_TRANSACTION_SELECTOR_GENERATOR = bytes4(keccak256("executeTransaction(uint256,address,bytes,bytes)"));
// fillOrKillOrder
bytes4 constant public FILL_OR_KILL_ORDER_SELECTOR = 0x64a3bc15;
bytes4 constant public FILL_OR_KILL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256("fillOrKillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)"));
// fillOrder
bytes4 constant public FILL_ORDER_SELECTOR = 0xb4be83d5;
bytes4 constant public FILL_ORDER_SELECTOR_GENERATOR = bytes4(keccak256("fillOrder((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)"));
// fillOrderNoThrow
bytes4 constant public FILL_ORDER_NO_THROW_SELECTOR = 0x3e228bae;
bytes4 constant public FILL_ORDER_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256("fillOrderNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes),uint256,bytes)"));
// filled
bytes4 constant public FILLED_SELECTOR = 0x288cdc91;
bytes4 constant public FILLED_SELECTOR_GENERATOR = bytes4(keccak256("filled(bytes32)"));
// getAssetProxy
bytes4 constant public GET_ASSET_PROXY_SELECTOR = 0x60704108;
bytes4 constant public GET_ASSET_PROXY_SELECTOR_GENERATOR = bytes4(keccak256("getAssetProxy(bytes4)"));
// getOrderInfo
bytes4 constant public GET_ORDER_INFO_SELECTOR = 0xc75e0a81;
bytes4 constant public GET_ORDER_INFO_SELECTOR_GENERATOR = bytes4(keccak256("getOrderInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes))"));
// getOrdersInfo
bytes4 constant public GET_ORDERS_INFO_SELECTOR = 0x7e9d74dc;
bytes4 constant public GET_ORDERS_INFO_SELECTOR_GENERATOR = bytes4(keccak256("getOrdersInfo((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[])"));
// isValidSignature
bytes4 constant public IS_VALID_SIGNATURE_SELECTOR = 0x93634702;
bytes4 constant public IS_VALID_SIGNATURE_SELECTOR_GENERATOR = bytes4(keccak256("isValidSignature(bytes32,address,bytes)"));
// marketBuyOrders
bytes4 constant public MARKET_BUY_ORDERS_SELECTOR = 0xe5fa431b;
bytes4 constant public MARKET_BUY_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("marketBuyOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])"));
// marketBuyOrdersNoThrow
bytes4 constant public MARKET_BUY_ORDERS_NO_THROW_SELECTOR = 0xa3e20380;
bytes4 constant public MARKET_BUY_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256("marketBuyOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])"));
// marketSellOrders
bytes4 constant public MARKET_SELL_ORDERS_SELECTOR = 0x7e1d9808;
bytes4 constant public MARKET_SELL_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("marketSellOrders((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])"));
// marketSellOrdersNoThrow
bytes4 constant public MARKET_SELL_ORDERS_NO_THROW_SELECTOR = 0xdd1c7d18;
bytes4 constant public MARKET_SELL_ORDERS_NO_THROW_SELECTOR_GENERATOR = bytes4(keccak256("marketSellOrdersNoThrow((address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,bytes,bytes)[],uint256,bytes[])"));
// matchOrders
bytes4 constant public MATCH_ORDERS_SELECTOR = 0x3c28d861;
bytes4 constant public MATCH_ORDERS_SELECTOR_GENERATOR = bytes4(keccak256("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)"));
// orderEpoch
bytes4 constant public ORDER_EPOCH_SELECTOR = 0xd9bfa73e;
bytes4 constant public ORDER_EPOCH_SELECTOR_GENERATOR = bytes4(keccak256("orderEpoch(address,address)"));
// owner
bytes4 constant public OWNER_SELECTOR = 0x8da5cb5b;
bytes4 constant public OWNER_SELECTOR_GENERATOR = bytes4(keccak256("owner()"));
// preSign
bytes4 constant public PRE_SIGN_SELECTOR = 0x3683ef8e;
bytes4 constant public PRE_SIGN_SELECTOR_GENERATOR = bytes4(keccak256("preSign(bytes32,address,bytes)"));
// preSigned
bytes4 constant public PRE_SIGNED_SELECTOR = 0x82c174d0;
bytes4 constant public PRE_SIGNED_SELECTOR_GENERATOR = bytes4(keccak256("preSigned(bytes32,address)"));
// registerAssetProxy
bytes4 constant public REGISTER_ASSET_PROXY_SELECTOR = 0xc585bb93;
bytes4 constant public REGISTER_ASSET_PROXY_SELECTOR_GENERATOR = bytes4(keccak256("registerAssetProxy(address)"));
// setSignatureValidatorApproval
bytes4 constant public SET_SIGNATURE_VALIDATOR_APPROVAL_SELECTOR = 0x77fcce68;
bytes4 constant public SET_SIGNATURE_VALIDATOR_APPROVAL_SELECTOR_GENERATOR = bytes4(keccak256("setSignatureValidatorApproval(address,bool)"));
// transactions
bytes4 constant public TRANSACTIONS_SELECTOR = 0x642f2eaf;
bytes4 constant public TRANSACTIONS_SELECTOR_GENERATOR = bytes4(keccak256("transactions(bytes32)"));
// transferOwnership
bytes4 constant public TRANSFER_OWNERSHIP_SELECTOR = 0xf2fde38b;
bytes4 constant public TRANSFER_OWNERSHIP_SELECTOR_GENERATOR = bytes4(keccak256("transferOwnership(address)"));
}

View File

@@ -1,253 +0,0 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.4.24;
import "@0x/contracts-utils/contracts/utils/SafeMath/SafeMath.sol";
contract LibMath is
SafeMath
{
/// @dev Calculates partial value given a numerator and denominator rounded down.
/// Reverts if rounding error is >= 0.1%
/// @param numerator Numerator.
/// @param denominator Denominator.
/// @param target Value to calculate partial of.
/// @return Partial value of target rounded down.
function safeGetPartialAmountFloor(
uint256 numerator,
uint256 denominator,
uint256 target
)
internal
pure
returns (uint256 partialAmount)
{
require(
denominator > 0,
"DIVISION_BY_ZERO"
);
require(
!isRoundingErrorFloor(
numerator,
denominator,
target
),
"ROUNDING_ERROR"
);
partialAmount = safeDiv(
safeMul(numerator, target),
denominator
);
return partialAmount;
}
/// @dev Calculates partial value given a numerator and denominator rounded down.
/// Reverts if rounding error is >= 0.1%
/// @param numerator Numerator.
/// @param denominator Denominator.
/// @param target Value to calculate partial of.
/// @return Partial value of target rounded up.
function safeGetPartialAmountCeil(
uint256 numerator,
uint256 denominator,
uint256 target
)
internal
pure
returns (uint256 partialAmount)
{
require(
denominator > 0,
"DIVISION_BY_ZERO"
);
require(
!isRoundingErrorCeil(
numerator,
denominator,
target
),
"ROUNDING_ERROR"
);
// safeDiv computes `floor(a / b)`. We use the identity (a, b integer):
// ceil(a / b) = floor((a + b - 1) / b)
// To implement `ceil(a / b)` using safeDiv.
partialAmount = safeDiv(
safeAdd(
safeMul(numerator, target),
safeSub(denominator, 1)
),
denominator
);
return partialAmount;
}
/// @dev Calculates partial value given a numerator and denominator rounded down.
/// @param numerator Numerator.
/// @param denominator Denominator.
/// @param target Value to calculate partial of.
/// @return Partial value of target rounded down.
function getPartialAmountFloor(
uint256 numerator,
uint256 denominator,
uint256 target
)
internal
pure
returns (uint256 partialAmount)
{
require(
denominator > 0,
"DIVISION_BY_ZERO"
);
partialAmount = safeDiv(
safeMul(numerator, target),
denominator
);
return partialAmount;
}
/// @dev Calculates partial value given a numerator and denominator rounded down.
/// @param numerator Numerator.
/// @param denominator Denominator.
/// @param target Value to calculate partial of.
/// @return Partial value of target rounded up.
function getPartialAmountCeil(
uint256 numerator,
uint256 denominator,
uint256 target
)
internal
pure
returns (uint256 partialAmount)
{
require(
denominator > 0,
"DIVISION_BY_ZERO"
);
// safeDiv computes `floor(a / b)`. We use the identity (a, b integer):
// ceil(a / b) = floor((a + b - 1) / b)
// To implement `ceil(a / b)` using safeDiv.
partialAmount = safeDiv(
safeAdd(
safeMul(numerator, target),
safeSub(denominator, 1)
),
denominator
);
return partialAmount;
}
/// @dev Checks if rounding error >= 0.1% when rounding down.
/// @param numerator Numerator.
/// @param denominator Denominator.
/// @param target Value to multiply with numerator/denominator.
/// @return Rounding error is present.
function isRoundingErrorFloor(
uint256 numerator,
uint256 denominator,
uint256 target
)
internal
pure
returns (bool isError)
{
require(
denominator > 0,
"DIVISION_BY_ZERO"
);
// The absolute rounding error is the difference between the rounded
// value and the ideal value. The relative rounding error is the
// absolute rounding error divided by the absolute value of the
// ideal value. This is undefined when the ideal value is zero.
//
// The ideal value is `numerator * target / denominator`.
// Let's call `numerator * target % denominator` the remainder.
// The absolute error is `remainder / denominator`.
//
// When the ideal value is zero, we require the absolute error to
// be zero. Fortunately, this is always the case. The ideal value is
// zero iff `numerator == 0` and/or `target == 0`. In this case the
// remainder and absolute error are also zero.
if (target == 0 || numerator == 0) {
return false;
}
// Otherwise, we want the relative rounding error to be strictly
// less than 0.1%.
// The relative error is `remainder / (numerator * target)`.
// We want the relative error less than 1 / 1000:
// remainder / (numerator * denominator) < 1 / 1000
// or equivalently:
// 1000 * remainder < numerator * target
// so we have a rounding error iff:
// 1000 * remainder >= numerator * target
uint256 remainder = mulmod(
target,
numerator,
denominator
);
isError = safeMul(1000, remainder) >= safeMul(numerator, target);
return isError;
}
/// @dev Checks if rounding error >= 0.1% when rounding up.
/// @param numerator Numerator.
/// @param denominator Denominator.
/// @param target Value to multiply with numerator/denominator.
/// @return Rounding error is present.
function isRoundingErrorCeil(
uint256 numerator,
uint256 denominator,
uint256 target
)
internal
pure
returns (bool isError)
{
require(
denominator > 0,
"DIVISION_BY_ZERO"
);
// See the comments in `isRoundingError`.
if (target == 0 || numerator == 0) {
// When either is zero, the ideal value and rounded value are zero
// and there is no rounding error. (Although the relative error
// is undefined.)
return false;
}
// Compute remainder as before
uint256 remainder = mulmod(
target,
numerator,
denominator
);
remainder = safeSub(denominator, remainder) % denominator;
isError = safeMul(1000, remainder) >= safeMul(numerator, target);
return isError;
}
}

View File

@@ -1,89 +0,0 @@
{
"name": "@0x/contracts-libs",
"version": "1.0.4",
"engines": {
"node": ">=6.12"
},
"description": "Smart contract libs of 0x protocol",
"main": "lib/src/index.js",
"directories": {
"test": "test"
},
"scripts": {
"build": "yarn pre_build && tsc -b",
"build:ci": "yarn build",
"pre_build": "run-s compile generate_contract_wrappers",
"test": "yarn run_mocha",
"rebuild_and_test": "run-s build test",
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
"test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
"compile": "sol-compiler",
"watch": "sol-compiler -w",
"clean": "shx rm -rf lib generated-artifacts 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 generated-wrappers --backend ethers",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
"coverage:report:text": "istanbul report text",
"coverage:report:html": "istanbul report html && open coverage/index.html",
"profiler:report:html": "istanbul report html && open coverage/index.html",
"coverage:report:lcov": "istanbul report lcov",
"test:circleci": "yarn test",
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
},
"config": {
"abis": "generated-artifacts/@(LibMath|LibOrder|LibFillResults|LibAbiEncoder|TestLibs|LibEIP712).json"
},
"repository": {
"type": "git",
"url": "https://github.com/0xProject/0x-monorepo.git"
},
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/0xProject/0x-monorepo/issues"
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/libs/README.md",
"devDependencies": {
"@0x/abi-gen": "^1.0.21",
"@0x/contracts-test-utils": "^1.0.4",
"@0x/dev-utils": "^1.0.23",
"@0x/sol-compiler": "^2.0.1",
"@0x/subproviders": "^2.1.10",
"@0x/tslint-config": "^2.0.1",
"@types/bn.js": "^4.11.0",
"@types/lodash": "4.14.104",
"@types/node": "*",
"@types/yargs": "^10.0.0",
"chai": "^4.0.1",
"chai-as-promised": "^7.1.0",
"chai-bignumber": "^2.0.1",
"dirty-chai": "^2.0.1",
"ethereumjs-abi": "0.6.5",
"make-promises-safe": "^1.1.0",
"mocha": "^4.1.0",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"solhint": "^1.4.1",
"tslint": "5.11.0",
"typescript": "3.0.1",
"yargs": "^10.0.3"
},
"dependencies": {
"@0x/base-contract": "^3.0.12",
"@0x/contracts-multisig": "^1.0.4",
"@0x/contracts-utils": "^1.0.4",
"@0x/order-utils": "^3.1.1",
"@0x/types": "^1.5.1",
"@0x/typescript-typings": "^3.0.7",
"@0x/utils": "^3.0.0",
"@0x/web3-wrapper": "^3.2.3",
"@types/js-combinatorics": "^0.5.29",
"bn.js": "^4.11.8",
"ethereum-types": "^1.1.5",
"ethereumjs-util": "^5.1.1",
"lodash": "^4.17.5"
},
"publishConfig": {
"access": "public"
}
}

View File

@@ -1,17 +0,0 @@
import { ContractArtifact } from 'ethereum-types';
import * as LibAbiEncoder from '../../generated-artifacts/LibAbiEncoder.json';
import * as LibEIP721 from '../../generated-artifacts/LibEIP712.json';
import * as LibFillResults from '../../generated-artifacts/LibFillResults.json';
import * as LibMath from '../../generated-artifacts/LibMath.json';
import * as LibOrder from '../../generated-artifacts/LibOrder.json';
import * as TestLibs from '../../generated-artifacts/TestLibs.json';
export const artifacts = {
TestLibs: TestLibs as ContractArtifact,
LibAbiEncoder: LibAbiEncoder as ContractArtifact,
LibFillResults: LibFillResults as ContractArtifact,
LibMath: LibMath as ContractArtifact,
LibOrder: LibOrder as ContractArtifact,
LibEIP721: LibEIP721 as ContractArtifact,
};

View File

@@ -1,2 +0,0 @@
export * from './artifacts';
export * from './wrappers';

View File

@@ -1,6 +0,0 @@
export * from '../../generated-wrappers/test_libs';
export * from '../../generated-wrappers/lib_abi_encoder';
export * from '../../generated-wrappers/lib_fill_results';
export * from '../../generated-wrappers/lib_math';
export * from '../../generated-wrappers/lib_order';
export * from '../../generated-wrappers/lib_e_i_p712';

View File

@@ -1,125 +0,0 @@
import {
addressUtils,
chaiSetup,
constants,
OrderFactory,
provider,
txDefaults,
web3Wrapper,
} from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
import { SignedOrder } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
import { TestLibsContract } from '../../generated-wrappers/test_libs';
import { artifacts } from '../../src/artifacts';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
describe('Exchange libs', () => {
let signedOrder: SignedOrder;
let orderFactory: OrderFactory;
let libs: TestLibsContract;
before(async () => {
await blockchainLifecycle.startAsync();
});
after(async () => {
await blockchainLifecycle.revertAsync();
});
before(async () => {
const accounts = await web3Wrapper.getAvailableAddressesAsync();
const makerAddress = accounts[0];
libs = await TestLibsContract.deployFrom0xArtifactAsync(artifacts.TestLibs, provider, txDefaults);
const defaultOrderParams = {
...constants.STATIC_ORDER_PARAMS,
exchangeAddress: libs.address,
makerAddress,
feeRecipientAddress: addressUtils.generatePseudoRandomAddress(),
makerAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
takerAssetData: assetDataUtils.encodeERC20AssetData(addressUtils.generatePseudoRandomAddress()),
};
const privateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
orderFactory = new OrderFactory(privateKey, defaultOrderParams);
});
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
// Note(albrow): These tests are designed to be supplemental to the
// combinatorial tests in test/exchange/internal. They test specific edge
// cases that are not covered by the combinatorial tests.
describe('LibMath', () => {
describe('isRoundingError', () => {
it('should return true if there is a rounding error of 0.1%', async () => {
const numerator = new BigNumber(20);
const denominator = new BigNumber(999);
const target = new BigNumber(50);
// rounding error = ((20*50/999) - floor(20*50/999)) / (20*50/999) = 0.1%
const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target);
expect(isRoundingError).to.be.true();
});
it('should return false if there is a rounding of 0.09%', async () => {
const numerator = new BigNumber(20);
const denominator = new BigNumber(9991);
const target = new BigNumber(500);
// rounding error = ((20*500/9991) - floor(20*500/9991)) / (20*500/9991) = 0.09%
const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target);
expect(isRoundingError).to.be.false();
});
it('should return true if there is a rounding error of 0.11%', async () => {
const numerator = new BigNumber(20);
const denominator = new BigNumber(9989);
const target = new BigNumber(500);
// rounding error = ((20*500/9989) - floor(20*500/9989)) / (20*500/9989) = 0.011%
const isRoundingError = await libs.publicIsRoundingErrorFloor.callAsync(numerator, denominator, target);
expect(isRoundingError).to.be.true();
});
});
describe('isRoundingErrorCeil', () => {
it('should return true if there is a rounding error of 0.1%', async () => {
const numerator = new BigNumber(20);
const denominator = new BigNumber(1001);
const target = new BigNumber(50);
// rounding error = (ceil(20*50/1001) - (20*50/1001)) / (20*50/1001) = 0.1%
const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target);
expect(isRoundingError).to.be.true();
});
it('should return false if there is a rounding of 0.09%', async () => {
const numerator = new BigNumber(20);
const denominator = new BigNumber(10009);
const target = new BigNumber(500);
// rounding error = (ceil(20*500/10009) - (20*500/10009)) / (20*500/10009) = 0.09%
const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target);
expect(isRoundingError).to.be.false();
});
it('should return true if there is a rounding error of 0.11%', async () => {
const numerator = new BigNumber(20);
const denominator = new BigNumber(10011);
const target = new BigNumber(500);
// rounding error = (ceil(20*500/10011) - (20*500/10011)) / (20*500/10011) = 0.11%
const isRoundingError = await libs.publicIsRoundingErrorCeil.callAsync(numerator, denominator, target);
expect(isRoundingError).to.be.true();
});
});
});
describe('LibOrder', () => {
describe('getOrderHash', () => {
it('should output the correct orderHash', async () => {
signedOrder = await orderFactory.newSignedOrderAsync();
const orderHashHex = await libs.publicGetOrderHash.callAsync(signedOrder);
expect(orderHashUtils.getOrderHashHex(signedOrder)).to.be.equal(orderHashHex);
});
});
});
});

View File

@@ -1,17 +0,0 @@
import { env, EnvVars } from '@0x/dev-utils';
import { coverage, profiler, provider } from '@0x/contracts-test-utils';
before('start web3 provider', () => {
provider.start();
});
after('generate coverage report', async () => {
if (env.parseBoolean(EnvVars.SolidityCoverage)) {
const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
await coverageSubprovider.writeCoverageAsync();
}
if (env.parseBoolean(EnvVars.SolidityProfiler)) {
const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
await profilerSubprovider.writeProfilerOutputAsync();
}
provider.stop();
});

View File

@@ -1,18 +0,0 @@
{
"extends": "../../tsconfig",
"compilerOptions": {
"outDir": "lib",
"rootDir": ".",
"resolveJsonModule": true
},
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
"files": [
"./generated-artifacts/TestLibs.json",
"./generated-artifacts/LibOrder.json",
"./generated-artifacts/LibFillResults.json",
"./generated-artifacts/LibAbiEncoder.json",
"./generated-artifacts/LibEIP712.json",
"./generated-artifacts/LibMath.json"
],
"exclude": ["./deploy/solc/solc_bin"]
}

View File

@@ -1,6 +0,0 @@
{
"extends": ["@0x/tslint-config"],
"rules": {
"custom-no-magic-numbers": false
}
}

View File

@@ -1,29 +0,0 @@
[
{
"timestamp": 1547225310,
"version": "1.0.4",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1547040760,
"version": "1.0.3",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1544741676,
"version": "1.0.2",
"changes": [
{
"note": "Dependencies updated"
}
]
}
]

View File

@@ -1,18 +0,0 @@
<!--
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
Edit the package's CHANGELOG.json file only.
-->
CHANGELOG
## v1.0.4 - _January 11, 2019_
* Dependencies updated
## v1.0.3 - _January 9, 2019_
* Dependencies updated
## v1.0.2 - _December 13, 2018_
* Dependencies updated

View File

@@ -1,70 +0,0 @@
## MultisSig Contracts
MultiSig smart contracts
## Usage
Contracts can be found in the [contracts](./contracts) directory. The contents of this directory are broken down into the following subdirectories:
- [multisig](./contracts/multisig)
- This directory contains the [Gnosis MultiSigWallet](https://github.com/gnosis/MultiSigWallet) and a custom extension that adds a timelock to transactions within the MultiSigWallet.
- [test](./contracts/test)
- This directory contains mocks and other contracts that are used solely for testing contracts within the other directories.
## 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.
For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
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/contracts-multisig yarn build
```
Or continuously rebuild on change:
```bash
PKG=@0x/contracts-multisig yarn watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash
yarn lint
```
### Run Tests
```bash
yarn test
```
#### Testing options
Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md).

View File

@@ -1,22 +0,0 @@
{
"artifactsDir": "./generated-artifacts",
"contractsDir": "./contracts",
"compilerSettings": {
"optimizer": {
"enabled": true,
"runs": 1000000
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode.object",
"evm.bytecode.sourceMap",
"evm.deployedBytecode.object",
"evm.deployedBytecode.sourceMap"
]
}
}
},
"contracts": ["MultiSigWallet", "MultiSigWalletWithTimeLock", "TestRejectEther"]
}

View File

@@ -1,23 +0,0 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity 0.4.24;
// solhint-disable no-empty-blocks
contract TestRejectEther {}

View File

@@ -1,84 +0,0 @@
{
"name": "@0x/contracts-multisig",
"version": "1.0.4",
"engines": {
"node": ">=6.12"
},
"description": "Multisig contracts used by 0x protocol",
"main": "lib/src/index.js",
"directories": {
"test": "test"
},
"scripts": {
"build": "yarn pre_build && tsc -b",
"build:ci": "yarn build",
"pre_build": "run-s compile generate_contract_wrappers",
"test": "yarn run_mocha",
"rebuild_and_test": "run-s build test",
"test:coverage": "SOLIDITY_COVERAGE=true run-s build run_mocha coverage:report:text coverage:report:lcov",
"test:profiler": "SOLIDITY_PROFILER=true run-s build run_mocha profiler:report:html",
"test:trace": "SOLIDITY_REVERT_TRACE=true run-s build run_mocha",
"run_mocha": "mocha --require source-map-support/register --require make-promises-safe 'lib/test/**/*.js' --timeout 100000 --bail --exit",
"compile": "sol-compiler",
"watch": "sol-compiler -w",
"clean": "shx rm -rf lib generated-artifacts generated-wrappers",
"generate_contract_wrappers": "abi-gen --abis ${npm_package_config_abis} --template ../../packages/abi-gen-templates/contract.handlebars --partials '../../packages/abi-gen-templates/partials/**/*.handlebars' --output generated-wrappers --backend ethers",
"lint": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
"coverage:report:text": "istanbul report text",
"coverage:report:html": "istanbul report html && open coverage/index.html",
"profiler:report:html": "istanbul report html && open coverage/index.html",
"coverage:report:lcov": "istanbul report lcov",
"test:circleci": "yarn test",
"lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
},
"config": {
"abis": "generated-artifacts/@(MultiSigWallet|MultiSigWalletWithTimeLock|TestRejectEther).json"
},
"repository": {
"type": "git",
"url": "https://github.com/0xProject/0x-monorepo.git"
},
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/0xProject/0x-monorepo/issues"
},
"homepage": "https://github.com/0xProject/0x-monorepo/contracts/multisig/README.md",
"devDependencies": {
"@0x/abi-gen": "^1.0.21",
"@0x/contracts-test-utils": "^1.0.4",
"@0x/dev-utils": "^1.0.23",
"@0x/sol-compiler": "^2.0.1",
"@0x/subproviders": "^2.1.10",
"@0x/tslint-config": "^2.0.1",
"@types/bn.js": "^4.11.0",
"@types/ethereumjs-abi": "^0.6.0",
"@types/lodash": "4.14.104",
"@types/node": "*",
"@types/yargs": "^10.0.0",
"chai": "^4.0.1",
"chai-as-promised": "^7.1.0",
"chai-bignumber": "^2.0.1",
"dirty-chai": "^2.0.1",
"make-promises-safe": "^1.1.0",
"mocha": "^4.1.0",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"solhint": "^1.4.1",
"tslint": "5.11.0",
"typescript": "3.0.1",
"yargs": "^10.0.3"
},
"dependencies": {
"@0x/base-contract": "^3.0.12",
"@0x/order-utils": "^3.1.1",
"@0x/types": "^1.5.1",
"@0x/typescript-typings": "^3.0.7",
"@0x/utils": "^3.0.0",
"@0x/web3-wrapper": "^3.2.3",
"ethereum-types": "^1.1.5",
"lodash": "^4.17.5"
},
"publishConfig": {
"access": "public"
}
}

View File

@@ -1,11 +0,0 @@
import { ContractArtifact } from 'ethereum-types';
import * as MultiSigWallet from '../../generated-artifacts/MultiSigWallet.json';
import * as MultiSigWalletWithTimeLock from '../../generated-artifacts/MultiSigWalletWithTimeLock.json';
import * as TestRejectEther from '../../generated-artifacts/TestRejectEther.json';
export const artifacts = {
TestRejectEther: TestRejectEther as ContractArtifact,
MultiSigWallet: MultiSigWallet as ContractArtifact,
MultiSigWalletWithTimeLock: MultiSigWalletWithTimeLock as ContractArtifact,
};

View File

@@ -1,2 +0,0 @@
export * from './artifacts';
export * from './wrappers';

View File

@@ -1,2 +0,0 @@
export * from '../../generated-wrappers/multi_sig_wallet';
export * from '../../generated-wrappers/multi_sig_wallet_with_time_lock';

View File

@@ -1,19 +0,0 @@
import { env, EnvVars } from '@0x/dev-utils';
import { coverage, profiler, provider } from '@0x/contracts-test-utils';
before('start web3 provider engine', () => {
provider.start();
});
after('generate coverage report', async () => {
if (env.parseBoolean(EnvVars.SolidityCoverage)) {
const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
await coverageSubprovider.writeCoverageAsync();
}
if (env.parseBoolean(EnvVars.SolidityProfiler)) {
const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
await profilerSubprovider.writeProfilerOutputAsync();
}
provider.stop();
});

View File

@@ -1,349 +0,0 @@
import {
chaiSetup,
constants,
expectTransactionFailedAsync,
expectTransactionFailedWithoutReasonAsync,
increaseTimeAndMineBlockAsync,
provider,
txDefaults,
web3Wrapper,
} from '@0x/contracts-test-utils';
import { BlockchainLifecycle } from '@0x/dev-utils';
import { RevertReason } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
import { LogWithDecodedArgs } from 'ethereum-types';
import * as _ from 'lodash';
import {
MultiSigWalletWithTimeLockConfirmationEventArgs,
MultiSigWalletWithTimeLockConfirmationTimeSetEventArgs,
MultiSigWalletWithTimeLockContract,
MultiSigWalletWithTimeLockExecutionEventArgs,
MultiSigWalletWithTimeLockExecutionFailureEventArgs,
MultiSigWalletWithTimeLockSubmissionEventArgs,
} from '../generated-wrappers/multi_sig_wallet_with_time_lock';
import { TestRejectEtherContract } from '../generated-wrappers/test_reject_ether';
import { artifacts } from '../src/artifacts';
import { MultiSigWrapper } from './utils/multi_sig_wrapper';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
// tslint:disable:no-unnecessary-type-assertion
describe('MultiSigWalletWithTimeLock', () => {
let owners: string[];
let notOwner: string;
const REQUIRED_APPROVALS = new BigNumber(2);
const SECONDS_TIME_LOCKED = new BigNumber(1000000);
before(async () => {
await blockchainLifecycle.startAsync();
});
after(async () => {
await blockchainLifecycle.revertAsync();
});
before(async () => {
const accounts = await web3Wrapper.getAvailableAddressesAsync();
owners = [accounts[0], accounts[1], accounts[2]];
notOwner = accounts[3];
});
let multiSig: MultiSigWalletWithTimeLockContract;
let multiSigWrapper: MultiSigWrapper;
beforeEach(async () => {
await blockchainLifecycle.startAsync();
});
afterEach(async () => {
await blockchainLifecycle.revertAsync();
});
describe('external_call', () => {
it('should be internal', async () => {
const secondsTimeLocked = new BigNumber(0);
multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync(
artifacts.MultiSigWalletWithTimeLock,
provider,
txDefaults,
owners,
REQUIRED_APPROVALS,
secondsTimeLocked,
);
expect(_.isUndefined((multiSig as any).external_call)).to.be.equal(true);
});
});
describe('confirmTransaction', () => {
let txId: BigNumber;
beforeEach(async () => {
const secondsTimeLocked = new BigNumber(0);
multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync(
artifacts.MultiSigWalletWithTimeLock,
provider,
txDefaults,
owners,
REQUIRED_APPROVALS,
secondsTimeLocked,
);
multiSigWrapper = new MultiSigWrapper(multiSig, provider);
const destination = notOwner;
const data = constants.NULL_BYTES;
const txReceipt = await multiSigWrapper.submitTransactionAsync(destination, data, owners[0]);
txId = (txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>).args
.transactionId;
});
it('should revert if called by a non-owner', async () => {
await expectTransactionFailedWithoutReasonAsync(multiSigWrapper.confirmTransactionAsync(txId, notOwner));
});
it('should revert if transaction does not exist', async () => {
const nonexistentTxId = new BigNumber(123456789);
await expectTransactionFailedWithoutReasonAsync(
multiSigWrapper.confirmTransactionAsync(nonexistentTxId, owners[1]),
);
});
it('should revert if transaction is already confirmed by caller', async () => {
await expectTransactionFailedWithoutReasonAsync(multiSigWrapper.confirmTransactionAsync(txId, owners[0]));
});
it('should confirm transaction for caller and log a Confirmation event', async () => {
const txReceipt = await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
const log = txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockConfirmationEventArgs>;
expect(log.event).to.be.equal('Confirmation');
expect(log.args.sender).to.be.equal(owners[1]);
expect(log.args.transactionId).to.be.bignumber.equal(txId);
});
it('should revert if fully confirmed', async () => {
await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
await expectTransactionFailedAsync(
multiSigWrapper.confirmTransactionAsync(txId, owners[2]),
RevertReason.TxFullyConfirmed,
);
});
it('should set the confirmation time of the transaction if it becomes fully confirmed', async () => {
const txReceipt = await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
const blockNum = await web3Wrapper.getBlockNumberAsync();
const timestamp = new BigNumber(await web3Wrapper.getBlockTimestampAsync(blockNum));
const log = txReceipt.logs[1] as LogWithDecodedArgs<MultiSigWalletWithTimeLockConfirmationTimeSetEventArgs>;
expect(log.args.confirmationTime).to.be.bignumber.equal(timestamp);
expect(log.args.transactionId).to.be.bignumber.equal(txId);
});
});
describe('executeTransaction', () => {
let txId: BigNumber;
const secondsTimeLocked = new BigNumber(1000000);
beforeEach(async () => {
multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync(
artifacts.MultiSigWalletWithTimeLock,
provider,
txDefaults,
owners,
REQUIRED_APPROVALS,
secondsTimeLocked,
);
multiSigWrapper = new MultiSigWrapper(multiSig, provider);
const destination = notOwner;
const data = constants.NULL_BYTES;
const txReceipt = await multiSigWrapper.submitTransactionAsync(destination, data, owners[0]);
txId = (txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>).args
.transactionId;
});
it('should revert if transaction has not been fully confirmed', async () => {
await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber());
await expectTransactionFailedAsync(
multiSigWrapper.executeTransactionAsync(txId, owners[1]),
RevertReason.TxNotFullyConfirmed,
);
});
it('should revert if time lock has not passed', async () => {
await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
await expectTransactionFailedAsync(
multiSigWrapper.executeTransactionAsync(txId, owners[1]),
RevertReason.TimeLockIncomplete,
);
});
it('should execute a transaction and log an Execution event if successful and called by owner', async () => {
await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber());
const txReceipt = await multiSigWrapper.executeTransactionAsync(txId, owners[1]);
const log = txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockExecutionEventArgs>;
expect(log.event).to.be.equal('Execution');
expect(log.args.transactionId).to.be.bignumber.equal(txId);
});
it('should execute a transaction and log an Execution event if successful and called by non-owner', async () => {
await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber());
const txReceipt = await multiSigWrapper.executeTransactionAsync(txId, notOwner);
const log = txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockExecutionEventArgs>;
expect(log.event).to.be.equal('Execution');
expect(log.args.transactionId).to.be.bignumber.equal(txId);
});
it('should revert if a required confirmation is revoked before executeTransaction is called', async () => {
await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber());
await multiSigWrapper.revokeConfirmationAsync(txId, owners[0]);
await expectTransactionFailedAsync(
multiSigWrapper.executeTransactionAsync(txId, owners[1]),
RevertReason.TxNotFullyConfirmed,
);
});
it('should revert if transaction has been executed', async () => {
await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber());
const txReceipt = await multiSigWrapper.executeTransactionAsync(txId, owners[1]);
const log = txReceipt.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockExecutionEventArgs>;
expect(log.args.transactionId).to.be.bignumber.equal(txId);
await expectTransactionFailedWithoutReasonAsync(multiSigWrapper.executeTransactionAsync(txId, owners[1]));
});
it("should log an ExecutionFailure event and not update the transaction's execution state if unsuccessful", async () => {
const contractWithoutFallback = await TestRejectEtherContract.deployFrom0xArtifactAsync(
artifacts.TestRejectEther,
provider,
txDefaults,
);
const data = constants.NULL_BYTES;
const value = new BigNumber(10);
const submissionTxReceipt = await multiSigWrapper.submitTransactionAsync(
contractWithoutFallback.address,
data,
owners[0],
{ value },
);
const newTxId = (submissionTxReceipt.logs[0] as LogWithDecodedArgs<
MultiSigWalletWithTimeLockSubmissionEventArgs
>).args.transactionId;
await multiSigWrapper.confirmTransactionAsync(newTxId, owners[1]);
await increaseTimeAndMineBlockAsync(secondsTimeLocked.toNumber());
const txReceipt = await multiSigWrapper.executeTransactionAsync(newTxId, owners[1]);
const executionFailureLog = txReceipt.logs[0] as LogWithDecodedArgs<
MultiSigWalletWithTimeLockExecutionFailureEventArgs
>;
expect(executionFailureLog.event).to.be.equal('ExecutionFailure');
expect(executionFailureLog.args.transactionId).to.be.bignumber.equal(newTxId);
});
});
describe('changeTimeLock', () => {
describe('initially non-time-locked', async () => {
before(async () => {
await blockchainLifecycle.startAsync();
});
after(async () => {
await blockchainLifecycle.revertAsync();
});
before('deploy a wallet', async () => {
const secondsTimeLocked = new BigNumber(0);
multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync(
artifacts.MultiSigWalletWithTimeLock,
provider,
txDefaults,
owners,
REQUIRED_APPROVALS,
secondsTimeLocked,
);
multiSigWrapper = new MultiSigWrapper(multiSig, provider);
});
it('should throw when not called by wallet', async () => {
return expectTransactionFailedWithoutReasonAsync(
multiSig.changeTimeLock.sendTransactionAsync(SECONDS_TIME_LOCKED, { from: owners[0] }),
);
});
it('should throw without enough confirmations', async () => {
const destination = multiSig.address;
const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(SECONDS_TIME_LOCKED);
const res = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]);
const log = res.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>;
const txId = log.args.transactionId;
return expectTransactionFailedAsync(
multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
RevertReason.TxNotFullyConfirmed,
);
});
it('should set confirmation time with enough confirmations', async () => {
const destination = multiSig.address;
const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(SECONDS_TIME_LOCKED);
const subRes = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]);
const subLog = subRes.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>;
const txId = subLog.args.transactionId;
const confirmRes = await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
expect(confirmRes.logs).to.have.length(2);
const blockNum = await web3Wrapper.getBlockNumberAsync();
const blockInfo = await web3Wrapper.getBlockIfExistsAsync(blockNum);
if (_.isUndefined(blockInfo)) {
throw new Error(`Unexpectedly failed to fetch block at #${blockNum}`);
}
const timestamp = new BigNumber(blockInfo.timestamp);
const confirmationTimeBigNum = new BigNumber(await multiSig.confirmationTimes.callAsync(txId));
expect(timestamp).to.be.bignumber.equal(confirmationTimeBigNum);
});
it('should be executable with enough confirmations and secondsTimeLocked of 0', async () => {
const destination = multiSig.address;
const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(SECONDS_TIME_LOCKED);
const subRes = await multiSigWrapper.submitTransactionAsync(destination, changeTimeLockData, owners[0]);
const subLog = subRes.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>;
const txId = subLog.args.transactionId;
await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
await multiSigWrapper.executeTransactionAsync(txId, owners[1]);
const secondsTimeLocked = new BigNumber(await multiSig.secondsTimeLocked.callAsync());
expect(secondsTimeLocked).to.be.bignumber.equal(SECONDS_TIME_LOCKED);
});
});
describe('initially time-locked', async () => {
before(async () => {
await blockchainLifecycle.startAsync();
});
after(async () => {
await blockchainLifecycle.revertAsync();
});
let txId: BigNumber;
const newSecondsTimeLocked = new BigNumber(0);
before('deploy a wallet, submit transaction to change timelock, and confirm the transaction', async () => {
multiSig = await MultiSigWalletWithTimeLockContract.deployFrom0xArtifactAsync(
artifacts.MultiSigWalletWithTimeLock,
provider,
txDefaults,
owners,
REQUIRED_APPROVALS,
SECONDS_TIME_LOCKED,
);
multiSigWrapper = new MultiSigWrapper(multiSig, provider);
const changeTimeLockData = multiSig.changeTimeLock.getABIEncodedTransactionData(newSecondsTimeLocked);
const res = await multiSigWrapper.submitTransactionAsync(
multiSig.address,
changeTimeLockData,
owners[0],
);
const log = res.logs[0] as LogWithDecodedArgs<MultiSigWalletWithTimeLockSubmissionEventArgs>;
txId = log.args.transactionId;
await multiSigWrapper.confirmTransactionAsync(txId, owners[1]);
});
it('should throw if it has enough confirmations but is not past the time lock', async () => {
return expectTransactionFailedAsync(
multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
RevertReason.TimeLockIncomplete,
);
});
it('should execute if it has enough confirmations and is past the time lock', async () => {
await increaseTimeAndMineBlockAsync(SECONDS_TIME_LOCKED.toNumber());
await web3Wrapper.awaitTransactionSuccessAsync(
await multiSig.executeTransaction.sendTransactionAsync(txId, { from: owners[0] }),
constants.AWAIT_TRANSACTION_MINED_MS,
);
const secondsTimeLocked = new BigNumber(await multiSig.secondsTimeLocked.callAsync());
expect(secondsTimeLocked).to.be.bignumber.equal(newSecondsTimeLocked);
});
});
});
});
// tslint:enable:no-unnecessary-type-assertion

View File

@@ -1,15 +0,0 @@
{
"extends": "../../tsconfig",
"compilerOptions": {
"outDir": "lib",
"rootDir": ".",
"resolveJsonModule": true
},
"include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
"files": [
"./generated-artifacts/MultiSigWallet.json",
"./generated-artifacts/MultiSigWalletWithTimeLock.json",
"./generated-artifacts/TestRejectEther.json"
],
"exclude": ["./deploy/solc/solc_bin"]
}

View File

@@ -1,6 +0,0 @@
{
"extends": ["@0x/tslint-config"],
"rules": {
"custom-no-magic-numbers": false
}
}

View File

@@ -1,38 +0,0 @@
[
{
"timestamp": 1547225310,
"version": "2.2.1",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"version": "2.2.0",
"changes": [
{
"note": "Added LibAddressArray",
"pr": 1383
},
{
"note": "Add validation and comments to MultiAssetProxy",
"pr": 1455
},
{
"note": "Move OrderValidator to extensions",
"pr": 1464
}
],
"timestamp": 1547040760
},
{
"timestamp": 1544741676,
"version": "2.1.59",
"changes": [
{
"note": "Dependencies updated"
}
]
}
]

View File

@@ -1,20 +0,0 @@
<!--
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
Edit the package's CHANGELOG.json file only.
-->
CHANGELOG
## v2.2.1 - _January 11, 2019_
* Dependencies updated
## v2.2.0 - _January 9, 2019_
* Added LibAddressArray (#1383)
* Add validation and comments to MultiAssetProxy (#1455)
* Move OrderValidator to extensions (#1464)
## v2.1.59 - _December 13, 2018_
* Dependencies updated

View File

@@ -1,92 +0,0 @@
[
{
"name": "MultiAssetProxy",
"version": "1.0.0",
"changes": [
{
"note": "Add MultiAssetProxy implementation",
"pr": 1224
}
]
},
{
"name": "OrderValidator",
"version": "1.0.0",
"changes": [
{
"note": "remove `getApproved` check from ERC721 approval query",
"pr": 1149
}
]
},
{
"name": "OrderValidator",
"version": "1.0.0",
"changes": [
{
"note": "protocol v2 deploy",
"networks": {
"1": "0x9463e518dea6810309563c81d5266c1b1d149138",
"3": "0x90431a90516ab49af23a0530e04e8c7836e7122f",
"42": "0xb389da3d204b412df2f75c6afb3d0a7ce0bc283d"
}
}
]
},
{
"name": "Exchange",
"version": "2.0.0",
"changes": [
{
"note": "protocol v2 deploy",
"networks": {
"1": "0x4f833a24e1f95d70f028921e27040ca56e09ab0b",
"3": "0x4530c0483a1633c7a1c97d2c53721caff2caaaaf",
"42": "0x35dd2932454449b14cee11a94d3674a936d5d7b2"
}
}
]
},
{
"name": "ERC20Proxy",
"version": "1.0.0",
"changes": [
{
"note": "protocol v2 deploy",
"networks": {
"1": "0x2240dab907db71e64d3e0dba4800c83b5c502d4e",
"3": "0xb1408f4c245a23c31b98d2c626777d4c0d766caa",
"42": "0xf1ec01d6236d3cd881a0bf0130ea25fe4234003e"
}
}
]
},
{
"name": "ERC721Proxy",
"version": "1.0.0",
"changes": [
{
"note": "protocol v2 deploy",
"networks": {
"1": "0x208e41fb445f1bb1b6780d58356e81405f3e6127",
"3": "0xe654aac058bfbf9f83fcaee7793311dd82f6ddb4",
"42": "0x2a9127c745688a165106c11cd4d647d2220af821"
}
}
]
},
{
"name": "AssetProxyOwner",
"version": "1.0.0",
"changes": [
{
"note": "protocol v2 deploy",
"networks": {
"1": "0x17992e4ffb22730138e4b62aaa6367fa9d3699a6",
"3": "0xf5fa5b5fed2727a0e44ac67f6772e97977aa358b",
"42": "0x2c824d2882baa668e0d5202b1e7f2922278703f8"
}
}
]
}
]

View File

@@ -1,74 +0,0 @@
## Contracts
Smart contracts that implement the 0x protocol. Addresses of the deployed contracts can be found in the 0x [wiki](https://0xproject.com/wiki#Deployed-Addresses) or the [CHANGELOG](./CHANGELOG.json) of this package.
## Usage
Contracts that make up and interact with version 2.0.0 of the protocol can be found in the [contracts](./contracts) directory. The contents of this directory are broken down into the following subdirectories:
- [protocol](./contracts/protocol)
- This directory contains the contracts that make up version 2.0.0. A full specification can be found [here](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md).
- [test](./contracts/test)
- This directory contains mocks and other contracts that are used solely for testing contracts within the other directories.
## Bug bounty
A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0xproject.com/wiki#Bug-Bounty).
## 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.
For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
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/contracts-protocol yarn build
```
Or continuously rebuild on change:
```bash
PKG=@0x/contracts-protocol yarn watch
```
### Clean
```bash
yarn clean
```
### Lint
```bash
yarn lint
```
### Run Tests
```bash
yarn test
```
#### Testing options
Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md).

View File

@@ -1,306 +0,0 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity 0.4.24;
import "../Exchange/MixinAssetProxyDispatcher.sol";
import "./MixinAuthorizable.sol";
contract MultiAssetProxy is
MixinAssetProxyDispatcher,
MixinAuthorizable
{
// Id of this proxy.
bytes4 constant internal PROXY_ID = bytes4(keccak256("MultiAsset(uint256[],bytes[])"));
// solhint-disable-next-line payable-fallback
function ()
external
{
// NOTE: The below assembly assumes that clients do some input validation and that the input is properly encoded according to the AbiV2 specification.
// It is technically possible for inputs with very large lengths and offsets to cause overflows. However, this would make the calldata prohibitively
// expensive and we therefore do not check for overflows in these scenarios.
assembly {
// The first 4 bytes of calldata holds the function selector
let selector := and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000)
// `transferFrom` will be called with the following parameters:
// assetData Encoded byte array.
// from Address to transfer asset from.
// to Address to transfer asset to.
// amount Amount of asset to transfer.
// bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
if eq(selector, 0xa85e59e400000000000000000000000000000000000000000000000000000000) {
// To lookup a value in a mapping, we load from the storage location keccak256(k, p),
// where k is the key left padded to 32 bytes and p is the storage slot
mstore(0, caller)
mstore(32, authorized_slot)
// Revert if authorized[msg.sender] == false
if iszero(sload(keccak256(0, 64))) {
// Revert with `Error("SENDER_NOT_AUTHORIZED")`
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(64, 0x0000001553454e4445525f4e4f545f415554484f52495a454400000000000000)
mstore(96, 0)
revert(0, 100)
}
// `transferFrom`.
// The function is marked `external`, so no abi decoding is done for
// us. Instead, we expect the `calldata` memory to contain the
// following:
//
// | Area | Offset | Length | Contents |
// |----------|--------|---------|-------------------------------------|
// | Header | 0 | 4 | function selector |
// | Params | | 4 * 32 | function parameters: |
// | | 4 | | 1. offset to assetData (*) |
// | | 36 | | 2. from |
// | | 68 | | 3. to |
// | | 100 | | 4. amount |
// | Data | | | assetData: |
// | | 132 | 32 | assetData Length |
// | | 164 | ** | assetData Contents |
//
// (*): offset is computed from start of function parameters, so offset
// by an additional 4 bytes in the calldata.
//
// (**): see table below to compute length of assetData Contents
//
// WARNING: The ABIv2 specification allows additional padding between
// the Params and Data section. This will result in a larger
// offset to assetData.
// Load offset to `assetData`
let assetDataOffset := calldataload(4)
// Asset data itself is encoded as follows:
//
// | Area | Offset | Length | Contents |
// |----------|-------------|---------|-------------------------------------|
// | Header | 0 | 4 | assetProxyId |
// | Params | | 2 * 32 | function parameters: |
// | | 4 | | 1. offset to amounts (*) |
// | | 36 | | 2. offset to nestedAssetData (*) |
// | Data | | | amounts: |
// | | 68 | 32 | amounts Length |
// | | 100 | a | amounts Contents |
// | | | | nestedAssetData: |
// | | 100 + a | 32 | nestedAssetData Length |
// | | 132 + a | b | nestedAssetData Contents (offsets) |
// | | 132 + a + b | | nestedAssetData[0, ..., len] |
// In order to find the offset to `amounts`, we must add:
// 4 (function selector)
// + assetDataOffset
// + 32 (assetData len)
// + 4 (assetProxyId)
let amountsOffset := calldataload(add(assetDataOffset, 40))
// In order to find the offset to `nestedAssetData`, we must add:
// 4 (function selector)
// + assetDataOffset
// + 32 (assetData len)
// + 4 (assetProxyId)
// + 32 (amounts offset)
let nestedAssetDataOffset := calldataload(add(assetDataOffset, 72))
// In order to find the start of the `amounts` contents, we must add:
// 4 (function selector)
// + assetDataOffset
// + 32 (assetData len)
// + 4 (assetProxyId)
// + amountsOffset
// + 32 (amounts len)
let amountsContentsStart := add(assetDataOffset, add(amountsOffset, 72))
// Load number of elements in `amounts`
let amountsLen := calldataload(sub(amountsContentsStart, 32))
// In order to find the start of the `nestedAssetData` contents, we must add:
// 4 (function selector)
// + assetDataOffset
// + 32 (assetData len)
// + 4 (assetProxyId)
// + nestedAssetDataOffset
// + 32 (nestedAssetData len)
let nestedAssetDataContentsStart := add(assetDataOffset, add(nestedAssetDataOffset, 72))
// Load number of elements in `nestedAssetData`
let nestedAssetDataLen := calldataload(sub(nestedAssetDataContentsStart, 32))
// Revert if number of elements in `amounts` differs from number of elements in `nestedAssetData`
if sub(amountsLen, nestedAssetDataLen) {
// Revert with `Error("LENGTH_MISMATCH")`
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(64, 0x0000000f4c454e4754485f4d49534d4154434800000000000000000000000000)
mstore(96, 0)
revert(0, 100)
}
// Copy `transferFrom` selector, offset to `assetData`, `from`, and `to` from calldata to memory
calldatacopy(
0, // memory can safely be overwritten from beginning
0, // start of calldata
100 // length of selector (4) and 3 params (32 * 3)
)
// Overwrite existing offset to `assetData` with our own
mstore(4, 128)
// Load `amount`
let amount := calldataload(100)
// Calculate number of bytes in `amounts` contents
let amountsByteLen := mul(amountsLen, 32)
// Initialize `assetProxyId` and `assetProxy` to 0
let assetProxyId := 0
let assetProxy := 0
// Loop through `amounts` and `nestedAssetData`, calling `transferFrom` for each respective element
for {let i := 0} lt(i, amountsByteLen) {i := add(i, 32)} {
// Calculate the total amount
let amountsElement := calldataload(add(amountsContentsStart, i))
let totalAmount := mul(amountsElement, amount)
// Revert if `amount` != 0 and multiplication resulted in an overflow
if iszero(or(
iszero(amount),
eq(div(totalAmount, amount), amountsElement)
)) {
// Revert with `Error("UINT256_OVERFLOW")`
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(64, 0x0000001055494e543235365f4f564552464c4f57000000000000000000000000)
mstore(96, 0)
revert(0, 100)
}
// Write `totalAmount` to memory
mstore(100, totalAmount)
// Load offset to `nestedAssetData[i]`
let nestedAssetDataElementOffset := calldataload(add(nestedAssetDataContentsStart, i))
// In order to find the start of the `nestedAssetData[i]` contents, we must add:
// 4 (function selector)
// + assetDataOffset
// + 32 (assetData len)
// + 4 (assetProxyId)
// + nestedAssetDataOffset
// + 32 (nestedAssetData len)
// + nestedAssetDataElementOffset
// + 32 (nestedAssetDataElement len)
let nestedAssetDataElementContentsStart := add(assetDataOffset, add(nestedAssetDataOffset, add(nestedAssetDataElementOffset, 104)))
// Load length of `nestedAssetData[i]`
let nestedAssetDataElementLenStart := sub(nestedAssetDataElementContentsStart, 32)
let nestedAssetDataElementLen := calldataload(nestedAssetDataElementLenStart)
// Revert if the `nestedAssetData` does not contain a 4 byte `assetProxyId`
if lt(nestedAssetDataElementLen, 4) {
// Revert with `Error("LENGTH_GREATER_THAN_3_REQUIRED")`
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(64, 0x0000001e4c454e4754485f475245415445525f5448414e5f335f524551554952)
mstore(96, 0x4544000000000000000000000000000000000000000000000000000000000000)
revert(0, 100)
}
// Load AssetProxy id
let currentAssetProxyId := and(
calldataload(nestedAssetDataElementContentsStart),
0xffffffff00000000000000000000000000000000000000000000000000000000
)
// Only load `assetProxy` if `currentAssetProxyId` does not equal `assetProxyId`
// We do not need to check if `currentAssetProxyId` is 0 since `assetProxy` is also initialized to 0
if sub(currentAssetProxyId, assetProxyId) {
// Update `assetProxyId`
assetProxyId := currentAssetProxyId
// To lookup a value in a mapping, we load from the storage location keccak256(k, p),
// where k is the key left padded to 32 bytes and p is the storage slot
mstore(132, assetProxyId)
mstore(164, assetProxies_slot)
assetProxy := sload(keccak256(132, 64))
}
// Revert if AssetProxy with given id does not exist
if iszero(assetProxy) {
// Revert with `Error("ASSET_PROXY_DOES_NOT_EXIST")`
mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
mstore(64, 0x0000001a41535345545f50524f58595f444f45535f4e4f545f45584953540000)
mstore(96, 0)
revert(0, 100)
}
// Copy `nestedAssetData[i]` from calldata to memory
calldatacopy(
132, // memory slot after `amounts[i]`
nestedAssetDataElementLenStart, // location of `nestedAssetData[i]` in calldata
add(nestedAssetDataElementLen, 32) // `nestedAssetData[i].length` plus 32 byte length
)
// call `assetProxy.transferFrom`
let success := call(
gas, // forward all gas
assetProxy, // call address of asset proxy
0, // don't send any ETH
0, // pointer to start of input
add(164, nestedAssetDataElementLen), // length of input
0, // write output over memory that won't be reused
0 // don't copy output to memory
)
// Revert with reason given by AssetProxy if `transferFrom` call failed
if iszero(success) {
returndatacopy(
0, // copy to memory at 0
0, // copy from return data at 0
returndatasize() // copy all return data
)
revert(0, returndatasize())
}
}
// Return if no `transferFrom` calls reverted
return(0, 0)
}
// Revert if undefined function is called
revert(0, 0)
}
}
/// @dev Gets the proxy id associated with the proxy address.
/// @return Proxy id.
function getProxyId()
external
pure
returns (bytes4)
{
return PROXY_ID;
}
}

View File

@@ -1,75 +0,0 @@
/*
Copyright 2018 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.4.24;
import "@0x/contracts-interfaces/contracts/protocol/Exchange/ISignatureValidator.sol";
contract MSignatureValidator is
ISignatureValidator
{
event SignatureValidatorApproval(
address indexed signerAddress, // Address that approves or disapproves a contract to verify signatures.
address indexed validatorAddress, // Address of signature validator contract.
bool approved // Approval or disapproval of validator contract.
);
// Allowed signature types.
enum SignatureType {
Illegal, // 0x00, default value
Invalid, // 0x01
EIP712, // 0x02
EthSign, // 0x03
Wallet, // 0x04
Validator, // 0x05
PreSigned, // 0x06
NSignatureTypes // 0x07, number of signature types. Always leave at end.
}
/// @dev Verifies signature using logic defined by Wallet contract.
/// @param hash Any 32 byte hash.
/// @param walletAddress Address that should have signed the given hash
/// and defines its own signature verification method.
/// @param signature Proof that the hash has been signed by signer.
/// @return True if the address recovered from the provided signature matches the input signer address.
function isValidWalletSignature(
bytes32 hash,
address walletAddress,
bytes signature
)
internal
view
returns (bool isValid);
/// @dev Verifies signature using logic defined by Validator contract.
/// @param validatorAddress Address of validator contract.
/// @param hash Any 32 byte hash.
/// @param signerAddress Address that should have signed the given hash.
/// @param signature Proof that the hash has been signed by signer.
/// @return True if the address recovered from the provided signature matches the input signer address.
function isValidValidatorSignature(
address validatorAddress,
bytes32 hash,
address signerAddress,
bytes signature
)
internal
view
returns (bool isValid);
}

Some files were not shown because too many files have changed in this diff Show More