Compare commits
	
		
			81 Commits
		
	
	
		
			feat/goerl
			...
			@0x/testne
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					bbd3c03969 | ||
| 
						 | 
					a4405c3d39 | ||
| 
						 | 
					0fe4f587d8 | ||
| 
						 | 
					d3c714bd17 | ||
| 
						 | 
					c399b7a7d5 | ||
| 
						 | 
					b9234e94fb | ||
| 
						 | 
					417bb87785 | ||
| 
						 | 
					0233ae3134 | ||
| 
						 | 
					eed0c5dd59 | ||
| 
						 | 
					2b3b167095 | ||
| 
						 | 
					5d91d19808 | ||
| 
						 | 
					0f374ddee9 | ||
| 
						 | 
					a65a9913cd | ||
| 
						 | 
					1ead32c666 | ||
| 
						 | 
					d1af9fc780 | ||
| 
						 | 
					0f06737fb6 | ||
| 
						 | 
					1676231532 | ||
| 
						 | 
					b1caf697c8 | ||
| 
						 | 
					51481065fe | ||
| 
						 | 
					e367da710c | ||
| 
						 | 
					f493d6524d | ||
| 
						 | 
					e1b85da2a7 | ||
| 
						 | 
					22c6548ed1 | ||
| 
						 | 
					afb32c087d | ||
| 
						 | 
					bbc1ed1c64 | ||
| 
						 | 
					3a46f1a27a | ||
| 
						 | 
					90cd364780 | ||
| 
						 | 
					6795e6f078 | ||
| 
						 | 
					cfb3404349 | ||
| 
						 | 
					0212f3ee78 | ||
| 
						 | 
					6b2995a4ee | ||
| 
						 | 
					09e7ac54d4 | ||
| 
						 | 
					f69009d4a8 | ||
| 
						 | 
					206802ae33 | ||
| 
						 | 
					91d4138fb8 | ||
| 
						 | 
					cb455f951a | ||
| 
						 | 
					5f25d20cd0 | ||
| 
						 | 
					1f0e2cd910 | ||
| 
						 | 
					1749d02701 | ||
| 
						 | 
					55ace3179c | ||
| 
						 | 
					7866d9ccb4 | ||
| 
						 | 
					51f73d07fa | ||
| 
						 | 
					63d84674ab | ||
| 
						 | 
					14066997b2 | ||
| 
						 | 
					28561e765a | ||
| 
						 | 
					453fbbdc5d | ||
| 
						 | 
					1e1e5ec10d | ||
| 
						 | 
					2088b0e459 | ||
| 
						 | 
					58400d9e01 | ||
| 
						 | 
					ac9375f1d2 | ||
| 
						 | 
					db061c9355 | ||
| 
						 | 
					d5ce6c464b | ||
| 
						 | 
					b06205bb7f | ||
| 
						 | 
					f528a3e1de | ||
| 
						 | 
					bddfdacfad | ||
| 
						 | 
					d3cdd3f235 | ||
| 
						 | 
					41ae45ea40 | ||
| 
						 | 
					657e0895ea | ||
| 
						 | 
					b2592d1cc2 | ||
| 
						 | 
					aa3524c3b2 | ||
| 
						 | 
					39deb1a05f | ||
| 
						 | 
					302d08e290 | ||
| 
						 | 
					05489dd7f1 | ||
| 
						 | 
					55bd076602 | ||
| 
						 | 
					7a224fe08f | ||
| 
						 | 
					3bdeb82097 | ||
| 
						 | 
					f49ab3f919 | ||
| 
						 | 
					42d5bdd3ab | ||
| 
						 | 
					7228cbfe92 | ||
| 
						 | 
					11e2fc5bc4 | ||
| 
						 | 
					3e88f820b8 | ||
| 
						 | 
					163750f8c2 | ||
| 
						 | 
					4aabc5d791 | ||
| 
						 | 
					c9a7b9dcc1 | ||
| 
						 | 
					98075b5653 | ||
| 
						 | 
					57ae5be916 | ||
| 
						 | 
					8caf62997f | ||
| 
						 | 
					f8656ad376 | ||
| 
						 | 
					29c6c2a2ad | ||
| 
						 | 
					f2db67ef02 | ||
| 
						 | 
					72b8ef33d9 | 
@@ -1,142 +1,306 @@
 | 
			
		||||
version: 2.1
 | 
			
		||||
version: 2
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
    build:
 | 
			
		||||
        resource_class: xlarge
 | 
			
		||||
        resource_class: medium+
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs8
 | 
			
		||||
        environment:
 | 
			
		||||
            NODE_OPTIONS: '--max-old-space-size=16384'
 | 
			
		||||
            CONTRACTS_COMMIT_HASH: '9ed05f5'
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        steps:
 | 
			
		||||
            - checkout
 | 
			
		||||
            - run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV
 | 
			
		||||
            # HACK(feuGeneA): commented out this hack as we're changing
 | 
			
		||||
            # from a circleci-maintained container to a different
 | 
			
		||||
            # container, and this hack may not apply anymore, as
 | 
			
		||||
            # suggested by the non-existance of `/home/circleci/.bashrc`
 | 
			
		||||
            # when running the command below.
 | 
			
		||||
            # - run:
 | 
			
		||||
            #       # HACK(albrow): Without this, yarn commands will sometimes
 | 
			
		||||
            #       # fail with a "permission denied" error.
 | 
			
		||||
            #       name: Set npm path
 | 
			
		||||
            #       command: npm set prefix=/home/circleci/npm && echo 'export PATH=$HOME/circleci/npm/bin:$PATH' >> /home/circleci/.bashrc
 | 
			
		||||
            - run:
 | 
			
		||||
                  name: install-yarn
 | 
			
		||||
                  command: npm install --force --global yarn@1.22.0
 | 
			
		||||
                  command: npm install --global yarn@1.9.4
 | 
			
		||||
            - run:
 | 
			
		||||
                  name: yarn
 | 
			
		||||
                  command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install
 | 
			
		||||
            - setup_remote_docker
 | 
			
		||||
            - run: yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci || yarn build:ci
 | 
			
		||||
            - run: yarn build:ci:no_website
 | 
			
		||||
            - run: yarn build:ts
 | 
			
		||||
            - save_cache:
 | 
			
		||||
                  key: repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
                  paths:
 | 
			
		||||
                      - ~/repo
 | 
			
		||||
            - save_cache:
 | 
			
		||||
                  key: python-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
                  paths:
 | 
			
		||||
                      - ~/repo/packages/python-contract-wrappers/generated
 | 
			
		||||
            - store_artifacts:
 | 
			
		||||
                  path: ~/repo/packages/python-contract-wrappers/generated
 | 
			
		||||
            - store_artifacts:
 | 
			
		||||
                  path: ~/repo/packages/abi-gen/test-cli/output
 | 
			
		||||
            - store_artifacts:
 | 
			
		||||
                  path: ~/repo/packages/contract-wrappers/generated_docs
 | 
			
		||||
    test-exchange-ganache:
 | 
			
		||||
                  path: ~/repo/packages/abi-gen-wrappers/generated_docs
 | 
			
		||||
    build-website:
 | 
			
		||||
        resource_class: medium+
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs8
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        steps:
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - run: yarn wsrun -p @0x/contracts-exchange -m --serial -c test:circleci
 | 
			
		||||
    test-integrations-ganache:
 | 
			
		||||
            - run: cd packages/website && yarn build:prod
 | 
			
		||||
    test-contracts-ganache:
 | 
			
		||||
        resource_class: medium+
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs8
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        steps:
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - run: yarn wsrun -p @0x/contracts-integrations -m --serial -c test:circleci
 | 
			
		||||
    test-contracts-staking-ganache:
 | 
			
		||||
        resource_class: medium+
 | 
			
		||||
            - run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-extensions @0x/contracts-asset-proxy @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-dev-utils
 | 
			
		||||
    test-contracts-geth:
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs8
 | 
			
		||||
            - image: 0xorg/devnet
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        steps:
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - run: yarn wsrun -p @0x/contracts-staking -m --serial -c test:circleci
 | 
			
		||||
    test-contracts-extra-ganache:
 | 
			
		||||
        resource_class: medium+
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        steps:
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - run: yarn wsrun -p @0x/contracts-exchange-forwarder -p @0x/contracts-coordinator -m --serial -c test:circleci
 | 
			
		||||
    test-contracts-rest-ganache:
 | 
			
		||||
        resource_class: medium+
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        steps:
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - run: yarn wsrun -p @0x/contracts-multisig -p @0x/contracts-utils -p @0x/contracts-exchange-libs -p  @0x/contracts-erc20 -p @0x/contracts-erc721 -p @0x/contracts-erc1155 -p @0x/contracts-asset-proxy -p @0x/contracts-broker -p @0x/contracts-zero-ex -m --serial -c test:circleci
 | 
			
		||||
            # HACK(albrow): we need to sleep 10 seconds to ensure the devnet is
 | 
			
		||||
            # initialized
 | 
			
		||||
            - run: sleep 10 && TEST_PROVIDER=geth yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-extensions @0x/contracts-asset-proxy @0x/contracts-exchange @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-dev-utils
 | 
			
		||||
    test-publish:
 | 
			
		||||
        resource_class: large
 | 
			
		||||
        environment:
 | 
			
		||||
            NODE_OPTIONS: '--max-old-space-size=6442'
 | 
			
		||||
        resource_class: medium+
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs8
 | 
			
		||||
            - image: 0xorg/verdaccio
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        steps:
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - run:
 | 
			
		||||
                  command: yarn test:publish:circleci
 | 
			
		||||
                  no_output_timeout: 1800
 | 
			
		||||
            - store_artifacts:
 | 
			
		||||
                  path: ~/.npm/_logs
 | 
			
		||||
            - run: yarn test:publish:circleci
 | 
			
		||||
    test-doc-generation:
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs8
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        steps:
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - run:
 | 
			
		||||
                  command: yarn test:generate_docs:circleci
 | 
			
		||||
                  no_output_timeout: 1200
 | 
			
		||||
            - run: yarn test:generate_docs:circleci
 | 
			
		||||
    test-rest:
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs8
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        environment:
 | 
			
		||||
            RUST_ROUTER: 'true'
 | 
			
		||||
        steps:
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - run: yarn wsrun -p @0x/contracts-test-utils -m --serial -c test:circleci
 | 
			
		||||
            - run: yarn wsrun -p @0x/contract-artifacts -m --serial -c test:circleci
 | 
			
		||||
            - run: yarn wsrun -p @0x/contract-wrappers-test -m --serial -c test:circleci
 | 
			
		||||
            - run: yarn wsrun -p @0x/order-utils -m --serial -c test:circleci
 | 
			
		||||
            - run: yarn wsrun -p @0x/asset-swapper -m --serial -c test:circleci
 | 
			
		||||
            - run: yarn wsrun test:circleci @0x/contracts-test-utils
 | 
			
		||||
            - run: yarn wsrun test:circleci @0x/abi-gen
 | 
			
		||||
            - run: yarn wsrun test:circleci @0x/asset-buyer
 | 
			
		||||
            - run: yarn wsrun test:circleci @0x/contract-artifacts
 | 
			
		||||
            - 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/order-utils
 | 
			
		||||
            - 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-contract-wrappers-test-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
                  key: coverage-abi-gen-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
                  paths:
 | 
			
		||||
                      - ~/repo/packages/contract-wrappers-test/coverage/lcov.info
 | 
			
		||||
                      - ~/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-asset-buyer-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
                  paths:
 | 
			
		||||
                      - ~/repo/packages/asset-buyer/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-order-utils-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
                  paths:
 | 
			
		||||
                      - ~/repo/packages/order-utils/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
 | 
			
		||||
    static-tests:
 | 
			
		||||
        resource_class: large
 | 
			
		||||
    test-python:
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs8
 | 
			
		||||
            - image: 0xorg/ganache-cli:2.2.2
 | 
			
		||||
            - image: 0xorg/launch-kit-backend:74bcc39
 | 
			
		||||
              environment:
 | 
			
		||||
                  RPC_URL: http://localhost:8545
 | 
			
		||||
                  NETWORK_ID: 50
 | 
			
		||||
                  WHITELIST_ALL_TOKENS: True
 | 
			
		||||
              command: |
 | 
			
		||||
                  sh -c "until printf 'POST /\r\nContent-Length: 26\r\n\r\n{\"method\":\"net_listening\"}' | nc localhost 8545 | grep true; do continue; done; node_modules/.bin/forever ts/lib/index.js"
 | 
			
		||||
        steps:
 | 
			
		||||
            - checkout
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  key: python-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - run:
 | 
			
		||||
                  command: |
 | 
			
		||||
                      cd python-packages
 | 
			
		||||
                      python -m ensurepip
 | 
			
		||||
                      ./pre_install
 | 
			
		||||
                      ./install
 | 
			
		||||
            - save_cache:
 | 
			
		||||
                  key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
                  paths:
 | 
			
		||||
                      - '/usr/local/bin'
 | 
			
		||||
                      - '/usr/local/lib/python3.7/site-packages'
 | 
			
		||||
            - run:
 | 
			
		||||
                  command: |
 | 
			
		||||
                      cd python-packages
 | 
			
		||||
                      ./parallel_without_sra_client coverage run setup.py test
 | 
			
		||||
                      ./build_docs
 | 
			
		||||
            - 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
 | 
			
		||||
            - store_artifacts:
 | 
			
		||||
                  path: ~/repo/python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc20_token/__init__.py
 | 
			
		||||
            - store_artifacts:
 | 
			
		||||
                  path: ~/repo/python-packages/contract_wrappers/src/zero_ex/contract_wrappers/exchange/__init__.py
 | 
			
		||||
            - store_artifacts:
 | 
			
		||||
                  path: ~/repo/python-packages/contract_addresses/build
 | 
			
		||||
            - store_artifacts:
 | 
			
		||||
                  path: ~/repo/python-packages/contract_artifacts/build
 | 
			
		||||
            - store_artifacts:
 | 
			
		||||
                  path: ~/repo/python-packages/contract_wrappers/build
 | 
			
		||||
            - store_artifacts:
 | 
			
		||||
                  path: ~/repo/python-packages/json_schemas/build
 | 
			
		||||
            - store_artifacts:
 | 
			
		||||
                  path: ~/repo/python-packages/middlewares/build
 | 
			
		||||
            - store_artifacts:
 | 
			
		||||
                  path: ~/repo/python-packages/order_utils/build
 | 
			
		||||
            - store_artifacts:
 | 
			
		||||
                  path: ~/repo/python-packages/sra_client/build
 | 
			
		||||
    test-rest-python:
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs8
 | 
			
		||||
        steps:
 | 
			
		||||
            - checkout
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - run:
 | 
			
		||||
                  command: |
 | 
			
		||||
                      cd python-packages/order_utils
 | 
			
		||||
                      python -m ensurepip
 | 
			
		||||
                      python -m pip install .
 | 
			
		||||
            - save_cache:
 | 
			
		||||
                  key: installed-py-{{ .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: nikolaik/python-nodejs:python3.7-nodejs8
 | 
			
		||||
        steps:
 | 
			
		||||
            - checkout
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  key: installed-py-{{ .Branch }}-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  key: python-contract-wrappers-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - run:
 | 
			
		||||
                  command: |
 | 
			
		||||
                      python -m ensurepip
 | 
			
		||||
                      cd python-packages
 | 
			
		||||
                      ./pre_install
 | 
			
		||||
                      ./install
 | 
			
		||||
                      ./lint
 | 
			
		||||
    static-tests:
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs8
 | 
			
		||||
        steps:
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
@@ -144,10 +308,11 @@ jobs:
 | 
			
		||||
            - run: yarn lerna run lint
 | 
			
		||||
            - run: yarn prettier:ci
 | 
			
		||||
            - run: yarn deps_versions:ci
 | 
			
		||||
            - run: yarn diff_md_docs:ci
 | 
			
		||||
            - run: cd packages/0x.js && yarn build:umd:prod
 | 
			
		||||
            - run: yarn bundlewatch
 | 
			
		||||
    submit-coverage:
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs8
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        steps:
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
@@ -155,35 +320,84 @@ jobs:
 | 
			
		||||
                      - repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - coverage-contract-wrappers-test-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
                      - coverage-abi-gen-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - coverage-assert-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - coverage-asset-buyer-{{ .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-order-utils-{{ .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
 | 
			
		||||
workflows:
 | 
			
		||||
    version: 2
 | 
			
		||||
    main:
 | 
			
		||||
        jobs:
 | 
			
		||||
            - build
 | 
			
		||||
            # Disabled until we begin actively developing on these packages again.
 | 
			
		||||
            # - test-exchange-ganache:
 | 
			
		||||
            #       requires:
 | 
			
		||||
            #           - build
 | 
			
		||||
            # - test-integrations-ganache:
 | 
			
		||||
            #       requires:
 | 
			
		||||
            #           - build
 | 
			
		||||
            # - test-contracts-staking-ganache:
 | 
			
		||||
            #       requires:
 | 
			
		||||
            #           - build
 | 
			
		||||
            # - test-contracts-extra-ganache:
 | 
			
		||||
            #       requires:
 | 
			
		||||
            #           - build
 | 
			
		||||
            - test-contracts-rest-ganache:
 | 
			
		||||
            - build-website:
 | 
			
		||||
                  requires:
 | 
			
		||||
                      - build
 | 
			
		||||
            - test-contracts-ganache:
 | 
			
		||||
                  requires:
 | 
			
		||||
                      - build
 | 
			
		||||
            # TODO(albrow): Tests always fail on Geth right now because our fork
 | 
			
		||||
            # is outdated. Uncomment once we have updated our Geth fork.
 | 
			
		||||
            # - test-contracts-geth:
 | 
			
		||||
            #       requires:
 | 
			
		||||
            #           - build
 | 
			
		||||
            - test-rest:
 | 
			
		||||
                  requires:
 | 
			
		||||
                      - build
 | 
			
		||||
@@ -196,14 +410,15 @@ workflows:
 | 
			
		||||
            - test-doc-generation:
 | 
			
		||||
                  requires:
 | 
			
		||||
                      - build
 | 
			
		||||
            # Disabled until this repo has a coveralls API key
 | 
			
		||||
            # - submit-coverage:
 | 
			
		||||
            #       requires:
 | 
			
		||||
            #           # Disabled until we begin actively developing on these packages again.
 | 
			
		||||
            #           # - test-exchange-ganache
 | 
			
		||||
            #           # - test-integrations-ganache
 | 
			
		||||
            #           # - test-contracts-staking-ganache
 | 
			
		||||
            #           # - test-contracts-extra-ganache
 | 
			
		||||
            #           - test-contracts-rest-ganache
 | 
			
		||||
            #           - test-rest
 | 
			
		||||
            #           - static-tests
 | 
			
		||||
            - submit-coverage:
 | 
			
		||||
                  requires:
 | 
			
		||||
                      - test-rest
 | 
			
		||||
                      - test-python
 | 
			
		||||
            - static-tests-python:
 | 
			
		||||
                  requires:
 | 
			
		||||
                      - test-python
 | 
			
		||||
            - test-python:
 | 
			
		||||
                  requires:
 | 
			
		||||
                      - build
 | 
			
		||||
            # skip python tox run for now, as we don't yet have multiple test environments to support.
 | 
			
		||||
            #- test-rest-python
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							@@ -2,3 +2,7 @@
 | 
			
		||||
 | 
			
		||||
# Automatically collapse generated files in GitHub.
 | 
			
		||||
*.svg linguist-generated=true
 | 
			
		||||
packages/contract-artifacts/artifacts/*json linguist-generated=true
 | 
			
		||||
packages/abi-gen-wrappers/src/generated-wrappers/*.ts linguist-generated=true
 | 
			
		||||
packages/contract-wrappers/src/generated-wrappers/*.ts linguist-generated=true
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										33
									
								
								.github/autolabeler.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										33
									
								
								.github/autolabeler.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,6 +1,39 @@
 | 
			
		||||
python: ['python-packages']
 | 
			
		||||
contracts: ['contracts']
 | 
			
		||||
@0x/sol-doc: ['packages/sol-doc']
 | 
			
		||||
@0x/sol-resolver: ['packages/sol-resolver']
 | 
			
		||||
@0x/contracts-gen: ['packages/contracts-gen']
 | 
			
		||||
@0x/sra-spec: ['packages/sra-spec']
 | 
			
		||||
@0x/subproviders: ['packages/subproviders']
 | 
			
		||||
@0x/contract-addresses: ['packages/contract-addresses']
 | 
			
		||||
@0x/migrations: ['packages/migrations']
 | 
			
		||||
@0x/web3-wrapper: ['packages/web3-wrapper']
 | 
			
		||||
@0x/sol-compiler: ['packages/sol-compiler']
 | 
			
		||||
@0x/types: ['packages/types']
 | 
			
		||||
@0x/instant: ['packages/instant']
 | 
			
		||||
@0x/abi-gen-templates: ['packages/abi-gen-templates']
 | 
			
		||||
@0x/abi-gen: ['packages/abi-gen']
 | 
			
		||||
@0x/website: ['packages/website']
 | 
			
		||||
@0x/sol-coverage: ['packages/sol-coverage']
 | 
			
		||||
@0x/sol-profiler: ['packages/sol-profiler']
 | 
			
		||||
@0x/sol-trace: ['packages/sol-trace']
 | 
			
		||||
@0x/sol-tracing-utils: ['packages/sol-tracing-utils']
 | 
			
		||||
@0x/utils: ['packages/utils']
 | 
			
		||||
@0x/tslint-config: ['packages/tslint-config']
 | 
			
		||||
@0x/asset-buyer: ['packages/asset-buyer']
 | 
			
		||||
@0x/order-utils: ['packages/order-utils']
 | 
			
		||||
@0x/assert: ['packages/assert']
 | 
			
		||||
@0x/base-contract: ['packages/base-contract']
 | 
			
		||||
@0x/typescript-typings: ['packages/typescript-typings']
 | 
			
		||||
0x.js: ['packages/0x.js']
 | 
			
		||||
@0x/abi-gen-wrappers: ['packages/abi-gen-wrappers']
 | 
			
		||||
@0x/contract-artifacts: ['packages/contract-artifacts']
 | 
			
		||||
@0x/dev-utils: ['packages/dev-utils']
 | 
			
		||||
@0x/contract-wrappers: ['packages/contract-wrappers']
 | 
			
		||||
@0x/json-schemas: ['packages/json-schemas']
 | 
			
		||||
@0x/ethereum-types: ['ethereum-types']
 | 
			
		||||
@0x/connect: ['packages/connect']
 | 
			
		||||
@0x/fill-scenarios: ['packages/fill-scenarios']
 | 
			
		||||
@0x/dev-tools-pages: ['packages/dev-tools-pages']
 | 
			
		||||
@0x/testnet-faucets: ['packages/testnet-faucets']
 | 
			
		||||
@0x/monorepo-scripts: ['packages/monorepo-scripts']
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										53
									
								
								.github/workflows/publish.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										53
									
								
								.github/workflows/publish.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,53 +0,0 @@
 | 
			
		||||
name: publish
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  workflow_dispatch:
 | 
			
		||||
      inputs:
 | 
			
		||||
          ci_status:
 | 
			
		||||
              description: 'required CI status'
 | 
			
		||||
              default: 'success'
 | 
			
		||||
              required: true
 | 
			
		||||
          prerelease:
 | 
			
		||||
              description: 'prerelease name'
 | 
			
		||||
              required: false
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
    publish:
 | 
			
		||||
        runs-on: ubuntu-latest
 | 
			
		||||
        steps:
 | 
			
		||||
            - name: 'check successful status'
 | 
			
		||||
              run: |
 | 
			
		||||
                  REF_STATUS=$(curl -s \
 | 
			
		||||
                  'https://api.github.com/repos/${{ github.repository }}/commits/${{ github.ref }}/status' \
 | 
			
		||||
                  | jq .state)
 | 
			
		||||
                  [[ "${REF_STATUS}" == '"${{ github.event.inputs.ci_status }}"' ]] || \
 | 
			
		||||
                  (echo "::error ::${{ github.ref }} does not have a successful CI status" && false)
 | 
			
		||||
            - uses: actions/checkout@v2
 | 
			
		||||
              with:
 | 
			
		||||
                ref: ${{ github.ref }}
 | 
			
		||||
                fetch-depth: 0
 | 
			
		||||
            - uses: actions/setup-node@v1
 | 
			
		||||
              with:
 | 
			
		||||
                node-version: 16
 | 
			
		||||
            - uses: actions/setup-python@v2
 | 
			
		||||
            - name: 'configure git'
 | 
			
		||||
              run: |
 | 
			
		||||
                  git config --global user.email "github-actions@github.com"
 | 
			
		||||
                  git config --global user.name "Github Actions"
 | 
			
		||||
            - name: 'install dependencies'
 | 
			
		||||
              run: |
 | 
			
		||||
                  yarn -D
 | 
			
		||||
            - name: 'build and publish'
 | 
			
		||||
              run: |
 | 
			
		||||
                  echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' > .npmrc
 | 
			
		||||
                  npm run run:publish:gha
 | 
			
		||||
              env:
 | 
			
		||||
                  NPM_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
 | 
			
		||||
                  GITHUB_TOKEN: ${{ github.token }}
 | 
			
		||||
                  PUBLISH_PRERELEASE: ${{ github.event.inputs.prerelease }}
 | 
			
		||||
            - name: 'merge into main branch'
 | 
			
		||||
              if: github.event.inputs.prerelease == '' # unless it's a prerelease
 | 
			
		||||
              run: |
 | 
			
		||||
                  git checkout main && \
 | 
			
		||||
                  git merge ${{ github.ref }} && \
 | 
			
		||||
                  git push
 | 
			
		||||
							
								
								
									
										123
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										123
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -40,12 +40,9 @@ build/Release
 | 
			
		||||
node_modules/
 | 
			
		||||
jspm_packages/
 | 
			
		||||
 | 
			
		||||
# TypeScript v1 declaration files
 | 
			
		||||
# Typescript v1 declaration files
 | 
			
		||||
typings/
 | 
			
		||||
 | 
			
		||||
# NVM config
 | 
			
		||||
.nvmrc
 | 
			
		||||
 | 
			
		||||
# Optional npm cache directory
 | 
			
		||||
.npm
 | 
			
		||||
.npmrc
 | 
			
		||||
@@ -75,108 +72,82 @@ generated_docs/
 | 
			
		||||
 | 
			
		||||
TODO.md
 | 
			
		||||
 | 
			
		||||
# IDE file
 | 
			
		||||
# VSCode file
 | 
			
		||||
.vscode
 | 
			
		||||
.idea
 | 
			
		||||
 | 
			
		||||
packages/website/public/bundle*
 | 
			
		||||
packages/dev-tools-pages/public/bundle*
 | 
			
		||||
 | 
			
		||||
# server cli
 | 
			
		||||
packages/testnet-faucets/server/
 | 
			
		||||
 | 
			
		||||
# generated contract artifacts/
 | 
			
		||||
contracts/broker/generated-artifacts/
 | 
			
		||||
contracts/broker/test/generated-artifacts/
 | 
			
		||||
contracts/erc20-bridge-sampler/generated-artifacts/
 | 
			
		||||
contracts/erc20-bridge-sampler/test/generated-artifacts/
 | 
			
		||||
contracts/integrations/generated-artifacts/
 | 
			
		||||
contracts/integrations/test/generated-artifacts/
 | 
			
		||||
contracts/staking/generated-artifacts/
 | 
			
		||||
contracts/staking/test/generated-artifacts/
 | 
			
		||||
contracts/coordinator/generated-artifacts/
 | 
			
		||||
contracts/coordinator/test/generated-artifacts/
 | 
			
		||||
contracts/exchange/generated-artifacts/
 | 
			
		||||
contracts/exchange/test/generated-artifacts/
 | 
			
		||||
contracts/asset-proxy/generated-artifacts/
 | 
			
		||||
contracts/asset-proxy/test/generated-artifacts/
 | 
			
		||||
contracts/multisig/generated-artifacts/
 | 
			
		||||
contracts/multisig/test/generated-artifacts/
 | 
			
		||||
contracts/utils/generated-artifacts/
 | 
			
		||||
contracts/utils/test/generated-artifacts/
 | 
			
		||||
contracts/exchange-libs/generated-artifacts/
 | 
			
		||||
contracts/exchange-libs/test/generated-artifacts/
 | 
			
		||||
contracts/erc20/generated-artifacts/
 | 
			
		||||
contracts/erc20/test/generated-artifacts/
 | 
			
		||||
contracts/erc721/generated-artifacts/
 | 
			
		||||
contracts/erc721/test/generated-artifacts/
 | 
			
		||||
contracts/erc1155/generated-artifacts/
 | 
			
		||||
contracts/erc1155/test/generated-artifacts/
 | 
			
		||||
contracts/extensions/generated-artifacts/
 | 
			
		||||
contracts/extensions/test/generated-artifacts/
 | 
			
		||||
contracts/exchange-forwarder/generated-artifacts/
 | 
			
		||||
contracts/exchange-forwarder/test/generated-artifacts/
 | 
			
		||||
contracts/dev-utils/generated-artifacts/
 | 
			
		||||
contracts/dev-utils/test/generated-artifacts/
 | 
			
		||||
contracts/zero-ex/generated-artifacts/
 | 
			
		||||
contracts/zero-ex/test/generated-artifacts/
 | 
			
		||||
contracts/treasury/generated-artifacts/
 | 
			
		||||
contracts/treasury/test/generated-artifacts/
 | 
			
		||||
 | 
			
		||||
# generated truffle contract artifacts/
 | 
			
		||||
contracts/broker/build/
 | 
			
		||||
contracts/erc20-bridge-sampler/build/
 | 
			
		||||
contracts/staking/build/
 | 
			
		||||
contracts/coordinator/build/
 | 
			
		||||
contracts/exchange/build/
 | 
			
		||||
contracts/asset-proxy/build/
 | 
			
		||||
contracts/multisig/build/
 | 
			
		||||
contracts/utils/build/
 | 
			
		||||
contracts/exchange-libs/build/
 | 
			
		||||
contracts/erc20/build/
 | 
			
		||||
contracts/erc721/build/
 | 
			
		||||
contracts/erc1155/build/
 | 
			
		||||
contracts/extensions/build/
 | 
			
		||||
contracts/exchange-forwarder/build/
 | 
			
		||||
contracts/dev-utils/build/
 | 
			
		||||
packages/sol-tracing-utils/test/fixtures/artifacts/
 | 
			
		||||
python-packages/contract_artifacts/src/zero_ex/contract_artifacts/artifacts/
 | 
			
		||||
 | 
			
		||||
# generated contract wrappers
 | 
			
		||||
contracts/broker/generated-wrappers/
 | 
			
		||||
contracts/broker/test/generated-wrappers/
 | 
			
		||||
packages/abi-gen-wrappers/src/generated-wrappers/
 | 
			
		||||
packages/python-contract-wrappers/generated/
 | 
			
		||||
contracts/erc20-bridge-sampler/generated-wrappers/
 | 
			
		||||
contracts/erc20-bridge-sampler/test/generated-wrappers/
 | 
			
		||||
contracts/integrations/generated-wrappers/
 | 
			
		||||
contracts/integrations/test/generated-wrappers/
 | 
			
		||||
contracts/staking/generated-wrappers/
 | 
			
		||||
contracts/staking/test/generated-wrappers/
 | 
			
		||||
contracts/coordinator/generated-wrappers/
 | 
			
		||||
contracts/coordinator/test/generated-wrappers/
 | 
			
		||||
contracts/exchange/generated-wrappers/
 | 
			
		||||
contracts/exchange/test/generated-wrappers/
 | 
			
		||||
contracts/asset-proxy/generated-wrappers/
 | 
			
		||||
contracts/asset-proxy/test/generated-wrappers/
 | 
			
		||||
contracts/multisig/generated-wrappers/
 | 
			
		||||
contracts/multisig/test/generated-wrappers/
 | 
			
		||||
contracts/utils/generated-wrappers/
 | 
			
		||||
contracts/utils/test/generated-wrappers/
 | 
			
		||||
contracts/exchange-libs/generated-wrappers/
 | 
			
		||||
contracts/exchange-libs/test/generated-wrappers/
 | 
			
		||||
contracts/erc20/generated-wrappers/
 | 
			
		||||
contracts/erc20/test/generated-wrappers/
 | 
			
		||||
contracts/erc721/generated-wrappers/
 | 
			
		||||
contracts/erc721/test/generated-wrappers/
 | 
			
		||||
contracts/erc1155/generated-wrappers/
 | 
			
		||||
contracts/erc1155/test/generated-wrappers/
 | 
			
		||||
contracts/extensions/generated-wrappers/
 | 
			
		||||
contracts/extensions/test/generated-wrappers/
 | 
			
		||||
contracts/exchange-forwarder/generated-wrappers/
 | 
			
		||||
contracts/exchange-forwarder/test/generated-wrappers/
 | 
			
		||||
contracts/dev-utils/generated-wrappers/
 | 
			
		||||
contracts/dev-utils/test/generated-wrappers/
 | 
			
		||||
contracts/zero-ex/generated-wrappers/
 | 
			
		||||
contracts/zero-ex/test/generated-wrappers/
 | 
			
		||||
contracts/treasury/generated-wrappers/
 | 
			
		||||
contracts/treasury/test/generated-wrappers/
 | 
			
		||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc20_token/__init__.py
 | 
			
		||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/exchange/__init__.py
 | 
			
		||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/asset_proxy_owner/__init__.py
 | 
			
		||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/coordinator/__init__.py
 | 
			
		||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/coordinator_registry/__init__.py
 | 
			
		||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dummy_erc20_token/__init__.py
 | 
			
		||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dummy_erc721_token/__init__.py
 | 
			
		||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/dutch_auction/__init__.py
 | 
			
		||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc20_proxy/__init__.py
 | 
			
		||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc721_proxy/__init__.py
 | 
			
		||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/erc721_token/__init__.py
 | 
			
		||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/eth_balance_checker/__init__.py
 | 
			
		||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/forwarder/__init__.py
 | 
			
		||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/i_asset_proxy/__init__.py
 | 
			
		||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/i_validator/__init__.py
 | 
			
		||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/i_wallet/__init__.py
 | 
			
		||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/multi_asset_proxy/__init__.py
 | 
			
		||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/order_validator/__init__.py
 | 
			
		||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/weth9/__init__.py
 | 
			
		||||
python-packages/contract_wrappers/src/zero_ex/contract_wrappers/zrx_token/__init__.py
 | 
			
		||||
 | 
			
		||||
# Doc README copy
 | 
			
		||||
packages/*/docs/README.md
 | 
			
		||||
# solc-bin in sol-compiler
 | 
			
		||||
packages/sol-compiler/solc_bin/
 | 
			
		||||
 | 
			
		||||
.DS_Store
 | 
			
		||||
# Monorepo scripts
 | 
			
		||||
packages/*/scripts/
 | 
			
		||||
 | 
			
		||||
# the snapshot that gets built for migrations sure does have a ton of files
 | 
			
		||||
packages/migrations/0x_ganache_snapshot*
 | 
			
		||||
# python stuff
 | 
			
		||||
.eggs
 | 
			
		||||
.mypy_cache
 | 
			
		||||
.tox
 | 
			
		||||
python-packages/*/build
 | 
			
		||||
python-packages/*/dist
 | 
			
		||||
__pycache__
 | 
			
		||||
python-packages/*/src/*.egg-info
 | 
			
		||||
python-packages/*/.coverage
 | 
			
		||||
 | 
			
		||||
# python keeps package-local copies of json schemas
 | 
			
		||||
python-packages/json_schemas/src/zero_ex/json_schemas/schemas
 | 
			
		||||
 
 | 
			
		||||
@@ -1,90 +1,40 @@
 | 
			
		||||
lib
 | 
			
		||||
.nyc_output
 | 
			
		||||
/contracts/broker/generated-wrappers
 | 
			
		||||
/contracts/broker/test/generated-wrappers
 | 
			
		||||
/contracts/broker/generated-artifacts
 | 
			
		||||
/contracts/broker/test/generated-artifacts
 | 
			
		||||
/contracts/integrations/generated-wrappers
 | 
			
		||||
/contracts/integrations/test/generated-wrappers
 | 
			
		||||
/contracts/integrations/generated-artifacts
 | 
			
		||||
/contracts/integrations/test/generated-artifacts
 | 
			
		||||
/contracts/staking/generated-wrappers
 | 
			
		||||
/contracts/staking/test/generated-wrappers
 | 
			
		||||
/contracts/staking/generated-artifacts
 | 
			
		||||
/contracts/staking/test/generated-artifacts
 | 
			
		||||
/contracts/coordinator/generated-wrappers
 | 
			
		||||
/contracts/coordinator/test/generated-wrappers
 | 
			
		||||
/contracts/coordinator/generated-artifacts
 | 
			
		||||
/contracts/coordinator/test/generated-artifacts
 | 
			
		||||
/contracts/exchange/generated-wrappers
 | 
			
		||||
/contracts/exchange/test/generated-wrappers
 | 
			
		||||
/contracts/exchange/generated-artifacts
 | 
			
		||||
/contracts/exchange/test/generated-artifacts
 | 
			
		||||
/contracts/asset-proxy/generated-wrappers
 | 
			
		||||
/contracts/asset-proxy/test/generated-wrappers
 | 
			
		||||
/contracts/asset-proxy/generated-artifacts
 | 
			
		||||
/contracts/asset-proxy/test/generated-artifacts
 | 
			
		||||
/contracts/multisig/generated-wrappers
 | 
			
		||||
/contracts/multisig/test/generated-wrappers
 | 
			
		||||
/contracts/multisig/generated-artifacts
 | 
			
		||||
/contracts/multisig/test/generated-artifacts
 | 
			
		||||
/contracts/utils/generated-wrappers
 | 
			
		||||
/contracts/utils/test/generated-wrappers
 | 
			
		||||
/contracts/utils/generated-artifacts
 | 
			
		||||
/contracts/utils/test/generated-artifacts
 | 
			
		||||
/contracts/exchange-libs/generated-wrappers
 | 
			
		||||
/contracts/exchange-libs/test/generated-wrappers
 | 
			
		||||
/contracts/exchange-libs/generated-artifacts
 | 
			
		||||
/contracts/exchange-libs/test/generated-artifacts
 | 
			
		||||
/contracts/erc20/generated-wrappers
 | 
			
		||||
/contracts/erc20/test/generated-wrappers
 | 
			
		||||
/contracts/erc20/generated-artifacts
 | 
			
		||||
/contracts/erc20/test/generated-artifacts
 | 
			
		||||
/contracts/erc721/generated-wrappers
 | 
			
		||||
/contracts/erc721/test/generated-wrappers
 | 
			
		||||
/contracts/erc721/generated-artifacts
 | 
			
		||||
/contracts/erc721/test/generated-artifacts
 | 
			
		||||
/contracts/erc1155/generated-wrappers
 | 
			
		||||
/contracts/erc1155/test/generated-wrappers
 | 
			
		||||
/contracts/erc1155/generated-artifacts
 | 
			
		||||
/contracts/erc1155/test/generated-artifacts
 | 
			
		||||
/contracts/extensions/generated-wrappers
 | 
			
		||||
/contracts/extensions/test/generated-wrappers
 | 
			
		||||
/contracts/extensions/generated-artifacts
 | 
			
		||||
/contracts/extensions/test/generated-artifacts
 | 
			
		||||
/contracts/exchange-forwarder/generated-wrappers
 | 
			
		||||
/contracts/exchange-forwarder/test/generated-wrappers
 | 
			
		||||
/contracts/exchange-forwarder/generated-artifacts
 | 
			
		||||
/contracts/exchange-forwarder/test/generated-artifacts
 | 
			
		||||
/contracts/dev-utils/generated-wrappers
 | 
			
		||||
/contracts/dev-utils/test/generated-wrappers
 | 
			
		||||
/contracts/dev-utils/generated-artifacts
 | 
			
		||||
/contracts/dev-utils/test/generated-artifacts
 | 
			
		||||
/contracts/zero-ex/generated-wrappers
 | 
			
		||||
/contracts/zero-ex/test/generated-wrappers
 | 
			
		||||
/contracts/zero-ex/generated-artifacts
 | 
			
		||||
/contracts/zero-ex/test/generated-artifacts
 | 
			
		||||
/contracts/treasury/generated-wrappers
 | 
			
		||||
/contracts/treasury/test/generated-wrappers
 | 
			
		||||
/contracts/treasury/generated-artifacts
 | 
			
		||||
/contracts/treasury/test/generated-artifacts
 | 
			
		||||
/contracts/staking/build/
 | 
			
		||||
/contracts/coordinator/build/
 | 
			
		||||
/contracts/exchange/build/
 | 
			
		||||
/contracts/asset-proxy/build/
 | 
			
		||||
/contracts/multisig/build/
 | 
			
		||||
/contracts/utils/build/
 | 
			
		||||
/contracts/exchange-libs/build/
 | 
			
		||||
/contracts/erc20/build/
 | 
			
		||||
/contracts/erc721/build/
 | 
			
		||||
/contracts/erc1155/build/
 | 
			
		||||
/contracts/extensions/build/
 | 
			
		||||
/contracts/exchange-forwarder/build/
 | 
			
		||||
/packages/asset-swapper/generated-artifacts
 | 
			
		||||
/packages/asset-swapper/generated-wrappers
 | 
			
		||||
/packages/asset-swapper/test/generated-artifacts
 | 
			
		||||
/packages/asset-swapper/test/generated-wrappers
 | 
			
		||||
/packages/abi-gen/test-cli/output
 | 
			
		||||
/packages/json-schemas/schemas
 | 
			
		||||
/python-packages/json_schemas/src/zero_ex/json_schemas/schemas
 | 
			
		||||
/packages/sra-spec/public/
 | 
			
		||||
/packages/dev-tools-pages/ts/**/data.json
 | 
			
		||||
package.json
 | 
			
		||||
packages/*/docs
 | 
			
		||||
docs/
 | 
			
		||||
*.sol
 | 
			
		||||
scripts/postpublish_utils.js
 | 
			
		||||
packages/sol-coverage/test/fixtures/artifacts
 | 
			
		||||
.pytest_cache
 | 
			
		||||
.mypy_cache
 | 
			
		||||
.tox
 | 
			
		||||
packages/abi-gen/test-cli/fixtures/artifacts/AbiGenDummy.json
 | 
			
		||||
packages/abi-gen/test-cli/fixtures/artifacts/LibDummy.json
 | 
			
		||||
packages/abi-gen/test-cli/fixtures/artifacts/TestLibDummy.json
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "printWidth": 120,
 | 
			
		||||
    "tabWidth": 4,
 | 
			
		||||
    "singleQuote": true,
 | 
			
		||||
    "trailingComma": "all",
 | 
			
		||||
    "bracketSpacing": true,
 | 
			
		||||
    "arrowParens": "avoid"
 | 
			
		||||
    "printWidth": 120,
 | 
			
		||||
    "trailingComma": all,
 | 
			
		||||
    "singleQuote": true
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,23 +0,0 @@
 | 
			
		||||
# Read the Docs configuration file
 | 
			
		||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
 | 
			
		||||
 | 
			
		||||
# Required
 | 
			
		||||
version: 2
 | 
			
		||||
 | 
			
		||||
# Build documentation in the docs/ directory with Sphinx
 | 
			
		||||
sphinx:
 | 
			
		||||
  configuration: docs/conf.py
 | 
			
		||||
 | 
			
		||||
# Build documentation with MkDocs
 | 
			
		||||
#mkdocs:
 | 
			
		||||
#  configuration: mkdocs.yml
 | 
			
		||||
 | 
			
		||||
# Optionally build your docs in additional formats such as PDF
 | 
			
		||||
#formats:
 | 
			
		||||
#  - pdf
 | 
			
		||||
 | 
			
		||||
# Optionally set the version of Python and requirements required to build your docs
 | 
			
		||||
python:
 | 
			
		||||
  version: 3.7
 | 
			
		||||
  install:
 | 
			
		||||
    - requirements: docs/requirements.txt
 | 
			
		||||
							
								
								
									
										39
									
								
								CODEOWNERS
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								CODEOWNERS
									
									
									
									
									
								
							@@ -1,20 +1,39 @@
 | 
			
		||||
# 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
 | 
			
		||||
 | 
			
		||||
packages/asset-swapper/ @dekz @dextracker @kyu-c
 | 
			
		||||
# Website
 | 
			
		||||
packages/asset-buyer/  @BMillman19 @fragosti @steveklebanoff
 | 
			
		||||
packages/instant/  @BMillman19 @fragosti @steveklebanoff
 | 
			
		||||
packages/website/  @BMillman19 @fragosti @fabioberger @steveklebanoff
 | 
			
		||||
 | 
			
		||||
# Dev tools & setup
 | 
			
		||||
 | 
			
		||||
.circleci/ @dekz
 | 
			
		||||
packages/contract-addresses/ @dekz @dextracker @kyu-c
 | 
			
		||||
packages/contract-artifacts/ @dekz
 | 
			
		||||
packages/protocol-utils/ @dekz
 | 
			
		||||
.circleci/ @LogvinovLeon
 | 
			
		||||
packages/abi-gen/ @feuGeneA
 | 
			
		||||
packages/base-contract/ @xianny
 | 
			
		||||
packages/connect/ @fragosti 
 | 
			
		||||
packages/abi-gen-templates/ @feuGeneA @xianny
 | 
			
		||||
packages/contract-addresses/ @albrow
 | 
			
		||||
packages/contract-artifacts/ @albrow
 | 
			
		||||
packages/dev-utils/ @LogvinovLeon @fabioberger
 | 
			
		||||
packages/devnet/ @albrow
 | 
			
		||||
packages/ethereum-types/ @LogvinovLeon
 | 
			
		||||
packages/monorepo-scripts/ @fabioberger
 | 
			
		||||
packages/order-utils/ @fabioberger @LogvinovLeon 
 | 
			
		||||
packages/python-contract-wrappers/ @feuGeneA
 | 
			
		||||
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
 | 
			
		||||
packages/utils/ @hysz
 | 
			
		||||
 | 
			
		||||
# Protocol/smart contracts
 | 
			
		||||
 | 
			
		||||
contracts/ @dekz @dextracker
 | 
			
		||||
contracts/ @abandeali1 @hysz
 | 
			
		||||
 
 | 
			
		||||
@@ -4,9 +4,9 @@ We welcome contributions from anyone on the internet and are grateful for even t
 | 
			
		||||
 | 
			
		||||
### Getting started
 | 
			
		||||
 | 
			
		||||
1.  Fork `0xproject/0x-tools`
 | 
			
		||||
1.  Fork `0xproject/0x-monorepo`
 | 
			
		||||
2.  Clone your fork
 | 
			
		||||
3.  Follow the [installation & build steps](https://github.com/0xProject/0x-tools#install-dependencies) in the repo's top-level README.
 | 
			
		||||
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))
 | 
			
		||||
 | 
			
		||||
@@ -29,9 +29,9 @@ ALL PRs should be opened against `development`.
 | 
			
		||||
 | 
			
		||||
Branch names should be prefixed with `fix`, `feature` or `refactor`.
 | 
			
		||||
 | 
			
		||||
-   e.g `fix/missing-import`
 | 
			
		||||
-   e.g `fix/broken-wiki-link`
 | 
			
		||||
-   If the PR only edits a single package, add it's name too
 | 
			
		||||
    -   e.g `fix/subproviders/missing-import`
 | 
			
		||||
    -   e.g `fix/website/broken-wiki-link`
 | 
			
		||||
 | 
			
		||||
### CHANGELOGs
 | 
			
		||||
 | 
			
		||||
@@ -55,15 +55,15 @@ If an entry without a `timestamp` already exists, this means other changes have
 | 
			
		||||
 | 
			
		||||
### 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.
 | 
			
		||||
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-tools/tree/development/packages/tslint-config) to keep our code-style consistent.
 | 
			
		||||
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-tools/tree/development/packages/tslint-config) package. All other packages have it as a dependency.
 | 
			
		||||
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:
 | 
			
		||||
 | 
			
		||||
@@ -89,17 +89,17 @@ A few of our coding conventions are not yet enforced by the linter/auto-formatte
 | 
			
		||||
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.  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-tools`, but when running the check against your fork the token needs to match your repo's name `your-username/0x-tools`.
 | 
			
		||||
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`.
 | 
			
		||||
 | 
			
		||||
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-tools, so you can ignore all of the instruction/explanation given on the page with the `Start Building` button.)
 | 
			
		||||
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.
 | 
			
		||||
 
 | 
			
		||||
@@ -49,6 +49,7 @@
 | 
			
		||||
| Package | Version |
 | 
			
		||||
| ------: | :------ |
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<!-- For example:
 | 
			
		||||
|             `0x.js` | 2.0.4   |
 | 
			
		||||
| `Exchange Contract` | v2      |
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							@@ -1,4 +1,4 @@
 | 
			
		||||
Copyright 2020 ZeroEx Labs
 | 
			
		||||
Copyright 2017 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										107
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								README.md
									
									
									
									
									
								
							@@ -2,43 +2,110 @@
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
[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://protocol.0x.org/).
 | 
			
		||||
[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).
 | 
			
		||||
 | 
			
		||||
This repository is a monorepo including the 0x protocol smart contracts and numerous developer tools. Each public sub-package is independently published to NPM.
 | 
			
		||||
 | 
			
		||||
[website-url]: https://0x.org
 | 
			
		||||
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.
 | 
			
		||||
 | 
			
		||||
[](https://circleci.com/gh/0xProject/protocool)
 | 
			
		||||
[website-url]: https://0xproject.com
 | 
			
		||||
[whitepaper-url]: https://0xproject.com/pdfs/0x_white_paper.pdf
 | 
			
		||||
[dev-mailing-list-url]: http://eepurl.com/dx4cPf
 | 
			
		||||
 | 
			
		||||
[](https://circleci.com/gh/0xProject/0x-monorepo)
 | 
			
		||||
[](https://coveralls.io/github/0xProject/0x-monorepo?branch=development)
 | 
			
		||||
[](https://discordapp.com/invite/d3FTX3M)
 | 
			
		||||
[](https://chat.0xproject.com)
 | 
			
		||||
[](https://gitter.im/0xProject/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 | 
			
		||||
[](https://opensource.org/licenses/Apache-2.0)
 | 
			
		||||
 | 
			
		||||
## Packages
 | 
			
		||||
 | 
			
		||||
Visit our [developer portal](https://0x.org/docs/) for a comprehensive list of core & community maintained packages. All packages maintained with this monorepo are listed below.
 | 
			
		||||
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.
 | 
			
		||||
 | 
			
		||||
### Python Packages
 | 
			
		||||
 | 
			
		||||
| Package                                                        | Version                                                                                                             | Description                                                                                       |
 | 
			
		||||
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
 | 
			
		||||
| [`0x-contract-addresses`](/python-packages/contract_addresses) | [](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) | [](https://pypi.org/project/0x-contract-artifacts/) | 0x smart contract compilation artifacts                                                           |
 | 
			
		||||
| [`0x-contract-wrappers`](/python-packages/contract_wrappers)   | [](https://pypi.org/project/0x-contract-wrappers/)   | 0x smart contract wrappers                                                                        |
 | 
			
		||||
| [`0x-json-schemas`](/python-packages/json_schemas)             | [](https://pypi.org/project/0x-json-schemas/)             | 0x-related JSON schemas                                                                           |
 | 
			
		||||
| [`0x-order-utils`](/python-packages/order_utils)               | [](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)                 | [](https://pypi.org/project/0x-sra-client/)                 | A Python client for interacting with servers conforming to the Standard Relayer API specification |
 | 
			
		||||
 | 
			
		||||
### Solidity Packages
 | 
			
		||||
 | 
			
		||||
These packages are all under development. See [/contracts/README.md](/contracts/README.md) for a list of deployed packages.
 | 
			
		||||
 | 
			
		||||
| Package                                                             | Version                                                                                                                                     | Description                                                                                                                                                                                                                                           |
 | 
			
		||||
| --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
 | 
			
		||||
| [`@0x/contracts-zero-ex`](/contracts/zero-ex)       | [](https://www.npmjs.com/package/@0x/contracts-zero-ex)       | The contracts used for settling trades within the protocol           |
 | 
			
		||||
| ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
 | 
			
		||||
| [`@0x/contracts-asset-proxy`](/contracts/asset-proxy)               | [](https://www.npmjs.com/package/@0x/contracts-asset-proxy)               | [`AssetProxy`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxy) contracts used within the protocol                                                                                               |
 | 
			
		||||
| [`@0x/contracts-erc20`](/contracts/erc20)                           | [](https://www.npmjs.com/package/@0x/contracts-erc20)                           | Implementations of various ERC20 tokens                                                                                                                                                                                                               |
 | 
			
		||||
| [`@0x/contracts-test-utils`](/contracts/test-utils) | [](https://www.npmjs.com/package/@0x/contracts-test-utils) | TypeScript/Javascript shared utilities used for testing contracts    |
 | 
			
		||||
| [`@0x/contracts-erc721`](/contracts/erc721)                         | [](https://www.npmjs.com/package/@0x/contracts-erc721)                         | Implementations of various ERC721 tokens                                                                                                                                                                                                              |
 | 
			
		||||
| [`@0x/contracts-erc1155`](/contracts/erc1155)                       | [](https://www.npmjs.com/package/@0x/contracts-erc1155)                       | Implementations of various ERC1155 tokens                                                                                                                                                                                                             |
 | 
			
		||||
| [`@0x/contracts-exchange`](/contracts/exchange)                     | [](https://www.npmjs.com/package/@0x/contracts-exchange)                     | The [`Exchange`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#exchange) contract used for settling trades within the protocol                                                                            |
 | 
			
		||||
| [`@0x/contracts-exchange-forwarder`](/contracts/exchange-forwarder) | [](https://www.npmjs.com/package/@0x/contracts-exchange-forwarder) | A [`Forwarder`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/forwarder-specification.md) contract used to simplify UX for interacting with the protocol                                                                      |
 | 
			
		||||
| [`@0x/contracts-exchange-libs`](/contracts/exchange-libs)           | [](https://www.npmjs.com/package/@0x/contracts-exchange-libs)           | Protocol specific libraries used within the [`Exchange`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#exchange) contract                                                                                 |
 | 
			
		||||
| [`@0x/contracts-extensions`](/contracts/extensions)                 | [](https://www.npmjs.com/package/@0x/contracts-extensions)                 | Contracts that interact with and extend the functionality of the core protocol                                                                                                                                                                        |
 | 
			
		||||
| [`@0x/contracts-multisig`](/contracts/multisig)                     | [](https://www.npmjs.com/package/@0x/contracts-multisig)                     | Various implementations of multisignature wallets, including the [`AssetProxyOwner`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxyowner) contract that has permissions to upgrade the protocol |
 | 
			
		||||
| [`@0x/contracts-test-utils`](/contracts/test-utils)                 | [](https://www.npmjs.com/package/@0x/contracts-test-utils)                 | Typescript/Javascript shared utilities used for testing contracts                                                                                                                                                                                     |
 | 
			
		||||
| [`@0x/contracts-utils`](/contracts/utils)                           | [](https://www.npmjs.com/package/@0x/contracts-utils)                           | Generic libraries and utilities used throughout all of the contracts                                                                                                                                                                                  |
 | 
			
		||||
| [`@0x/contracts-coordinator`](/contracts/coordinator)               | [](https://www.npmjs.com/package/@0x/contracts-coordinator)               | A contract that allows users to execute 0x transactions with permission from a Coordinator                                                                                                                                                            |
 | 
			
		||||
| [`@0x/contracts-dev-utils`](/contracts/dev-utils)                   | [](https://www.npmjs.com/package/@0x/contracts-dev-utils)                   | A contract contains utility functions for developers (such as validating many orders using a single eth_call)                                                                                                                                         |
 | 
			
		||||
 | 
			
		||||
### TypeScript/Javascript Packages
 | 
			
		||||
### Typescript/Javascript Packages
 | 
			
		||||
 | 
			
		||||
#### 0x-specific packages
 | 
			
		||||
 | 
			
		||||
| Package                                                  | Version                                                                                                                 | Description                                                                                       |
 | 
			
		||||
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
 | 
			
		||||
| [`@0x/asset-swapper`](/packages/asset-swapper)           | [](https://www.npmjs.com/package/@0x/asset-swapper)           | Package used to find and create aggregated swaps                                               |
 | 
			
		||||
| [`@0x/protocol-utils`](/packages/protocol-utils)         | [](https://www.npmjs.com/package/@0x/protocol-utils)         | A set of utilities for generating, parsing, signing and validating 0x orders                   |
 | 
			
		||||
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
 | 
			
		||||
| [`0x.js`](/packages/0x.js)                               | [](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) | [](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)   | [](https://www.npmjs.com/package/@0x/contract-wrappers)   | JS/TS wrappers for interacting with the 0x smart contracts                                        |
 | 
			
		||||
| [`@0x/contract-artifacts`](/packages/contract-artifacts) | [](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts                                                        |  |
 | 
			
		||||
| [`@0x/order-utils`](/packages/order-utils)               | [](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)             | [](https://www.npmjs.com/package/@0x/json-schemas)             | 0x-related JSON schemas                                                                           |  |
 | 
			
		||||
| [`@0x/migrations`](/packages/migrations)                 | [](https://www.npmjs.com/package/@0x/migrations)                 | Migration tool for deploying 0x smart contracts on private testnets                               |
 | 
			
		||||
| [`@0x/contract-artifacts`](/packages/contract-artifacts) | [](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts                                                           |
 | 
			
		||||
| [`@0x/abi-gen-wrappers`](/packages/abi-gen-wrappers)     | [](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)                     | [](https://www.npmjs.com/package/@0x/sra-spec)                     | OpenAPI specification for the Standard Relayer API                                                |
 | 
			
		||||
| [`@0x/connect`](/packages/connect)                       | [](https://www.npmjs.com/package/@0x/connect)                       | An HTTP/WS client for interacting with the Standard Relayer API                                   |
 | 
			
		||||
| [`@0x/asset-buyer`](/packages/asset-buyer)               | [](https://www.npmjs.com/package/@0x/asset-buyer)               | Convenience package for discovering and buying assets with Ether                                  |
 | 
			
		||||
| [`@0x/asset-swapper`](/packages/asset-swapper)           | [](https://www.npmjs.com/package/@0x/asset-swapper)           | Convenience package for discovering and performing swaps for any ERC20 Assets                     |
 | 
			
		||||
 | 
			
		||||
#### Ethereum tooling
 | 
			
		||||
 | 
			
		||||
| Package                                      | Version                                                                                                     | Description                                                                                                                                                                             |
 | 
			
		||||
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
 | 
			
		||||
| [`@0x/web3-wrapper`](/packages/web3-wrapper) | [](https://www.npmjs.com/package/@0x/web3-wrapper) | An Ethereum JSON RPC client                                                                                                                                                             |
 | 
			
		||||
| [`@0x/sol-compiler`](/packages/sol-compiler) | [](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) | [](https://www.npmjs.com/package/@0x/sol-coverage) | A solidity test coverage tool                                                                                                                                                           |
 | 
			
		||||
| [`@0x/sol-profiler`](/packages/sol-profiler) | [](https://www.npmjs.com/package/@0x/sol-profiler) | A solidity gas cost profiler                                                                                                                                                            |
 | 
			
		||||
| [`@0x/sol-trace`](/packages/sol-trace)       | [](https://www.npmjs.com/package/@0x/sol-trace)       | A solidity stack trace tool                                                                                                                                                             |
 | 
			
		||||
| [`@0x/sol-resolver`](/packages/sol-resolver) | [](https://www.npmjs.com/package/@0x/sol-resolver) | Import resolver for smart contracts dependencies                                                                                                                                        |
 | 
			
		||||
| [`@0x/subproviders`](/packages/subproviders) | [](https://www.npmjs.com/package/@0x/subproviders) | Web3 provider middlewares (e.g. LedgerSubprovider)                                                                                                                                      |
 | 
			
		||||
| [`@0x/sol-doc`](/packages/sol-doc)           | [](https://www.npmjs.com/package/@0x/sol-doc)           | Solidity documentation generator                                                                                                                                                        |
 | 
			
		||||
 | 
			
		||||
#### Utilities
 | 
			
		||||
 | 
			
		||||
| Package                                                  | Version                                                                                                                 | Description                                                     |
 | 
			
		||||
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
 | 
			
		||||
| [`@0x/abi-gen`](/packages/abi-gen)                       | [](https://www.npmjs.com/package/@0x/abi-gen)                       | Tool to generate TS wrappers from smart contract ABIs           |
 | 
			
		||||
| [`@0x/tslint-config`](/packages/tslint-config)           | [](https://www.npmjs.com/package/@0x/tslint-config)           | Custom TSLint rules used by the 0x core team                    |
 | 
			
		||||
| [`@0x/types`](/packages/types)                           | [](https://www.npmjs.com/package/@0x/types)                           | Shared type declarations                                        |
 | 
			
		||||
| [`@0x/typescript-typings`](/packages/typescript-typings) | [](https://www.npmjs.com/package/@0x/typescript-typings) | Repository of types for external packages                       |
 | 
			
		||||
| [`@0x/utils`](/packages/utils)                           | [](https://www.npmjs.com/package/@0x/utils)                           | Shared utilities                                                |
 | 
			
		||||
| [`@0x/assert`](/packages/assert)                         | [](https://www.npmjs.com/package/@0x/assert)                         | Type and schema assertions used by our packages                 |
 | 
			
		||||
| [`@0x/base-contract`](/packages/base-contract)           | [](https://www.npmjs.com/package/@0x/base-contract)           | BaseContract used by auto-generated `abi-gen` wrapper contracts |
 | 
			
		||||
| [`@0x/dev-utils`](/packages/dev-utils)                   | [](https://www.npmjs.com/package/@0x/dev-utils)                   | Dev utils to be shared across 0x packages                       |
 | 
			
		||||
| [`@0x/fill-scenarios`](/packages/fill-scenarios)         | [](https://www.npmjs.com/package/@0x/fill-scenarios)         | 0x order fill scenario generator                                |
 | 
			
		||||
 | 
			
		||||
#### Private Packages
 | 
			
		||||
 | 
			
		||||
| Package                                            | Description                                                                      |
 | 
			
		||||
| -------------------------------------------------- | -------------------------------------------------------------------------------- |
 | 
			
		||||
| [`@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                                                                       |
 | 
			
		||||
 | 
			
		||||
## Usage
 | 
			
		||||
 | 
			
		||||
@@ -71,6 +138,8 @@ Then install dependencies
 | 
			
		||||
yarn install
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
You will also need to have Python 3 installed, in order to build and run the tests of `abi-gen`'s command-line interface, which is integrated with the yarn build, yarn test, and yarn lint commands described below. More specifically, your local pip should resolve to the Python 3 version of pip, not a Python 2.x version.
 | 
			
		||||
 | 
			
		||||
### Build
 | 
			
		||||
 | 
			
		||||
To build all packages:
 | 
			
		||||
@@ -82,7 +151,7 @@ yarn build
 | 
			
		||||
To build a specific package:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
PKG=@0x/asset-swapper yarn build
 | 
			
		||||
PKG=@0x/web3-wrapper yarn build
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
To build all contracts packages:
 | 
			
		||||
@@ -105,7 +174,7 @@ To watch a specific package and all it's dependent packages:
 | 
			
		||||
PKG=[NPM_PACKAGE_NAME] yarn watch
 | 
			
		||||
 | 
			
		||||
e.g
 | 
			
		||||
PKG=@0x/asset-swapper yarn watch
 | 
			
		||||
PKG=@0x/web3-wrapper yarn watch
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Clean
 | 
			
		||||
@@ -119,7 +188,7 @@ yarn clean
 | 
			
		||||
Clean a specific package
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
PKG=@0x/asset-swapper yarn clean
 | 
			
		||||
PKG=0x.js yarn clean
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Rebuild
 | 
			
		||||
@@ -133,7 +202,7 @@ yarn rebuild
 | 
			
		||||
To re-build (clean & build) a specific package & it's deps:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
PKG=@0x/asset-swapper yarn rebuild
 | 
			
		||||
PKG=0x.js yarn rebuild
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Lint
 | 
			
		||||
@@ -147,7 +216,7 @@ yarn lint
 | 
			
		||||
Lint a specific package:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
PKG=@0x/asset-swapper yarn lint
 | 
			
		||||
PKG=0x.js yarn lint
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Run Tests
 | 
			
		||||
@@ -161,7 +230,7 @@ yarn test
 | 
			
		||||
Run a specific package's test:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
PKG=@0x/asset-swapper yarn test
 | 
			
		||||
PKG=@0x/web3-wrapper yarn test
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Run all contracts packages tests:
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,6 @@
 | 
			
		||||
        "quotes": ["error", "double"],
 | 
			
		||||
        "separate-by-one-line-in-contract": "error",
 | 
			
		||||
        "space-after-comma": "error",
 | 
			
		||||
        "statement-indent": "error",
 | 
			
		||||
        "no-empty-blocks": false
 | 
			
		||||
        "statement-indent": "error"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,16 @@
 | 
			
		||||
#### Deployed Contract Packages
 | 
			
		||||
 | 
			
		||||
| Contract        | Package                                                             | Version                                                                          | Git Tag                                                                                                                                |
 | 
			
		||||
| --------------- | ------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
 | 
			
		||||
| AssetProxyOwner | [`@0x/contracts-multisig`](/contracts/multisig)                     | [v1.0.2](https://www.npmjs.com/package/@0x/contracts-multisig/v/1.0.2)           | [@0x/contracts-multisig@1.0.2](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-multisig@1.0.2)                     |
 | 
			
		||||
| ERC20Proxy      | [`@0x/contracts-asset-proxy`](/contracts/asset-proxy)               | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-asset-proxy/v/1.0.1)        | [@0x/contracts-asset-proxy@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-asset-proxy@1.0.1)               |
 | 
			
		||||
| ERC721Proxy     | [`@0x/contracts-asset-proxy`](/contracts/asset-proxy)               | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-asset-proxy/v/1.0.1)        | [@0x/contracts-asset-proxy@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-asset-proxy@1.0.1)               |
 | 
			
		||||
| Exchange        | [`@0x/contracts-exchange`](/contracts/exchange)                     | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-exchange/v/1.0.1)           | [@0x/contracts-exchange@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-exchange@1.0.1)                     |
 | 
			
		||||
| DutchAuction    | [`@0x/contracts-extensions`](/contracts/extensions)                 | [v1.0.2](https://www.npmjs.com/package/@0x/contracts-extensions/v/1.0.2)         | [@0x/contracts-extensions@1.0.2](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-extensions@1.0.2)                 |
 | 
			
		||||
| Forwarder       | [`@0x/contracts-exchange-forwarder`](/contracts/exchange-forwarder) | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-exchange-forwarder/v/1.0.1) | [@0x/contracts-exchange-forwarder@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-exchange-forwarder@1.0.1) |
 | 
			
		||||
| MultiAssetProxy | [`@0x/contracts-asset-proxy`](/contracts/asset-proxy)               | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-asset-proxy/v/1.0.1)        | [@0x/contracts-asset-proxy@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-asset-proxy@1.0.1)               |
 | 
			
		||||
| ZRXToken        | [`@0x/contracts-erc20`](/contracts/erc20)                           | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-erc20/v/1.0.1)              | [@0x/contracts-erc20@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-erc20@1.0.1)                           |
 | 
			
		||||
 | 
			
		||||
#### Development
 | 
			
		||||
 | 
			
		||||
Building solidity files will update the contract artifact in `{package-name}/generated-artifacts/{contract}.json`, but does not automatically update the `contract-artifacts` or `contract-wrappers` packages, which are generated from the artifact JSON. See `contract-artifacts/README.md` for instructions on updating these packages.
 | 
			
		||||
Building solidity files will update the contract artifact in `{package-name}/generated-artifacts/{contract}.json`, but does not automatically update the `abi-gen-wrappers` package, which are generated from the artifact JSON. To ensure consistency, clean and rebuild `abi-gen-wrappers` after any changes to the artifact JSON.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										48
									
								
								contracts/TESTING.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								contracts/TESTING.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
# 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.
 | 
			
		||||
							
								
								
									
										243
									
								
								contracts/asset-proxy/CHANGELOG.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										243
									
								
								contracts/asset-proxy/CHANGELOG.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,243 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1566446343,
 | 
			
		||||
        "version": "2.2.6",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1565296576,
 | 
			
		||||
        "version": "2.2.5",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "2.2.4",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Updated calls to <contract wrapper>.deployFrom0xArtifactAsync to include artifact dependencies.",
 | 
			
		||||
                "pr": 1995
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1564607468
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1563957393,
 | 
			
		||||
        "version": "2.2.3",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1563193019,
 | 
			
		||||
        "version": "2.2.2",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1563047529,
 | 
			
		||||
        "version": "2.2.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "2.2.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add `LibAssetProxyIds` contract",
 | 
			
		||||
                "pr": 1835
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Updated ERC1155 Asset Proxy. Less optimization. More explicit handling of edge cases.",
 | 
			
		||||
                "pr": 1852
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Implement StaticCallProxy",
 | 
			
		||||
                "pr": 1863
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1563006338
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1558712885,
 | 
			
		||||
        "version": "2.1.5",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1557961111,
 | 
			
		||||
        "version": "2.1.4",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1557799313,
 | 
			
		||||
        "version": "2.1.3",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "2.1.2",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Update tests to use contract-built-in `awaitTransactionSuccessAsync`",
 | 
			
		||||
                "pr": 1797
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1557507213
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "2.1.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1554997931
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "2.1.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Run Web3ProviderEngine without excess block polling",
 | 
			
		||||
                "pr": 1695
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1553183790
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "2.0.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Do not reexport external dependencies",
 | 
			
		||||
                "pr": 1682
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add ERC1155Proxy",
 | 
			
		||||
                "pr": 1661
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Bumped solidity version to ^0.5.5",
 | 
			
		||||
                "pr": 1701
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Integration testing for ERC1155Proxy",
 | 
			
		||||
                "pr": 1673
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1553091633
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1551479279,
 | 
			
		||||
        "version": "1.0.9",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1551299797,
 | 
			
		||||
        "version": "1.0.8",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1551220833,
 | 
			
		||||
        "version": "1.0.7",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1551130135,
 | 
			
		||||
        "version": "1.0.6",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1549733923,
 | 
			
		||||
        "version": "1.0.5",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "1.0.4",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1549547375
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "1.0.3",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Fake publish to enable pinning"
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1549504360
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1549452781,
 | 
			
		||||
        "version": "1.0.2",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1549373905,
 | 
			
		||||
        "version": "1.0.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "1.0.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Move all AssetProxy contracts out of contracts-protocol to new package",
 | 
			
		||||
                "pr": 1539
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    }
 | 
			
		||||
]
 | 
			
		||||
							
								
								
									
										107
									
								
								contracts/asset-proxy/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								contracts/asset-proxy/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
			
		||||
<!--
 | 
			
		||||
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.6 - _August 22, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.2.5 - _August 8, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.2.4 - _July 31, 2019_
 | 
			
		||||
 | 
			
		||||
    * Updated calls to <contract wrapper>.deployFrom0xArtifactAsync to include artifact dependencies. (#1995)
 | 
			
		||||
 | 
			
		||||
## v2.2.3 - _July 24, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.2.2 - _July 15, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.2.1 - _July 13, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.2.0 - _July 13, 2019_
 | 
			
		||||
 | 
			
		||||
    * Add `LibAssetProxyIds` contract (#1835)
 | 
			
		||||
    * Updated ERC1155 Asset Proxy. Less optimization. More explicit handling of edge cases. (#1852)
 | 
			
		||||
    * Implement StaticCallProxy (#1863)
 | 
			
		||||
 | 
			
		||||
## v2.1.5 - _May 24, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.1.4 - _May 15, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.1.3 - _May 14, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.1.2 - _May 10, 2019_
 | 
			
		||||
 | 
			
		||||
    * Update tests to use contract-built-in `awaitTransactionSuccessAsync` (#1797)
 | 
			
		||||
 | 
			
		||||
## v2.1.1 - _April 11, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.1.0 - _March 21, 2019_
 | 
			
		||||
 | 
			
		||||
    * Run Web3ProviderEngine without excess block polling (#1695)
 | 
			
		||||
 | 
			
		||||
## v2.0.0 - _March 20, 2019_
 | 
			
		||||
 | 
			
		||||
    * Do not reexport external dependencies (#1682)
 | 
			
		||||
    * Add ERC1155Proxy (#1661)
 | 
			
		||||
    * Bumped solidity version to ^0.5.5 (#1701)
 | 
			
		||||
    * Integration testing for ERC1155Proxy (#1673)
 | 
			
		||||
 | 
			
		||||
## v1.0.9 - _March 1, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.0.8 - _February 27, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.0.7 - _February 26, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.0.6 - _February 25, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.0.5 - _February 9, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.0.4 - _February 7, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.0.3 - _February 7, 2019_
 | 
			
		||||
 | 
			
		||||
    * Fake publish to enable pinning
 | 
			
		||||
 | 
			
		||||
## v1.0.2 - _February 6, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.0.1 - _February 5, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.0.0 - _Invalid date_
 | 
			
		||||
 | 
			
		||||
    * Move all AssetProxy contracts out of contracts-protocol to new package (#1539)
 | 
			
		||||
							
								
								
									
										47
									
								
								contracts/asset-proxy/DEPLOYS.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								contracts/asset-proxy/DEPLOYS.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "name": "MultiAssetProxy",
 | 
			
		||||
        "version": "1.0.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add MultiAssetProxy implementation",
 | 
			
		||||
                "pr": 1224,
 | 
			
		||||
                "networks": {
 | 
			
		||||
                    "3": "0xab8fbd189c569ccdee3a4d929bb7f557be4028f6",
 | 
			
		||||
                    "4": "0xb34cde0ad3a83d04abebc0b66e75196f22216621",
 | 
			
		||||
                    "42": "0xf6313a772c222f51c28f2304c0703b8cf5428fd8"
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "name": "ERC20Proxy",
 | 
			
		||||
        "version": "1.0.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "protocol v2 deploy",
 | 
			
		||||
                "networks": {
 | 
			
		||||
                    "1": "0x2240dab907db71e64d3e0dba4800c83b5c502d4e",
 | 
			
		||||
                    "3": "0xb1408f4c245a23c31b98d2c626777d4c0d766caa",
 | 
			
		||||
                    "4": "0x3e809c563c15a295e832e37053798ddc8d6c8dab",
 | 
			
		||||
                    "42": "0xf1ec01d6236d3cd881a0bf0130ea25fe4234003e"
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "name": "ERC721Proxy",
 | 
			
		||||
        "version": "1.0.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "protocol v2 deploy",
 | 
			
		||||
                "networks": {
 | 
			
		||||
                    "1": "0x208e41fb445f1bb1b6780d58356e81405f3e6127",
 | 
			
		||||
                    "3": "0xe654aac058bfbf9f83fcaee7793311dd82f6ddb4",
 | 
			
		||||
                    "4": "0x8e1ff02637cb5e39f2fa36c14706aa348b065b09",
 | 
			
		||||
                    "42": "0x2a9127c745688a165106c11cd4d647d2220af821"
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    }
 | 
			
		||||
]
 | 
			
		||||
							
								
								
									
										73
									
								
								contracts/asset-proxy/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								contracts/asset-proxy/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
## AssetProxy
 | 
			
		||||
 | 
			
		||||
This package contains the implementations of all of the [`AssetProxy`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxy) contracts available within the 0x protocol. These contracts are responsible for decoding the `assetData` sent to them and performing the actual transfer of assets. Addresses of the deployed contracts can be found in the 0x [wiki](https://0xproject.com/wiki#Deployed-Addresses) or the [DEPLOYS](./DEPLOYS.json) file within this package.
 | 
			
		||||
 | 
			
		||||
## Installation
 | 
			
		||||
 | 
			
		||||
**Install**
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npm install @0x/contracts-asset-proxy --save
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 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-asset-proxy yarn build
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Or continuously rebuild on change:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
PKG=@0x/contracts-asset-proxy 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).
 | 
			
		||||
							
								
								
									
										38
									
								
								contracts/asset-proxy/compiler.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								contracts/asset-proxy/compiler.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
{
 | 
			
		||||
    "artifactsDir": "./generated-artifacts",
 | 
			
		||||
    "contractsDir": "./contracts",
 | 
			
		||||
    "useDockerisedSolc": false,
 | 
			
		||||
    "isOfflineMode": false,
 | 
			
		||||
    "compilerSettings": {
 | 
			
		||||
        "evmVersion": "constantinople",
 | 
			
		||||
        "optimizer": {
 | 
			
		||||
            "enabled": true,
 | 
			
		||||
            "runs": 1000000,
 | 
			
		||||
            "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true }
 | 
			
		||||
        },
 | 
			
		||||
        "outputSelection": {
 | 
			
		||||
            "*": {
 | 
			
		||||
                "*": [
 | 
			
		||||
                    "abi",
 | 
			
		||||
                    "devdoc",
 | 
			
		||||
                    "evm.bytecode.object",
 | 
			
		||||
                    "evm.bytecode.sourceMap",
 | 
			
		||||
                    "evm.deployedBytecode.object",
 | 
			
		||||
                    "evm.deployedBytecode.sourceMap"
 | 
			
		||||
                ]
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    "contracts": [
 | 
			
		||||
        "src/ERC1155Proxy.sol",
 | 
			
		||||
        "src/ERC20Proxy.sol",
 | 
			
		||||
        "src/ERC721Proxy.sol",
 | 
			
		||||
        "src/MixinAuthorizable.sol",
 | 
			
		||||
        "src/MultiAssetProxy.sol",
 | 
			
		||||
        "src/StaticCallProxy.sol",
 | 
			
		||||
        "src/interfaces/IAssetData.sol",
 | 
			
		||||
        "src/interfaces/IAssetProxy.sol",
 | 
			
		||||
        "src/interfaces/IAuthorizable.sol",
 | 
			
		||||
        "test/TestStaticCallTarget.sol"
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										97
									
								
								contracts/asset-proxy/contracts/src/ERC1155Proxy.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								contracts/asset-proxy/contracts/src/ERC1155Proxy.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,97 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.9;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/SafeMath.sol";
 | 
			
		||||
import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol";
 | 
			
		||||
import "./MixinAuthorizable.sol";
 | 
			
		||||
import "./interfaces/IAssetProxy.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract ERC1155Proxy is
 | 
			
		||||
    MixinAuthorizable,
 | 
			
		||||
    SafeMath,
 | 
			
		||||
    IAssetProxy
 | 
			
		||||
{
 | 
			
		||||
    using LibBytes for bytes;
 | 
			
		||||
 | 
			
		||||
    // Id of this proxy.
 | 
			
		||||
    bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC1155Assets(address,uint256[],uint256[],bytes)"));
 | 
			
		||||
 | 
			
		||||
    /// @dev Transfers batch of ERC1155 assets. Either succeeds or throws.
 | 
			
		||||
    /// @param assetData Byte array encoded with ERC1155 token address, array of ids, array of values, and callback data.
 | 
			
		||||
    /// @param from Address to transfer assets from.
 | 
			
		||||
    /// @param to Address to transfer assets to.
 | 
			
		||||
    /// @param amount Amount that will be multiplied with each element of `assetData.values` to scale the
 | 
			
		||||
    ///        values that will be transferred.
 | 
			
		||||
    function transferFrom(
 | 
			
		||||
        bytes calldata assetData,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        onlyAuthorized
 | 
			
		||||
    {
 | 
			
		||||
        // Decode params from `assetData`
 | 
			
		||||
        // solhint-disable indent
 | 
			
		||||
        (
 | 
			
		||||
            address erc1155TokenAddress,
 | 
			
		||||
            uint256[] memory ids,
 | 
			
		||||
            uint256[] memory values,
 | 
			
		||||
            bytes memory data
 | 
			
		||||
        ) = abi.decode(
 | 
			
		||||
            assetData.sliceDestructive(4, assetData.length),
 | 
			
		||||
            (address, uint256[], uint256[], bytes)
 | 
			
		||||
        );
 | 
			
		||||
        // solhint-enable indent
 | 
			
		||||
 | 
			
		||||
        // Scale values up by `amount`
 | 
			
		||||
        uint256 length = values.length;
 | 
			
		||||
        uint256[] memory scaledValues = new uint256[](length);
 | 
			
		||||
        for (uint256 i = 0; i != length; i++) {
 | 
			
		||||
            // We write the scaled values to an unused location in memory in order
 | 
			
		||||
            // to avoid copying over `ids` or `data`. This is possible if they are
 | 
			
		||||
            // identical to `values` and the offsets for each are pointing to the 
 | 
			
		||||
            // same location in the ABI encoded calldata.
 | 
			
		||||
            scaledValues[i] = safeMul(values[i], amount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Execute `safeBatchTransferFrom` call
 | 
			
		||||
        // Either succeeds or throws
 | 
			
		||||
        IERC1155(erc1155TokenAddress).safeBatchTransferFrom(
 | 
			
		||||
            from,
 | 
			
		||||
            to,
 | 
			
		||||
            ids,
 | 
			
		||||
            scaledValues,
 | 
			
		||||
            data
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets the proxy id associated with the proxy address.
 | 
			
		||||
    /// @return Proxy id.
 | 
			
		||||
    function getProxyId()
 | 
			
		||||
        external
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes4)
 | 
			
		||||
    {
 | 
			
		||||
        return PROXY_ID;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										184
									
								
								contracts/asset-proxy/contracts/src/ERC20Proxy.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								contracts/asset-proxy/contracts/src/ERC20Proxy.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,184 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
 | 
			
		||||
import "./MixinAuthorizable.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract ERC20Proxy is
 | 
			
		||||
    MixinAuthorizable
 | 
			
		||||
{
 | 
			
		||||
    // Id of this proxy.
 | 
			
		||||
    bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC20Token(address)"));
 | 
			
		||||
    
 | 
			
		||||
    // solhint-disable-next-line payable-fallback
 | 
			
		||||
    function () 
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        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
 | 
			
		||||
                let start := mload(64)
 | 
			
		||||
                mstore(start, and(caller, 0xffffffffffffffffffffffffffffffffffffffff))
 | 
			
		||||
                mstore(add(start, 32), authorized_slot)
 | 
			
		||||
 | 
			
		||||
                // Revert if authorized[msg.sender] == false
 | 
			
		||||
                if iszero(sload(keccak256(start, 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 decodeding 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.
 | 
			
		||||
 | 
			
		||||
                // Asset data itself is encoded as follows:
 | 
			
		||||
                //
 | 
			
		||||
                // | Area     | Offset | Length  | Contents                            |
 | 
			
		||||
                // |----------|--------|---------|-------------------------------------|
 | 
			
		||||
                // | Header   | 0      | 4       | function selector                   |
 | 
			
		||||
                // | Params   |        | 1 * 32  | function parameters:                |
 | 
			
		||||
                // |          | 4      | 12 + 20 |   1. token address                  |
 | 
			
		||||
 | 
			
		||||
                // We construct calldata for the `token.transferFrom` ABI.
 | 
			
		||||
                // The layout of this calldata is in the table below.
 | 
			
		||||
                //
 | 
			
		||||
                // | Area     | Offset | Length  | Contents                            |
 | 
			
		||||
                // |----------|--------|---------|-------------------------------------|
 | 
			
		||||
                // | Header   | 0      | 4       | function selector                   |
 | 
			
		||||
                // | Params   |        | 3 * 32  | function parameters:                |
 | 
			
		||||
                // |          | 4      |         |   1. from                           |
 | 
			
		||||
                // |          | 36     |         |   2. to                             |
 | 
			
		||||
                // |          | 68     |         |   3. amount                         |
 | 
			
		||||
 | 
			
		||||
                /////// Read token address from calldata ///////
 | 
			
		||||
                // * The token address is stored in `assetData`.
 | 
			
		||||
                //
 | 
			
		||||
                // * The "offset to assetData" is stored at offset 4 in the calldata (table 1).
 | 
			
		||||
                //   [assetDataOffsetFromParams = calldataload(4)]
 | 
			
		||||
                //
 | 
			
		||||
                // * Notes that the "offset to assetData" is relative to the "Params" area of calldata;
 | 
			
		||||
                //   add 4 bytes to account for the length of the "Header" area (table 1).
 | 
			
		||||
                //   [assetDataOffsetFromHeader = assetDataOffsetFromParams + 4]
 | 
			
		||||
                //
 | 
			
		||||
                // * The "token address" is offset 32+4=36 bytes into "assetData" (tables 1 & 2).
 | 
			
		||||
                //   [tokenOffset = assetDataOffsetFromHeader + 36 = calldataload(4) + 4 + 36]
 | 
			
		||||
                let token := calldataload(add(calldataload(4), 40))
 | 
			
		||||
                
 | 
			
		||||
                /////// Setup Header Area ///////
 | 
			
		||||
                // This area holds the 4-byte `transferFrom` selector.
 | 
			
		||||
                // Any trailing data in transferFromSelector will be
 | 
			
		||||
                // overwritten in the next `mstore` call.
 | 
			
		||||
                mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                
 | 
			
		||||
                /////// Setup Params Area ///////
 | 
			
		||||
                // We copy the fields `from`, `to` and `amount` in bulk
 | 
			
		||||
                // from our own calldata to the new calldata.
 | 
			
		||||
                calldatacopy(4, 36, 96)
 | 
			
		||||
 | 
			
		||||
                /////// Call `token.transferFrom` using the calldata ///////
 | 
			
		||||
                let success := call(
 | 
			
		||||
                    gas,            // forward all gas
 | 
			
		||||
                    token,          // call address of token contract
 | 
			
		||||
                    0,              // don't send any ETH
 | 
			
		||||
                    0,              // pointer to start of input
 | 
			
		||||
                    100,            // length of input
 | 
			
		||||
                    0,              // write output over input
 | 
			
		||||
                    32              // output size should be 32 bytes
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                /////// 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
 | 
			
		||||
                // nonzero 32 bytes value.
 | 
			
		||||
                // So the transfer succeeded if the call succeeded and either
 | 
			
		||||
                // returned nothing, or returned a non-zero 32 byte value. 
 | 
			
		||||
                success := and(success, or(
 | 
			
		||||
                    iszero(returndatasize),
 | 
			
		||||
                    and(
 | 
			
		||||
                        eq(returndatasize, 32),
 | 
			
		||||
                        gt(mload(0), 0)
 | 
			
		||||
                    )
 | 
			
		||||
                ))
 | 
			
		||||
                if success {
 | 
			
		||||
                    return(0, 0)
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                // Revert with `Error("TRANSFER_FAILED")`
 | 
			
		||||
                mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                mstore(64, 0x0000000f5452414e534645525f4641494c454400000000000000000000000000)
 | 
			
		||||
                mstore(96, 0)
 | 
			
		||||
                revert(0, 100)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // 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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										171
									
								
								contracts/asset-proxy/contracts/src/ERC721Proxy.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								contracts/asset-proxy/contracts/src/ERC721Proxy.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,171 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
 | 
			
		||||
import "./MixinAuthorizable.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract ERC721Proxy is
 | 
			
		||||
    MixinAuthorizable
 | 
			
		||||
{
 | 
			
		||||
    // Id of this proxy.
 | 
			
		||||
    bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
 | 
			
		||||
 | 
			
		||||
    // solhint-disable-next-line payable-fallback
 | 
			
		||||
    function () 
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        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
 | 
			
		||||
                let start := mload(64)
 | 
			
		||||
                mstore(start, and(caller, 0xffffffffffffffffffffffffffffffffffffffff))
 | 
			
		||||
                mstore(add(start, 32), authorized_slot)
 | 
			
		||||
 | 
			
		||||
                // Revert if authorized[msg.sender] == false
 | 
			
		||||
                if iszero(sload(keccak256(start, 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 decodeding 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.
 | 
			
		||||
 | 
			
		||||
                // Asset data itself is encoded as follows:
 | 
			
		||||
                //
 | 
			
		||||
                // | Area     | Offset | Length  | Contents                            |
 | 
			
		||||
                // |----------|--------|---------|-------------------------------------|
 | 
			
		||||
                // | Header   | 0      | 4       | function selector                   |
 | 
			
		||||
                // | Params   |        | 2 * 32  | function parameters:                |
 | 
			
		||||
                // |          | 4      | 12 + 20 |   1. token address                  |
 | 
			
		||||
                // |          | 36     |         |   2. tokenId                        |
 | 
			
		||||
                
 | 
			
		||||
                // We construct calldata for the `token.transferFrom` ABI.
 | 
			
		||||
                // The layout of this calldata is in the table below.
 | 
			
		||||
                // 
 | 
			
		||||
                // | Area     | Offset | Length  | Contents                            |
 | 
			
		||||
                // |----------|--------|---------|-------------------------------------|
 | 
			
		||||
                // | Header   | 0      | 4       | function selector                   |
 | 
			
		||||
                // | Params   |        | 3 * 32  | function parameters:                |
 | 
			
		||||
                // |          | 4      |         |   1. from                           |
 | 
			
		||||
                // |          | 36     |         |   2. to                             |
 | 
			
		||||
                // |          | 68     |         |   3. tokenId                        |
 | 
			
		||||
 | 
			
		||||
                // There exists only 1 of each token.
 | 
			
		||||
                // require(amount == 1, "INVALID_AMOUNT")
 | 
			
		||||
                if sub(calldataload(100), 1) {
 | 
			
		||||
                    // Revert with `Error("INVALID_AMOUNT")`
 | 
			
		||||
                    mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                    mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                    mstore(64, 0x0000000e494e56414c49445f414d4f554e540000000000000000000000000000)
 | 
			
		||||
                    mstore(96, 0)
 | 
			
		||||
                    revert(0, 100)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                /////// Setup Header Area ///////
 | 
			
		||||
                // This area holds the 4-byte `transferFrom` selector.
 | 
			
		||||
                // Any trailing data in transferFromSelector will be
 | 
			
		||||
                // overwritten in the next `mstore` call.
 | 
			
		||||
                mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                
 | 
			
		||||
                /////// Setup Params Area ///////
 | 
			
		||||
                // We copy the fields `from` and `to` in bulk
 | 
			
		||||
                // from our own calldata to the new calldata.
 | 
			
		||||
                calldatacopy(4, 36, 64)
 | 
			
		||||
 | 
			
		||||
                // Copy `tokenId` field from our own calldata to the new calldata.
 | 
			
		||||
                let assetDataOffset := calldataload(4)
 | 
			
		||||
                calldatacopy(68, add(assetDataOffset, 72), 32)
 | 
			
		||||
 | 
			
		||||
                /////// Call `token.transferFrom` using the calldata ///////
 | 
			
		||||
                let token := calldataload(add(assetDataOffset, 40))
 | 
			
		||||
                let success := call(
 | 
			
		||||
                    gas,            // forward all gas
 | 
			
		||||
                    token,          // call address of token contract
 | 
			
		||||
                    0,              // don't send any ETH
 | 
			
		||||
                    0,              // pointer to start of input
 | 
			
		||||
                    100,            // length of input
 | 
			
		||||
                    0,              // write output to null
 | 
			
		||||
                    0               // output size is 0 bytes
 | 
			
		||||
                )
 | 
			
		||||
                if success {
 | 
			
		||||
                    return(0, 0)
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                // Revert with `Error("TRANSFER_FAILED")`
 | 
			
		||||
                mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                mstore(64, 0x0000000f5452414e534645525f4641494c454400000000000000000000000000)
 | 
			
		||||
                mstore(96, 0)
 | 
			
		||||
                revert(0, 100)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // 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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,172 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/Ownable.sol";
 | 
			
		||||
import "./mixins/MAssetProxyDispatcher.sol";
 | 
			
		||||
import "./interfaces/IAssetProxy.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract MixinAssetProxyDispatcher is
 | 
			
		||||
    Ownable,
 | 
			
		||||
    MAssetProxyDispatcher
 | 
			
		||||
{
 | 
			
		||||
    // Mapping from Asset Proxy Id's to their respective Asset Proxy
 | 
			
		||||
    mapping (bytes4 => address) public assetProxies;
 | 
			
		||||
 | 
			
		||||
    /// @dev Registers an asset proxy to its asset proxy id.
 | 
			
		||||
    ///      Once an asset proxy is registered, it cannot be unregistered.
 | 
			
		||||
    /// @param assetProxy Address of new asset proxy to register.
 | 
			
		||||
    function registerAssetProxy(address assetProxy)
 | 
			
		||||
        external
 | 
			
		||||
        onlyOwner
 | 
			
		||||
    {
 | 
			
		||||
        // Ensure that no asset proxy exists with current id.
 | 
			
		||||
        bytes4 assetProxyId = IAssetProxy(assetProxy).getProxyId();
 | 
			
		||||
        address currentAssetProxy = assetProxies[assetProxyId];
 | 
			
		||||
        require(
 | 
			
		||||
            currentAssetProxy == address(0),
 | 
			
		||||
            "ASSET_PROXY_ALREADY_EXISTS"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Add asset proxy and log registration.
 | 
			
		||||
        assetProxies[assetProxyId] = assetProxy;
 | 
			
		||||
        emit AssetProxyRegistered(
 | 
			
		||||
            assetProxyId,
 | 
			
		||||
            assetProxy
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets an asset proxy.
 | 
			
		||||
    /// @param assetProxyId Id of the asset proxy.
 | 
			
		||||
    /// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered.
 | 
			
		||||
    function getAssetProxy(bytes4 assetProxyId)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (address)
 | 
			
		||||
    {
 | 
			
		||||
        return assetProxies[assetProxyId];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
 | 
			
		||||
    /// @param assetData Byte array encoded for the asset.
 | 
			
		||||
    /// @param from Address to transfer token from.
 | 
			
		||||
    /// @param to Address to transfer token to.
 | 
			
		||||
    /// @param amount Amount of token to transfer.
 | 
			
		||||
    function dispatchTransferFrom(
 | 
			
		||||
        bytes memory assetData,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
    {
 | 
			
		||||
        // Do nothing if no amount should be transferred.
 | 
			
		||||
        if (amount > 0 && from != to) {
 | 
			
		||||
            // Ensure assetData length is valid
 | 
			
		||||
            require(
 | 
			
		||||
                assetData.length > 3,
 | 
			
		||||
                "LENGTH_GREATER_THAN_3_REQUIRED"
 | 
			
		||||
            );
 | 
			
		||||
            
 | 
			
		||||
            // Lookup assetProxy. We do not use `LibBytes.readBytes4` for gas efficiency reasons.
 | 
			
		||||
            bytes4 assetProxyId;
 | 
			
		||||
            assembly {
 | 
			
		||||
                assetProxyId := and(mload(
 | 
			
		||||
                    add(assetData, 32)),
 | 
			
		||||
                    0xFFFFFFFF00000000000000000000000000000000000000000000000000000000
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            address assetProxy = assetProxies[assetProxyId];
 | 
			
		||||
 | 
			
		||||
            // Ensure that assetProxy exists
 | 
			
		||||
            require(
 | 
			
		||||
                assetProxy != address(0),
 | 
			
		||||
                "ASSET_PROXY_DOES_NOT_EXIST"
 | 
			
		||||
            );
 | 
			
		||||
            
 | 
			
		||||
            // We construct calldata for the `assetProxy.transferFrom` ABI.
 | 
			
		||||
            // The layout of this calldata is in the table below.
 | 
			
		||||
            // 
 | 
			
		||||
            // | 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                          |
 | 
			
		||||
 | 
			
		||||
            assembly {
 | 
			
		||||
                /////// Setup State ///////
 | 
			
		||||
                // `cdStart` is the start of the calldata for `assetProxy.transferFrom` (equal to free memory ptr).
 | 
			
		||||
                let cdStart := mload(64)
 | 
			
		||||
                // `dataAreaLength` is the total number of words needed to store `assetData`
 | 
			
		||||
                //  As-per the ABI spec, this value is padded up to the nearest multiple of 32,
 | 
			
		||||
                //  and includes 32-bytes for length.
 | 
			
		||||
                let dataAreaLength := and(add(mload(assetData), 63), 0xFFFFFFFFFFFE0)
 | 
			
		||||
                // `cdEnd` is the end of the calldata for `assetProxy.transferFrom`.
 | 
			
		||||
                let cdEnd := add(cdStart, add(132, dataAreaLength))
 | 
			
		||||
 | 
			
		||||
                
 | 
			
		||||
                /////// Setup Header Area ///////
 | 
			
		||||
                // This area holds the 4-byte `transferFromSelector`.
 | 
			
		||||
                // bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
 | 
			
		||||
                mstore(cdStart, 0xa85e59e400000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                
 | 
			
		||||
                /////// Setup Params Area ///////
 | 
			
		||||
                // Each parameter is padded to 32-bytes. The entire Params Area is 128 bytes.
 | 
			
		||||
                // Notes:
 | 
			
		||||
                //   1. The offset to `assetData` is the length of the Params Area (128 bytes).
 | 
			
		||||
                //   2. A 20-byte mask is applied to addresses to zero-out the unused bytes.
 | 
			
		||||
                mstore(add(cdStart, 4), 128)
 | 
			
		||||
                mstore(add(cdStart, 36), and(from, 0xffffffffffffffffffffffffffffffffffffffff))
 | 
			
		||||
                mstore(add(cdStart, 68), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
 | 
			
		||||
                mstore(add(cdStart, 100), amount)
 | 
			
		||||
                
 | 
			
		||||
                /////// Setup Data Area ///////
 | 
			
		||||
                // This area holds `assetData`.
 | 
			
		||||
                let dataArea := add(cdStart, 132)
 | 
			
		||||
                // solhint-disable-next-line no-empty-blocks
 | 
			
		||||
                for {} lt(dataArea, cdEnd) {} {
 | 
			
		||||
                    mstore(dataArea, mload(assetData))
 | 
			
		||||
                    dataArea := add(dataArea, 32)
 | 
			
		||||
                    assetData := add(assetData, 32)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                /////// Call `assetProxy.transferFrom` using the constructed calldata ///////
 | 
			
		||||
                let success := call(
 | 
			
		||||
                    gas,                    // forward all gas
 | 
			
		||||
                    assetProxy,             // call address of asset proxy
 | 
			
		||||
                    0,                      // don't send any ETH
 | 
			
		||||
                    cdStart,                // pointer to start of input
 | 
			
		||||
                    sub(cdEnd, cdStart),    // length of input  
 | 
			
		||||
                    cdStart,                // write output over input
 | 
			
		||||
                    512                     // reserve 512 bytes for output
 | 
			
		||||
                )
 | 
			
		||||
                if iszero(success) {
 | 
			
		||||
                    revert(cdStart, returndatasize())
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										117
									
								
								contracts/asset-proxy/contracts/src/MixinAuthorizable.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								contracts/asset-proxy/contracts/src/MixinAuthorizable.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,117 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/Ownable.sol";
 | 
			
		||||
import "./mixins/MAuthorizable.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract MixinAuthorizable is
 | 
			
		||||
    Ownable,
 | 
			
		||||
    MAuthorizable
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Only authorized addresses can invoke functions with this modifier.
 | 
			
		||||
    modifier onlyAuthorized {
 | 
			
		||||
        require(
 | 
			
		||||
            authorized[msg.sender],
 | 
			
		||||
            "SENDER_NOT_AUTHORIZED"
 | 
			
		||||
        );
 | 
			
		||||
        _;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    mapping (address => bool) public authorized;
 | 
			
		||||
    address[] public authorities;
 | 
			
		||||
 | 
			
		||||
    /// @dev Authorizes an address.
 | 
			
		||||
    /// @param target Address to authorize.
 | 
			
		||||
    function addAuthorizedAddress(address target)
 | 
			
		||||
        external
 | 
			
		||||
        onlyOwner
 | 
			
		||||
    {
 | 
			
		||||
        require(
 | 
			
		||||
            !authorized[target],
 | 
			
		||||
            "TARGET_ALREADY_AUTHORIZED"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        authorized[target] = true;
 | 
			
		||||
        authorities.push(target);
 | 
			
		||||
        emit AuthorizedAddressAdded(target, msg.sender);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Removes authorizion of an address.
 | 
			
		||||
    /// @param target Address to remove authorization from.
 | 
			
		||||
    function removeAuthorizedAddress(address target)
 | 
			
		||||
        external
 | 
			
		||||
        onlyOwner
 | 
			
		||||
    {
 | 
			
		||||
        require(
 | 
			
		||||
            authorized[target],
 | 
			
		||||
            "TARGET_NOT_AUTHORIZED"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        delete authorized[target];
 | 
			
		||||
        for (uint256 i = 0; i < authorities.length; i++) {
 | 
			
		||||
            if (authorities[i] == target) {
 | 
			
		||||
                authorities[i] = authorities[authorities.length - 1];
 | 
			
		||||
                authorities.length -= 1;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        emit AuthorizedAddressRemoved(target, msg.sender);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Removes authorizion of an address.
 | 
			
		||||
    /// @param target Address to remove authorization from.
 | 
			
		||||
    /// @param index Index of target in authorities array.
 | 
			
		||||
    function removeAuthorizedAddressAtIndex(
 | 
			
		||||
        address target,
 | 
			
		||||
        uint256 index
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        onlyOwner
 | 
			
		||||
    {
 | 
			
		||||
        require(
 | 
			
		||||
            authorized[target],
 | 
			
		||||
            "TARGET_NOT_AUTHORIZED"
 | 
			
		||||
        );
 | 
			
		||||
        require(
 | 
			
		||||
            index < authorities.length,
 | 
			
		||||
            "INDEX_OUT_OF_BOUNDS"
 | 
			
		||||
        );
 | 
			
		||||
        require(
 | 
			
		||||
            authorities[index] == target,
 | 
			
		||||
            "AUTHORIZED_ADDRESS_MISMATCH"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        delete authorized[target];
 | 
			
		||||
        authorities[index] = authorities[authorities.length - 1];
 | 
			
		||||
        authorities.length -= 1;
 | 
			
		||||
        emit AuthorizedAddressRemoved(target, msg.sender);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets all authorized addresses.
 | 
			
		||||
    /// @return Array of authorized addresses.
 | 
			
		||||
    function getAuthorizedAddresses()
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (address[] memory)
 | 
			
		||||
    {
 | 
			
		||||
        return authorities;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										335
									
								
								contracts/asset-proxy/contracts/src/MultiAssetProxy.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										335
									
								
								contracts/asset-proxy/contracts/src/MultiAssetProxy.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,335 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
 | 
			
		||||
import "./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 := add(calldataload(4), 4)
 | 
			
		||||
 | 
			
		||||
                // Load length in bytes of `assetData`
 | 
			
		||||
                let assetDataLength := calldataload(assetDataOffset)
 | 
			
		||||
 | 
			
		||||
                // 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]        |
 | 
			
		||||
 | 
			
		||||
                // Assert that the length of asset data:
 | 
			
		||||
                // 1. Must be at least 68 bytes (see table above)
 | 
			
		||||
                // 2. Must be a multiple of 32 (excluding the 4-byte selector)
 | 
			
		||||
                if or(lt(assetDataLength, 68), mod(sub(assetDataLength, 4), 32)) {
 | 
			
		||||
                    // Revert with `Error("INVALID_ASSET_DATA_LENGTH")`
 | 
			
		||||
                    mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                    mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                    mstore(64, 0x00000019494e56414c49445f41535345545f444154415f4c454e475448000000)
 | 
			
		||||
                    mstore(96, 0)
 | 
			
		||||
                    revert(0, 100)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // End of asset data in calldata
 | 
			
		||||
                // assetDataOffset
 | 
			
		||||
                // + 32 (assetData len)
 | 
			
		||||
                let assetDataEnd := add(assetDataOffset, add(assetDataLength, 32))
 | 
			
		||||
                if gt(assetDataEnd, calldatasize()) {
 | 
			
		||||
                    // Revert with `Error("INVALID_ASSET_DATA_END")`
 | 
			
		||||
                    mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                    mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                    mstore(64, 0x00000016494e56414c49445f41535345545f444154415f454e44000000000000)
 | 
			
		||||
                    mstore(96, 0)
 | 
			
		||||
                    revert(0, 100)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // In order to find the offset to `amounts`, we must add:
 | 
			
		||||
                // assetDataOffset
 | 
			
		||||
                // + 32 (assetData len)
 | 
			
		||||
                // + 4 (assetProxyId)
 | 
			
		||||
                let amountsOffset := calldataload(add(assetDataOffset, 36))
 | 
			
		||||
 | 
			
		||||
                // In order to find the offset to `nestedAssetData`, we must add:
 | 
			
		||||
                // assetDataOffset
 | 
			
		||||
                // + 32 (assetData len)
 | 
			
		||||
                // + 4 (assetProxyId)
 | 
			
		||||
                // + 32 (amounts offset)
 | 
			
		||||
                let nestedAssetDataOffset := calldataload(add(assetDataOffset, 68))
 | 
			
		||||
 | 
			
		||||
                // In order to find the start of the `amounts` contents, we must add: 
 | 
			
		||||
                // assetDataOffset 
 | 
			
		||||
                // + 32 (assetData len)
 | 
			
		||||
                // + 4 (assetProxyId)
 | 
			
		||||
                // + amountsOffset
 | 
			
		||||
                // + 32 (amounts len)
 | 
			
		||||
                let amountsContentsStart := add(assetDataOffset, add(amountsOffset, 68))
 | 
			
		||||
 | 
			
		||||
                // 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: 
 | 
			
		||||
                // assetDataOffset 
 | 
			
		||||
                // + 32 (assetData len)
 | 
			
		||||
                // + 4 (assetProxyId)
 | 
			
		||||
                // + nestedAssetDataOffset
 | 
			
		||||
                // + 32 (nestedAssetData len)
 | 
			
		||||
                let nestedAssetDataContentsStart := add(assetDataOffset, add(nestedAssetDataOffset, 68))
 | 
			
		||||
 | 
			
		||||
                // 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:
 | 
			
		||||
                    // assetDataOffset 
 | 
			
		||||
                    // + 32 (assetData len)
 | 
			
		||||
                    // + 4 (assetProxyId)
 | 
			
		||||
                    // + nestedAssetDataOffset
 | 
			
		||||
                    // + 32 (nestedAssetData len)
 | 
			
		||||
                    // + nestedAssetDataElementOffset
 | 
			
		||||
                    // + 32 (nestedAssetDataElement len)
 | 
			
		||||
                    let nestedAssetDataElementContentsStart := add(
 | 
			
		||||
                        assetDataOffset,
 | 
			
		||||
                        add(
 | 
			
		||||
                            nestedAssetDataOffset,
 | 
			
		||||
                            add(nestedAssetDataElementOffset, 100)
 | 
			
		||||
                        )
 | 
			
		||||
                    )
 | 
			
		||||
 | 
			
		||||
                    // 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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										83
									
								
								contracts/asset-proxy/contracts/src/StaticCallProxy.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								contracts/asset-proxy/contracts/src/StaticCallProxy.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.9;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable no-unused-vars
 | 
			
		||||
contract StaticCallProxy {
 | 
			
		||||
 | 
			
		||||
    using LibBytes for bytes;
 | 
			
		||||
 | 
			
		||||
    // Id of this proxy.
 | 
			
		||||
    bytes4 constant internal PROXY_ID = bytes4(keccak256("StaticCall(address,bytes,bytes32)"));
 | 
			
		||||
 | 
			
		||||
    /// @dev Makes a staticcall to a target address and verifies that the data returned matches the expected return data.
 | 
			
		||||
    /// @param assetData Byte array encoded with staticCallTarget, staticCallData, and expectedCallResultHash
 | 
			
		||||
    /// @param from This value is ignored.
 | 
			
		||||
    /// @param to This value is ignored.
 | 
			
		||||
    /// @param amount This value is ignored.
 | 
			
		||||
    function transferFrom(
 | 
			
		||||
        bytes calldata assetData,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
    {
 | 
			
		||||
        // Decode params from `assetData`
 | 
			
		||||
        (
 | 
			
		||||
            address staticCallTarget,
 | 
			
		||||
            bytes memory staticCallData,
 | 
			
		||||
            bytes32 expectedReturnDataHash
 | 
			
		||||
        ) = abi.decode(
 | 
			
		||||
            assetData.sliceDestructive(4, assetData.length),
 | 
			
		||||
            (address, bytes, bytes32)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Execute staticcall
 | 
			
		||||
        (bool success, bytes memory returnData) = staticCallTarget.staticcall(staticCallData);
 | 
			
		||||
 | 
			
		||||
        // Revert with returned data if staticcall is unsuccessful
 | 
			
		||||
        if (!success) {
 | 
			
		||||
            assembly {
 | 
			
		||||
                revert(add(returnData, 32), mload(returnData))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Revert if hash of return data is not as expected
 | 
			
		||||
        bytes32 returnDataHash = keccak256(returnData);
 | 
			
		||||
        require(
 | 
			
		||||
            expectedReturnDataHash == returnDataHash,
 | 
			
		||||
            "UNEXPECTED_STATIC_CALL_RESULT"
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets the proxy id associated with the proxy address.
 | 
			
		||||
    /// @return Proxy id.
 | 
			
		||||
    function getProxyId()
 | 
			
		||||
        external
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes4)
 | 
			
		||||
    {
 | 
			
		||||
        return PROXY_ID;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,58 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
// solhint-disable
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// @dev Interface of the asset proxy's assetData.
 | 
			
		||||
// The asset proxies take an ABI encoded `bytes assetData` as argument.
 | 
			
		||||
// This argument is ABI encoded as one of the methods of this interface.
 | 
			
		||||
interface IAssetData {
 | 
			
		||||
 | 
			
		||||
    function ERC20Token(address tokenAddress)
 | 
			
		||||
        external;
 | 
			
		||||
    
 | 
			
		||||
    function ERC721Token(
 | 
			
		||||
        address tokenAddress,
 | 
			
		||||
        uint256 tokenId
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    function ERC1155Assets(
 | 
			
		||||
        address tokenAddress,
 | 
			
		||||
        uint256[] calldata tokenIds,
 | 
			
		||||
        uint256[] calldata tokenValues,
 | 
			
		||||
        bytes calldata callbackData
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    function MultiAsset(
 | 
			
		||||
        uint256[] calldata amounts,
 | 
			
		||||
        bytes[] calldata nestedAssetData
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    function StaticCall(
 | 
			
		||||
        address callTarget,
 | 
			
		||||
        bytes calldata staticCallData,
 | 
			
		||||
        bytes32 callResultHash
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,45 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
 | 
			
		||||
import "./IAuthorizable.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract IAssetProxy {
 | 
			
		||||
 | 
			
		||||
    /// @dev Transfers assets. Either succeeds or throws.
 | 
			
		||||
    /// @param assetData Byte array encoded for the respective asset proxy.
 | 
			
		||||
    /// @param from Address to transfer asset from.
 | 
			
		||||
    /// @param to Address to transfer asset to.
 | 
			
		||||
    /// @param amount Amount of asset to transfer.
 | 
			
		||||
    function transferFrom(
 | 
			
		||||
        bytes calldata assetData,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
    
 | 
			
		||||
    /// @dev Gets the proxy id associated with the proxy address.
 | 
			
		||||
    /// @return Proxy id.
 | 
			
		||||
    function getProxyId()
 | 
			
		||||
        external
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes4);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,37 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract IAssetProxyDispatcher {
 | 
			
		||||
 | 
			
		||||
    /// @dev Registers an asset proxy to its asset proxy id.
 | 
			
		||||
    ///      Once an asset proxy is registered, it cannot be unregistered.
 | 
			
		||||
    /// @param assetProxy Address of new asset proxy to register.
 | 
			
		||||
    function registerAssetProxy(address assetProxy)
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets an asset proxy.
 | 
			
		||||
    /// @param assetProxyId Id of the asset proxy.
 | 
			
		||||
    /// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered.
 | 
			
		||||
    function getAssetProxy(bytes4 assetProxyId)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (address);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2019 ZeroEx Intl.
 | 
			
		||||
  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.
 | 
			
		||||
@@ -16,26 +16,14 @@
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.9;
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
 | 
			
		||||
import "./IOwnable.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/interfaces/IOwnable.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract IAuthorizable is
 | 
			
		||||
    IOwnable
 | 
			
		||||
{
 | 
			
		||||
    // Event logged when a new address is authorized.
 | 
			
		||||
    event AuthorizedAddressAdded(
 | 
			
		||||
        address indexed target,
 | 
			
		||||
        address indexed caller
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Event logged when a currently authorized address is unauthorized.
 | 
			
		||||
    event AuthorizedAddressRemoved(
 | 
			
		||||
        address indexed target,
 | 
			
		||||
        address indexed caller
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    /// @dev Authorizes an address.
 | 
			
		||||
    /// @param target Address to authorize.
 | 
			
		||||
    function addAuthorizedAddress(address target)
 | 
			
		||||
@@ -0,0 +1,40 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2019 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract LibAssetProxyIds {
 | 
			
		||||
 | 
			
		||||
    // AssetProxy Ids are equiavalent the first 4 bytes of the keccak256 hash of the function signature assigned to each AssetProxy.
 | 
			
		||||
 | 
			
		||||
    // ERC20Token(address)
 | 
			
		||||
    bytes4 constant public ERC20_PROXY_ID = 0xf47261b0;
 | 
			
		||||
 | 
			
		||||
    // ERC721Token(address,uint256)
 | 
			
		||||
    bytes4 constant public ERC721_PROXY_ID = 0x02571792;
 | 
			
		||||
 | 
			
		||||
    // ERC1155Assets(address,uint256[],uint256[],bytes)
 | 
			
		||||
    bytes4 constant public ERC1155_PROXY_ID = 0xa7cb5fb7;
 | 
			
		||||
 | 
			
		||||
    // MultiAsset(uint256[],bytes[])
 | 
			
		||||
    bytes4 constant public MULTI_ASSET_PROXY_ID = 0x94cfcdd7;
 | 
			
		||||
 | 
			
		||||
    // StaticCall(address,bytes,bytes32)
 | 
			
		||||
    bytes4 constant public STATIC_CALL_PROXY_ID = 0xc339d10a;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,45 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
 | 
			
		||||
import "../interfaces/IAssetProxyDispatcher.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract MAssetProxyDispatcher is
 | 
			
		||||
    IAssetProxyDispatcher
 | 
			
		||||
{
 | 
			
		||||
    // Logs registration of new asset proxy
 | 
			
		||||
    event AssetProxyRegistered(
 | 
			
		||||
        bytes4 id,              // Id of new registered AssetProxy.
 | 
			
		||||
        address assetProxy      // Address of new registered AssetProxy.
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    /// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
 | 
			
		||||
    /// @param assetData Byte array encoded for the asset.
 | 
			
		||||
    /// @param from Address to transfer token from.
 | 
			
		||||
    /// @param to Address to transfer token to.
 | 
			
		||||
    /// @param amount Amount of token to transfer.
 | 
			
		||||
    function dispatchTransferFrom(
 | 
			
		||||
        bytes memory assetData,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        internal;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										41
									
								
								contracts/asset-proxy/contracts/src/mixins/MAuthorizable.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								contracts/asset-proxy/contracts/src/mixins/MAuthorizable.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
 | 
			
		||||
import "../interfaces/IAuthorizable.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract MAuthorizable is
 | 
			
		||||
    IAuthorizable
 | 
			
		||||
{
 | 
			
		||||
    // Event logged when a new address is authorized.
 | 
			
		||||
    event AuthorizedAddressAdded(
 | 
			
		||||
        address indexed target,
 | 
			
		||||
        address indexed caller
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Event logged when a currently authorized address is unauthorized.
 | 
			
		||||
    event AuthorizedAddressRemoved(
 | 
			
		||||
        address indexed target,
 | 
			
		||||
        address indexed caller
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    /// @dev Only authorized addresses can invoke functions with this modifier.
 | 
			
		||||
    modifier onlyAuthorized { revert(); _; }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,82 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.9;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract TestStaticCallTarget {
 | 
			
		||||
 | 
			
		||||
    using LibBytes for bytes;
 | 
			
		||||
 | 
			
		||||
    uint256 internal _state;
 | 
			
		||||
 
 | 
			
		||||
    function updateState()
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        _state++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function assertEvenNumber(uint256 target)
 | 
			
		||||
        external
 | 
			
		||||
        pure
 | 
			
		||||
    {
 | 
			
		||||
        require(
 | 
			
		||||
            target % 2 == 0,
 | 
			
		||||
            "TARGET_NOT_EVEN"
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function isOddNumber(uint256 target)
 | 
			
		||||
        external
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bool isOdd)
 | 
			
		||||
    {
 | 
			
		||||
        isOdd = target % 2 == 1;
 | 
			
		||||
        return isOdd;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function noInputFunction()
 | 
			
		||||
        external
 | 
			
		||||
        pure
 | 
			
		||||
    {
 | 
			
		||||
        assert(msg.data.length == 4 && msg.data.readBytes4(0) == bytes4(keccak256("noInputFunction()")));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function dynamicInputFunction(bytes calldata a)
 | 
			
		||||
        external
 | 
			
		||||
        pure
 | 
			
		||||
    {
 | 
			
		||||
        bytes memory abiEncodedData = abi.encodeWithSignature("dynamicInputFunction(bytes)", a);
 | 
			
		||||
        assert(msg.data.equals(abiEncodedData));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function returnComplexType(uint256 a, uint256 b)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes memory result)
 | 
			
		||||
    {
 | 
			
		||||
        result = abi.encodePacked(
 | 
			
		||||
            address(this),
 | 
			
		||||
            a,
 | 
			
		||||
            b
 | 
			
		||||
        );
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										89
									
								
								contracts/asset-proxy/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								contracts/asset-proxy/package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contracts-asset-proxy",
 | 
			
		||||
    "version": "2.2.6",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
    "description": "Smart contract components 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",
 | 
			
		||||
        "fix": "tslint --fix --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",
 | 
			
		||||
        "contracts:gen": "contracts-gen",
 | 
			
		||||
        "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
 | 
			
		||||
    },
 | 
			
		||||
    "config": {
 | 
			
		||||
        "abis": "./generated-artifacts/@(ERC1155Proxy|ERC20Proxy|ERC721Proxy|IAssetData|IAssetProxy|IAuthorizable|MixinAuthorizable|MultiAssetProxy|StaticCallProxy|TestStaticCallTarget).json",
 | 
			
		||||
        "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
 | 
			
		||||
    },
 | 
			
		||||
    "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/protocol/README.md",
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "@0x/abi-gen": "^4.1.1",
 | 
			
		||||
        "@0x/contracts-gen": "^1.0.13",
 | 
			
		||||
        "@0x/contracts-test-utils": "^3.1.14",
 | 
			
		||||
        "@0x/dev-utils": "^2.3.1",
 | 
			
		||||
        "@0x/sol-compiler": "^3.1.13",
 | 
			
		||||
        "@0x/tslint-config": "^3.0.1",
 | 
			
		||||
        "@types/lodash": "4.14.104",
 | 
			
		||||
        "@types/mocha": "^5.2.7",
 | 
			
		||||
        "@types/node": "*",
 | 
			
		||||
        "chai": "^4.0.1",
 | 
			
		||||
        "chai-as-promised": "^7.1.0",
 | 
			
		||||
        "chai-bignumber": "^3.0.0",
 | 
			
		||||
        "dirty-chai": "^2.0.1",
 | 
			
		||||
        "make-promises-safe": "^1.1.0",
 | 
			
		||||
        "mocha": "^6.2.0",
 | 
			
		||||
        "npm-run-all": "^4.1.2",
 | 
			
		||||
        "shx": "^0.2.2",
 | 
			
		||||
        "solhint": "^1.4.1",
 | 
			
		||||
        "tslint": "5.11.0",
 | 
			
		||||
        "typescript": "3.0.1"
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@0x/base-contract": "^5.3.2",
 | 
			
		||||
        "@0x/contracts-erc1155": "^1.1.13",
 | 
			
		||||
        "@0x/contracts-erc20": "^2.2.12",
 | 
			
		||||
        "@0x/contracts-erc721": "^2.1.13",
 | 
			
		||||
        "@0x/contracts-utils": "^3.2.2",
 | 
			
		||||
        "@0x/order-utils": "^8.3.0",
 | 
			
		||||
        "@0x/types": "^2.4.1",
 | 
			
		||||
        "@0x/typescript-typings": "^4.2.4",
 | 
			
		||||
        "@0x/utils": "^4.5.0",
 | 
			
		||||
        "@0x/web3-wrapper": "^6.0.11",
 | 
			
		||||
        "ethereum-types": "^2.1.4",
 | 
			
		||||
        "ethereumjs-util": "^5.1.1",
 | 
			
		||||
        "lodash": "^4.17.11"
 | 
			
		||||
    },
 | 
			
		||||
    "publishConfig": {
 | 
			
		||||
        "access": "public"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								contracts/asset-proxy/src/artifacts.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								contracts/asset-proxy/src/artifacts.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
/*
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 * Warning: This file is auto-generated by contracts-gen. Don't edit manually.
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
import { ContractArtifact } from 'ethereum-types';
 | 
			
		||||
 | 
			
		||||
import * as ERC1155Proxy from '../generated-artifacts/ERC1155Proxy.json';
 | 
			
		||||
import * as ERC20Proxy from '../generated-artifacts/ERC20Proxy.json';
 | 
			
		||||
import * as ERC721Proxy from '../generated-artifacts/ERC721Proxy.json';
 | 
			
		||||
import * as IAssetData from '../generated-artifacts/IAssetData.json';
 | 
			
		||||
import * as IAssetProxy from '../generated-artifacts/IAssetProxy.json';
 | 
			
		||||
import * as IAuthorizable from '../generated-artifacts/IAuthorizable.json';
 | 
			
		||||
import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json';
 | 
			
		||||
import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json';
 | 
			
		||||
import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json';
 | 
			
		||||
import * as TestStaticCallTarget from '../generated-artifacts/TestStaticCallTarget.json';
 | 
			
		||||
export const artifacts = {
 | 
			
		||||
    ERC1155Proxy: ERC1155Proxy as ContractArtifact,
 | 
			
		||||
    ERC20Proxy: ERC20Proxy as ContractArtifact,
 | 
			
		||||
    ERC721Proxy: ERC721Proxy as ContractArtifact,
 | 
			
		||||
    MixinAuthorizable: MixinAuthorizable as ContractArtifact,
 | 
			
		||||
    MultiAssetProxy: MultiAssetProxy as ContractArtifact,
 | 
			
		||||
    StaticCallProxy: StaticCallProxy as ContractArtifact,
 | 
			
		||||
    IAssetData: IAssetData as ContractArtifact,
 | 
			
		||||
    IAssetProxy: IAssetProxy as ContractArtifact,
 | 
			
		||||
    IAuthorizable: IAuthorizable as ContractArtifact,
 | 
			
		||||
    TestStaticCallTarget: TestStaticCallTarget as ContractArtifact,
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										3
									
								
								contracts/asset-proxy/src/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								contracts/asset-proxy/src/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
export * from './artifacts';
 | 
			
		||||
export * from './wrappers';
 | 
			
		||||
export * from '../test/utils';
 | 
			
		||||
							
								
								
									
										15
									
								
								contracts/asset-proxy/src/wrappers.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								contracts/asset-proxy/src/wrappers.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
/*
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 * Warning: This file is auto-generated by contracts-gen. Don't edit manually.
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
export * from '../generated-wrappers/erc1155_proxy';
 | 
			
		||||
export * from '../generated-wrappers/erc20_proxy';
 | 
			
		||||
export * from '../generated-wrappers/erc721_proxy';
 | 
			
		||||
export * from '../generated-wrappers/i_asset_data';
 | 
			
		||||
export * from '../generated-wrappers/i_asset_proxy';
 | 
			
		||||
export * from '../generated-wrappers/i_authorizable';
 | 
			
		||||
export * from '../generated-wrappers/mixin_authorizable';
 | 
			
		||||
export * from '../generated-wrappers/multi_asset_proxy';
 | 
			
		||||
export * from '../generated-wrappers/static_call_proxy';
 | 
			
		||||
export * from '../generated-wrappers/test_static_call_target';
 | 
			
		||||
							
								
								
									
										216
									
								
								contracts/asset-proxy/test/authorizable.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								contracts/asset-proxy/test/authorizable.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,216 @@
 | 
			
		||||
import {
 | 
			
		||||
    chaiSetup,
 | 
			
		||||
    constants,
 | 
			
		||||
    expectTransactionFailedAsync,
 | 
			
		||||
    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 * as _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
import { artifacts, MixinAuthorizableContract } from '../src';
 | 
			
		||||
 | 
			
		||||
chaiSetup.configure();
 | 
			
		||||
const expect = chai.expect;
 | 
			
		||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
 | 
			
		||||
 | 
			
		||||
describe('Authorizable', () => {
 | 
			
		||||
    let owner: string;
 | 
			
		||||
    let notOwner: string;
 | 
			
		||||
    let address: string;
 | 
			
		||||
    let authorizable: MixinAuthorizableContract;
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        await blockchainLifecycle.startAsync();
 | 
			
		||||
    });
 | 
			
		||||
    after(async () => {
 | 
			
		||||
        await blockchainLifecycle.revertAsync();
 | 
			
		||||
    });
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        const accounts = await web3Wrapper.getAvailableAddressesAsync();
 | 
			
		||||
        [owner, address, notOwner] = _.slice(accounts, 0, 3);
 | 
			
		||||
        authorizable = await MixinAuthorizableContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.MixinAuthorizable,
 | 
			
		||||
            provider,
 | 
			
		||||
            txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
    });
 | 
			
		||||
    beforeEach(async () => {
 | 
			
		||||
        await blockchainLifecycle.startAsync();
 | 
			
		||||
    });
 | 
			
		||||
    afterEach(async () => {
 | 
			
		||||
        await blockchainLifecycle.revertAsync();
 | 
			
		||||
    });
 | 
			
		||||
    describe('addAuthorizedAddress', () => {
 | 
			
		||||
        it('should throw if not called by owner', async () => {
 | 
			
		||||
            return expectTransactionFailedAsync(
 | 
			
		||||
                authorizable.addAuthorizedAddress.sendTransactionAsync(notOwner, { from: notOwner }),
 | 
			
		||||
                RevertReason.OnlyContractOwner,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('should allow owner to add an authorized address', async () => {
 | 
			
		||||
            await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
 | 
			
		||||
                address,
 | 
			
		||||
                { from: owner },
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            const isAuthorized = await authorizable.authorized.callAsync(address);
 | 
			
		||||
            expect(isAuthorized).to.be.true();
 | 
			
		||||
        });
 | 
			
		||||
        it('should throw if owner attempts to authorize a duplicate address', async () => {
 | 
			
		||||
            await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
 | 
			
		||||
                address,
 | 
			
		||||
                { from: owner },
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            return expectTransactionFailedAsync(
 | 
			
		||||
                authorizable.addAuthorizedAddress.sendTransactionAsync(address, { from: owner }),
 | 
			
		||||
                RevertReason.TargetAlreadyAuthorized,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('removeAuthorizedAddress', () => {
 | 
			
		||||
        it('should throw if not called by owner', async () => {
 | 
			
		||||
            await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
 | 
			
		||||
                address,
 | 
			
		||||
                { from: owner },
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            return expectTransactionFailedAsync(
 | 
			
		||||
                authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
 | 
			
		||||
                    from: notOwner,
 | 
			
		||||
                }),
 | 
			
		||||
                RevertReason.OnlyContractOwner,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should allow owner to remove an authorized address', async () => {
 | 
			
		||||
            await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
 | 
			
		||||
                address,
 | 
			
		||||
                { from: owner },
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            await authorizable.removeAuthorizedAddress.awaitTransactionSuccessAsync(
 | 
			
		||||
                address,
 | 
			
		||||
                { from: owner },
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            const isAuthorized = await authorizable.authorized.callAsync(address);
 | 
			
		||||
            expect(isAuthorized).to.be.false();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should throw if owner attempts to remove an address that is not authorized', async () => {
 | 
			
		||||
            return expectTransactionFailedAsync(
 | 
			
		||||
                authorizable.removeAuthorizedAddress.sendTransactionAsync(address, {
 | 
			
		||||
                    from: owner,
 | 
			
		||||
                }),
 | 
			
		||||
                RevertReason.TargetNotAuthorized,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('removeAuthorizedAddressAtIndex', () => {
 | 
			
		||||
        it('should throw if not called by owner', async () => {
 | 
			
		||||
            await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
 | 
			
		||||
                address,
 | 
			
		||||
                { from: owner },
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            const index = new BigNumber(0);
 | 
			
		||||
            return expectTransactionFailedAsync(
 | 
			
		||||
                authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
 | 
			
		||||
                    from: notOwner,
 | 
			
		||||
                }),
 | 
			
		||||
                RevertReason.OnlyContractOwner,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('should throw if index is >= authorities.length', async () => {
 | 
			
		||||
            await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
 | 
			
		||||
                address,
 | 
			
		||||
                { from: owner },
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            const index = new BigNumber(1);
 | 
			
		||||
            return expectTransactionFailedAsync(
 | 
			
		||||
                authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
 | 
			
		||||
                    from: owner,
 | 
			
		||||
                }),
 | 
			
		||||
                RevertReason.IndexOutOfBounds,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('should throw if owner attempts to remove an address that is not authorized', async () => {
 | 
			
		||||
            const index = new BigNumber(0);
 | 
			
		||||
            return expectTransactionFailedAsync(
 | 
			
		||||
                authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address, index, {
 | 
			
		||||
                    from: owner,
 | 
			
		||||
                }),
 | 
			
		||||
                RevertReason.TargetNotAuthorized,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('should throw if address at index does not match target', async () => {
 | 
			
		||||
            const address1 = address;
 | 
			
		||||
            const address2 = notOwner;
 | 
			
		||||
            await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
 | 
			
		||||
                address1,
 | 
			
		||||
                { from: owner },
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
 | 
			
		||||
                address2,
 | 
			
		||||
                { from: owner },
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            const address1Index = new BigNumber(0);
 | 
			
		||||
            return expectTransactionFailedAsync(
 | 
			
		||||
                authorizable.removeAuthorizedAddressAtIndex.sendTransactionAsync(address2, address1Index, {
 | 
			
		||||
                    from: owner,
 | 
			
		||||
                }),
 | 
			
		||||
                RevertReason.AuthorizedAddressMismatch,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('should allow owner to remove an authorized address', async () => {
 | 
			
		||||
            await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
 | 
			
		||||
                address,
 | 
			
		||||
                { from: owner },
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            const index = new BigNumber(0);
 | 
			
		||||
            await authorizable.removeAuthorizedAddressAtIndex.awaitTransactionSuccessAsync(
 | 
			
		||||
                address,
 | 
			
		||||
                index,
 | 
			
		||||
                { from: owner },
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            const isAuthorized = await authorizable.authorized.callAsync(address);
 | 
			
		||||
            expect(isAuthorized).to.be.false();
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('getAuthorizedAddresses', () => {
 | 
			
		||||
        it('should return all authorized addresses', async () => {
 | 
			
		||||
            const initial = await authorizable.getAuthorizedAddresses.callAsync();
 | 
			
		||||
            expect(initial).to.have.length(0);
 | 
			
		||||
            await authorizable.addAuthorizedAddress.awaitTransactionSuccessAsync(
 | 
			
		||||
                address,
 | 
			
		||||
                { from: owner },
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            const afterAdd = await authorizable.getAuthorizedAddresses.callAsync();
 | 
			
		||||
            expect(afterAdd).to.have.length(1);
 | 
			
		||||
            expect(afterAdd).to.include(address);
 | 
			
		||||
            await authorizable.removeAuthorizedAddress.awaitTransactionSuccessAsync(
 | 
			
		||||
                address,
 | 
			
		||||
                { from: owner },
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            const afterRemove = await authorizable.getAuthorizedAddresses.callAsync();
 | 
			
		||||
            expect(afterRemove).to.have.length(0);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										1907
									
								
								contracts/asset-proxy/test/erc1155_proxy.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1907
									
								
								contracts/asset-proxy/test/erc1155_proxy.ts
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										19
									
								
								contracts/asset-proxy/test/global_hooks.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								contracts/asset-proxy/test/global_hooks.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
import { env, EnvVars } from '@0x/dev-utils';
 | 
			
		||||
 | 
			
		||||
import { coverage, profiler, provider } from '@0x/contracts-test-utils';
 | 
			
		||||
import { providerUtils } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
before('start web3 provider', () => {
 | 
			
		||||
    providerUtils.startProviderEngine(provider);
 | 
			
		||||
});
 | 
			
		||||
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();
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										1750
									
								
								contracts/asset-proxy/test/proxies.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1750
									
								
								contracts/asset-proxy/test/proxies.ts
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										242
									
								
								contracts/asset-proxy/test/static_call_proxy.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										242
									
								
								contracts/asset-proxy/test/static_call_proxy.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,242 @@
 | 
			
		||||
import {
 | 
			
		||||
    chaiSetup,
 | 
			
		||||
    constants,
 | 
			
		||||
    expectTransactionFailedAsync,
 | 
			
		||||
    expectTransactionFailedWithoutReasonAsync,
 | 
			
		||||
    provider,
 | 
			
		||||
    txDefaults,
 | 
			
		||||
    web3Wrapper,
 | 
			
		||||
} from '@0x/contracts-test-utils';
 | 
			
		||||
import { BlockchainLifecycle } from '@0x/dev-utils';
 | 
			
		||||
import { assetDataUtils } from '@0x/order-utils';
 | 
			
		||||
import { AssetProxyId, RevertReason } from '@0x/types';
 | 
			
		||||
import { AbiEncoder, BigNumber } from '@0x/utils';
 | 
			
		||||
import * as chai from 'chai';
 | 
			
		||||
import * as ethUtil from 'ethereumjs-util';
 | 
			
		||||
 | 
			
		||||
import { artifacts, IAssetProxyContract, StaticCallProxyContract, TestStaticCallTargetContract } from '../src';
 | 
			
		||||
 | 
			
		||||
chaiSetup.configure();
 | 
			
		||||
const expect = chai.expect;
 | 
			
		||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
 | 
			
		||||
 | 
			
		||||
describe('StaticCallProxy', () => {
 | 
			
		||||
    const amount = constants.ZERO_AMOUNT;
 | 
			
		||||
    let fromAddress: string;
 | 
			
		||||
    let toAddress: string;
 | 
			
		||||
 | 
			
		||||
    let staticCallProxy: IAssetProxyContract;
 | 
			
		||||
    let staticCallTarget: TestStaticCallTargetContract;
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        await blockchainLifecycle.startAsync();
 | 
			
		||||
    });
 | 
			
		||||
    after(async () => {
 | 
			
		||||
        await blockchainLifecycle.revertAsync();
 | 
			
		||||
    });
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        const accounts = await web3Wrapper.getAvailableAddressesAsync();
 | 
			
		||||
        [fromAddress, toAddress] = accounts.slice(0, 2);
 | 
			
		||||
        const staticCallProxyWithoutTransferFrom = await StaticCallProxyContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.StaticCallProxy,
 | 
			
		||||
            provider,
 | 
			
		||||
            txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
        staticCallProxy = new IAssetProxyContract(staticCallProxyWithoutTransferFrom.address, provider, txDefaults);
 | 
			
		||||
        staticCallTarget = await TestStaticCallTargetContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.TestStaticCallTarget,
 | 
			
		||||
            provider,
 | 
			
		||||
            txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
    });
 | 
			
		||||
    beforeEach(async () => {
 | 
			
		||||
        await blockchainLifecycle.startAsync();
 | 
			
		||||
    });
 | 
			
		||||
    afterEach(async () => {
 | 
			
		||||
        await blockchainLifecycle.revertAsync();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('general', () => {
 | 
			
		||||
        it('should revert if undefined function is called', async () => {
 | 
			
		||||
            const undefinedSelector = '0x01020304';
 | 
			
		||||
            await expectTransactionFailedWithoutReasonAsync(
 | 
			
		||||
                web3Wrapper.sendTransactionAsync({
 | 
			
		||||
                    from: fromAddress,
 | 
			
		||||
                    to: staticCallProxy.address,
 | 
			
		||||
                    value: constants.ZERO_AMOUNT,
 | 
			
		||||
                    data: undefinedSelector,
 | 
			
		||||
                }),
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('should have an id of 0xc339d10a', async () => {
 | 
			
		||||
            const proxyId = await staticCallProxy.getProxyId.callAsync();
 | 
			
		||||
            const expectedProxyId = AssetProxyId.StaticCall;
 | 
			
		||||
            expect(proxyId).to.equal(expectedProxyId);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
    describe('transferFrom', () => {
 | 
			
		||||
        it('should revert if assetData lies outside the bounds of calldata', async () => {
 | 
			
		||||
            const staticCallData = staticCallTarget.noInputFunction.getABIEncodedTransactionData();
 | 
			
		||||
            const expectedResultHash = constants.KECCAK256_NULL;
 | 
			
		||||
            const assetData = assetDataUtils.encodeStaticCallAssetData(
 | 
			
		||||
                staticCallTarget.address,
 | 
			
		||||
                staticCallData,
 | 
			
		||||
                expectedResultHash,
 | 
			
		||||
            );
 | 
			
		||||
            const txData = staticCallProxy.transferFrom.getABIEncodedTransactionData(
 | 
			
		||||
                assetData,
 | 
			
		||||
                fromAddress,
 | 
			
		||||
                toAddress,
 | 
			
		||||
                amount,
 | 
			
		||||
            );
 | 
			
		||||
            const offsetToAssetData = '0000000000000000000000000000000000000000000000000000000000000080';
 | 
			
		||||
            const txDataEndBuffer = ethUtil.toBuffer((txData.length - 2) / 2 - 4);
 | 
			
		||||
            const paddedTxDataEndBuffer = ethUtil.setLengthLeft(txDataEndBuffer, 32);
 | 
			
		||||
            const invalidOffsetToAssetData = ethUtil.bufferToHex(paddedTxDataEndBuffer).slice(2);
 | 
			
		||||
            const newAssetData = '0000000000000000000000000000000000000000000000000000000000000304';
 | 
			
		||||
            const badTxData = `${txData.replace(offsetToAssetData, invalidOffsetToAssetData)}${newAssetData}`;
 | 
			
		||||
            await expectTransactionFailedWithoutReasonAsync(
 | 
			
		||||
                web3Wrapper.sendTransactionAsync({
 | 
			
		||||
                    to: staticCallProxy.address,
 | 
			
		||||
                    from: fromAddress,
 | 
			
		||||
                    data: badTxData,
 | 
			
		||||
                }),
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('should revert if the length of assetData is less than 100 bytes', async () => {
 | 
			
		||||
            const staticCallData = constants.NULL_BYTES;
 | 
			
		||||
            const expectedResultHash = constants.KECCAK256_NULL;
 | 
			
		||||
            const assetData = assetDataUtils
 | 
			
		||||
                .encodeStaticCallAssetData(staticCallTarget.address, staticCallData, expectedResultHash)
 | 
			
		||||
                .slice(0, -128);
 | 
			
		||||
            const assetDataByteLen = (assetData.length - 2) / 2;
 | 
			
		||||
            expect((assetDataByteLen - 4) % 32).to.equal(0);
 | 
			
		||||
            await expectTransactionFailedWithoutReasonAsync(
 | 
			
		||||
                staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount),
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('should revert if the offset to `staticCallData` points to outside of assetData', async () => {
 | 
			
		||||
            const staticCallData = staticCallTarget.noInputFunction.getABIEncodedTransactionData();
 | 
			
		||||
            const expectedResultHash = constants.KECCAK256_NULL;
 | 
			
		||||
            const assetData = assetDataUtils.encodeStaticCallAssetData(
 | 
			
		||||
                staticCallTarget.address,
 | 
			
		||||
                staticCallData,
 | 
			
		||||
                expectedResultHash,
 | 
			
		||||
            );
 | 
			
		||||
            const offsetToStaticCallData = '0000000000000000000000000000000000000000000000000000000000000060';
 | 
			
		||||
            const assetDataEndBuffer = ethUtil.toBuffer((assetData.length - 2) / 2 - 4);
 | 
			
		||||
            const paddedAssetDataEndBuffer = ethUtil.setLengthLeft(assetDataEndBuffer, 32);
 | 
			
		||||
            const invalidOffsetToStaticCallData = ethUtil.bufferToHex(paddedAssetDataEndBuffer).slice(2);
 | 
			
		||||
            const newStaticCallData = '0000000000000000000000000000000000000000000000000000000000000304';
 | 
			
		||||
            const badAssetData = `${assetData.replace(
 | 
			
		||||
                offsetToStaticCallData,
 | 
			
		||||
                invalidOffsetToStaticCallData,
 | 
			
		||||
            )}${newStaticCallData}`;
 | 
			
		||||
            await expectTransactionFailedWithoutReasonAsync(
 | 
			
		||||
                staticCallProxy.transferFrom.sendTransactionAsync(badAssetData, fromAddress, toAddress, amount),
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('should revert if the callTarget attempts to write to state', async () => {
 | 
			
		||||
            const staticCallData = staticCallTarget.updateState.getABIEncodedTransactionData();
 | 
			
		||||
            const expectedResultHash = constants.KECCAK256_NULL;
 | 
			
		||||
            const assetData = assetDataUtils.encodeStaticCallAssetData(
 | 
			
		||||
                staticCallTarget.address,
 | 
			
		||||
                staticCallData,
 | 
			
		||||
                expectedResultHash,
 | 
			
		||||
            );
 | 
			
		||||
            await expectTransactionFailedWithoutReasonAsync(
 | 
			
		||||
                staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount),
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('should revert with data provided by the callTarget if the staticcall reverts', async () => {
 | 
			
		||||
            const staticCallData = staticCallTarget.assertEvenNumber.getABIEncodedTransactionData(new BigNumber(1));
 | 
			
		||||
            const expectedResultHash = constants.KECCAK256_NULL;
 | 
			
		||||
            const assetData = assetDataUtils.encodeStaticCallAssetData(
 | 
			
		||||
                staticCallTarget.address,
 | 
			
		||||
                staticCallData,
 | 
			
		||||
                expectedResultHash,
 | 
			
		||||
            );
 | 
			
		||||
            await expectTransactionFailedAsync(
 | 
			
		||||
                staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount),
 | 
			
		||||
                RevertReason.TargetNotEven,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('should revert if the hash of the output is different than expected expected', async () => {
 | 
			
		||||
            const staticCallData = staticCallTarget.isOddNumber.getABIEncodedTransactionData(new BigNumber(0));
 | 
			
		||||
            const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001');
 | 
			
		||||
            const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer));
 | 
			
		||||
            const assetData = assetDataUtils.encodeStaticCallAssetData(
 | 
			
		||||
                staticCallTarget.address,
 | 
			
		||||
                staticCallData,
 | 
			
		||||
                expectedResultHash,
 | 
			
		||||
            );
 | 
			
		||||
            await expectTransactionFailedAsync(
 | 
			
		||||
                staticCallProxy.transferFrom.sendTransactionAsync(assetData, fromAddress, toAddress, amount),
 | 
			
		||||
                RevertReason.UnexpectedStaticCallResult,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('should be successful if a function call with no inputs and no outputs is successful', async () => {
 | 
			
		||||
            const staticCallData = staticCallTarget.noInputFunction.getABIEncodedTransactionData();
 | 
			
		||||
            const expectedResultHash = constants.KECCAK256_NULL;
 | 
			
		||||
            const assetData = assetDataUtils.encodeStaticCallAssetData(
 | 
			
		||||
                staticCallTarget.address,
 | 
			
		||||
                staticCallData,
 | 
			
		||||
                expectedResultHash,
 | 
			
		||||
            );
 | 
			
		||||
            await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
 | 
			
		||||
        });
 | 
			
		||||
        it('should be successful if the staticCallTarget is not a contract and no return value is expected', async () => {
 | 
			
		||||
            const staticCallData = '0x0102030405060708';
 | 
			
		||||
            const expectedResultHash = constants.KECCAK256_NULL;
 | 
			
		||||
            const assetData = assetDataUtils.encodeStaticCallAssetData(toAddress, staticCallData, expectedResultHash);
 | 
			
		||||
            await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
 | 
			
		||||
        });
 | 
			
		||||
        it('should be successful if a function call with one static input returns the correct value', async () => {
 | 
			
		||||
            const staticCallData = staticCallTarget.isOddNumber.getABIEncodedTransactionData(new BigNumber(1));
 | 
			
		||||
            const trueAsBuffer = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001');
 | 
			
		||||
            const expectedResultHash = ethUtil.bufferToHex(ethUtil.sha3(trueAsBuffer));
 | 
			
		||||
            const assetData = assetDataUtils.encodeStaticCallAssetData(
 | 
			
		||||
                staticCallTarget.address,
 | 
			
		||||
                staticCallData,
 | 
			
		||||
                expectedResultHash,
 | 
			
		||||
            );
 | 
			
		||||
            await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
 | 
			
		||||
        });
 | 
			
		||||
        it('should be successful if a function with one dynamic input is successful', async () => {
 | 
			
		||||
            const dynamicInput = '0x0102030405060708';
 | 
			
		||||
            const staticCallData = staticCallTarget.dynamicInputFunction.getABIEncodedTransactionData(dynamicInput);
 | 
			
		||||
            const expectedResultHash = constants.KECCAK256_NULL;
 | 
			
		||||
            const assetData = assetDataUtils.encodeStaticCallAssetData(
 | 
			
		||||
                staticCallTarget.address,
 | 
			
		||||
                staticCallData,
 | 
			
		||||
                expectedResultHash,
 | 
			
		||||
            );
 | 
			
		||||
            await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
 | 
			
		||||
        });
 | 
			
		||||
        it('should be successful if a function call returns a complex type', async () => {
 | 
			
		||||
            const a = new BigNumber(1);
 | 
			
		||||
            const b = new BigNumber(2);
 | 
			
		||||
            const staticCallData = staticCallTarget.returnComplexType.getABIEncodedTransactionData(a, b);
 | 
			
		||||
            const abiEncoder = new AbiEncoder.DynamicBytes({
 | 
			
		||||
                name: '',
 | 
			
		||||
                type: 'bytes',
 | 
			
		||||
            });
 | 
			
		||||
            const aHex = '0000000000000000000000000000000000000000000000000000000000000001';
 | 
			
		||||
            const bHex = '0000000000000000000000000000000000000000000000000000000000000002';
 | 
			
		||||
            const expectedResults = `${staticCallTarget.address}${aHex}${bHex}`;
 | 
			
		||||
            const offset = '0000000000000000000000000000000000000000000000000000000000000020';
 | 
			
		||||
            const encodedExpectedResultWithOffset = `0x${offset}${abiEncoder.encode(expectedResults).slice(2)}`;
 | 
			
		||||
            const expectedResultHash = ethUtil.bufferToHex(
 | 
			
		||||
                ethUtil.sha3(ethUtil.toBuffer(encodedExpectedResultWithOffset)),
 | 
			
		||||
            );
 | 
			
		||||
            const assetData = assetDataUtils.encodeStaticCallAssetData(
 | 
			
		||||
                staticCallTarget.address,
 | 
			
		||||
                staticCallData,
 | 
			
		||||
                expectedResultHash,
 | 
			
		||||
            );
 | 
			
		||||
            await staticCallProxy.transferFrom.awaitTransactionSuccessAsync(assetData, fromAddress, toAddress, amount);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										403
									
								
								contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										403
									
								
								contracts/asset-proxy/test/utils/erc1155_proxy_wrapper.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,403 @@
 | 
			
		||||
import { artifacts as erc1155Artifacts, ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155';
 | 
			
		||||
import {
 | 
			
		||||
    constants,
 | 
			
		||||
    ERC1155FungibleHoldingsByOwner,
 | 
			
		||||
    ERC1155HoldingsByOwner,
 | 
			
		||||
    ERC1155NonFungibleHoldingsByOwner,
 | 
			
		||||
    LogDecoder,
 | 
			
		||||
    txDefaults,
 | 
			
		||||
} from '@0x/contracts-test-utils';
 | 
			
		||||
import { assetDataUtils } from '@0x/order-utils';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
import { Web3Wrapper } from '@0x/web3-wrapper';
 | 
			
		||||
import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
import { artifacts, ERC1155ProxyContract, IAssetProxyContract } from '../../src';
 | 
			
		||||
 | 
			
		||||
export class ERC1155ProxyWrapper {
 | 
			
		||||
    private readonly _tokenOwnerAddresses: string[];
 | 
			
		||||
    private readonly _fungibleTokenIds: string[];
 | 
			
		||||
    private readonly _nonFungibleTokenIds: string[];
 | 
			
		||||
    private readonly _nfts: Array<{ id: BigNumber; tokenId: BigNumber }>;
 | 
			
		||||
    private readonly _contractOwnerAddress: string;
 | 
			
		||||
    private readonly _web3Wrapper: Web3Wrapper;
 | 
			
		||||
    private readonly _provider: Provider;
 | 
			
		||||
    private readonly _logDecoder: LogDecoder;
 | 
			
		||||
    private readonly _dummyTokenWrappers: Erc1155Wrapper[];
 | 
			
		||||
    private readonly _assetProxyInterface: IAssetProxyContract;
 | 
			
		||||
    private _proxyContract?: ERC1155ProxyContract;
 | 
			
		||||
    private _proxyIdIfExists?: string;
 | 
			
		||||
    private _initialTokenIdsByOwner: ERC1155HoldingsByOwner = { fungible: {}, nonFungible: {} };
 | 
			
		||||
 | 
			
		||||
    constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) {
 | 
			
		||||
        this._web3Wrapper = new Web3Wrapper(provider);
 | 
			
		||||
        this._provider = provider;
 | 
			
		||||
        const allArtifacts = _.merge(artifacts, erc1155Artifacts);
 | 
			
		||||
        this._logDecoder = new LogDecoder(this._web3Wrapper, allArtifacts);
 | 
			
		||||
        this._dummyTokenWrappers = [];
 | 
			
		||||
        this._assetProxyInterface = new IAssetProxyContract(constants.NULL_ADDRESS, provider);
 | 
			
		||||
        this._tokenOwnerAddresses = tokenOwnerAddresses;
 | 
			
		||||
        this._contractOwnerAddress = contractOwnerAddress;
 | 
			
		||||
        this._fungibleTokenIds = [];
 | 
			
		||||
        this._nonFungibleTokenIds = [];
 | 
			
		||||
        this._nfts = [];
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Deploys dummy ERC1155 contracts
 | 
			
		||||
     * @return An array of ERC1155 wrappers; one for each deployed contract.
 | 
			
		||||
     */
 | 
			
		||||
    public async deployDummyContractsAsync(): Promise<Erc1155Wrapper[]> {
 | 
			
		||||
        // tslint:disable-next-line:no-unused-variable
 | 
			
		||||
        for (const i of _.times(constants.NUM_DUMMY_ERC1155_CONTRACTS_TO_DEPLOY)) {
 | 
			
		||||
            const erc1155Contract = await ERC1155MintableContract.deployFrom0xArtifactAsync(
 | 
			
		||||
                erc1155Artifacts.ERC1155Mintable,
 | 
			
		||||
                this._provider,
 | 
			
		||||
                txDefaults,
 | 
			
		||||
                artifacts,
 | 
			
		||||
            );
 | 
			
		||||
            const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._provider, this._contractOwnerAddress);
 | 
			
		||||
            this._dummyTokenWrappers.push(erc1155Wrapper);
 | 
			
		||||
        }
 | 
			
		||||
        return this._dummyTokenWrappers;
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Deploys the ERC1155 proxy
 | 
			
		||||
     * @return Deployed ERC1155 proxy contract instance
 | 
			
		||||
     */
 | 
			
		||||
    public async deployProxyAsync(): Promise<ERC1155ProxyContract> {
 | 
			
		||||
        this._proxyContract = await ERC1155ProxyContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.ERC1155Proxy,
 | 
			
		||||
            this._provider,
 | 
			
		||||
            txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
        this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync();
 | 
			
		||||
        return this._proxyContract;
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Gets the ERC1155 proxy id
 | 
			
		||||
     */
 | 
			
		||||
    public getProxyId(): string {
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        return this._proxyIdIfExists as string;
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev generates abi-encoded tx data for transferring erc1155 fungible/non-fungible tokens.
 | 
			
		||||
     * @param from source address
 | 
			
		||||
     * @param to destination address
 | 
			
		||||
     * @param contractAddress address of erc155 contract
 | 
			
		||||
     * @param tokensToTransfer array of erc1155 tokens to transfer
 | 
			
		||||
     * @param valuesToTransfer array of corresponding values for each erc1155 token to transfer
 | 
			
		||||
     * @param valueMultiplier each value in `valuesToTransfer` is multiplied by this
 | 
			
		||||
     * @param receiverCallbackData callback data if `to` is a contract
 | 
			
		||||
     * @param authorizedSender sender of `transferFrom` transaction
 | 
			
		||||
     * @param extraData extra data to append to `transferFrom` transaction. Optional.
 | 
			
		||||
     * @return abi encoded tx data.
 | 
			
		||||
     */
 | 
			
		||||
    public getTransferFromAbiEncodedTxData(
 | 
			
		||||
        from: string,
 | 
			
		||||
        to: string,
 | 
			
		||||
        contractAddress: string,
 | 
			
		||||
        tokensToTransfer: BigNumber[],
 | 
			
		||||
        valuesToTransfer: BigNumber[],
 | 
			
		||||
        valueMultiplier: BigNumber,
 | 
			
		||||
        receiverCallbackData: string,
 | 
			
		||||
        authorizedSender: string,
 | 
			
		||||
        assetData_?: string,
 | 
			
		||||
    ): string {
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        const assetData =
 | 
			
		||||
            assetData_ === undefined
 | 
			
		||||
                ? assetDataUtils.encodeERC1155AssetData(
 | 
			
		||||
                      contractAddress,
 | 
			
		||||
                      tokensToTransfer,
 | 
			
		||||
                      valuesToTransfer,
 | 
			
		||||
                      receiverCallbackData,
 | 
			
		||||
                  )
 | 
			
		||||
                : assetData_;
 | 
			
		||||
        const data = this._assetProxyInterface.transferFrom.getABIEncodedTransactionData(
 | 
			
		||||
            assetData,
 | 
			
		||||
            from,
 | 
			
		||||
            to,
 | 
			
		||||
            valueMultiplier,
 | 
			
		||||
        );
 | 
			
		||||
        return data;
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev transfers erc1155 fungible/non-fungible tokens.
 | 
			
		||||
     * @param txData: abi-encoded tx data
 | 
			
		||||
     * @param authorizedSender sender of `transferFrom` transaction
 | 
			
		||||
     */
 | 
			
		||||
    public async transferFromRawAsync(
 | 
			
		||||
        txData: string,
 | 
			
		||||
        authorizedSender: string,
 | 
			
		||||
    ): Promise<TransactionReceiptWithDecodedLogs> {
 | 
			
		||||
        const txHash = await this._web3Wrapper.sendTransactionAsync({
 | 
			
		||||
            to: (this._proxyContract as ERC1155ProxyContract).address,
 | 
			
		||||
            data: txData,
 | 
			
		||||
            from: authorizedSender,
 | 
			
		||||
            gas: 300000,
 | 
			
		||||
        });
 | 
			
		||||
        const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
 | 
			
		||||
        return txReceipt;
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev transfers erc1155 fungible/non-fungible tokens.
 | 
			
		||||
     * @param from source address
 | 
			
		||||
     * @param to destination address
 | 
			
		||||
     * @param contractAddress address of erc155 contract
 | 
			
		||||
     * @param tokensToTransfer array of erc1155 tokens to transfer
 | 
			
		||||
     * @param valuesToTransfer array of corresponding values for each erc1155 token to transfer
 | 
			
		||||
     * @param valueMultiplier each value in `valuesToTransfer` is multiplied by this
 | 
			
		||||
     * @param receiverCallbackData callback data if `to` is a contract
 | 
			
		||||
     * @param authorizedSender sender of `transferFrom` transaction
 | 
			
		||||
     * @param extraData extra data to append to `transferFrom` transaction. Optional.
 | 
			
		||||
     * @return tranasction hash.
 | 
			
		||||
     */
 | 
			
		||||
    public async transferFromAsync(
 | 
			
		||||
        from: string,
 | 
			
		||||
        to: string,
 | 
			
		||||
        contractAddress: string,
 | 
			
		||||
        tokensToTransfer: BigNumber[],
 | 
			
		||||
        valuesToTransfer: BigNumber[],
 | 
			
		||||
        valueMultiplier: BigNumber,
 | 
			
		||||
        receiverCallbackData: string,
 | 
			
		||||
        authorizedSender: string,
 | 
			
		||||
        assetData_?: string,
 | 
			
		||||
    ): Promise<TransactionReceiptWithDecodedLogs> {
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        const assetData =
 | 
			
		||||
            assetData_ === undefined
 | 
			
		||||
                ? assetDataUtils.encodeERC1155AssetData(
 | 
			
		||||
                      contractAddress,
 | 
			
		||||
                      tokensToTransfer,
 | 
			
		||||
                      valuesToTransfer,
 | 
			
		||||
                      receiverCallbackData,
 | 
			
		||||
                  )
 | 
			
		||||
                : assetData_;
 | 
			
		||||
        const data = this._assetProxyInterface.transferFrom.getABIEncodedTransactionData(
 | 
			
		||||
            assetData,
 | 
			
		||||
            from,
 | 
			
		||||
            to,
 | 
			
		||||
            valueMultiplier,
 | 
			
		||||
        );
 | 
			
		||||
        const txHash = await this._web3Wrapper.sendTransactionAsync({
 | 
			
		||||
            to: (this._proxyContract as ERC1155ProxyContract).address,
 | 
			
		||||
            data,
 | 
			
		||||
            from: authorizedSender,
 | 
			
		||||
            gas: 300000,
 | 
			
		||||
        });
 | 
			
		||||
        const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
 | 
			
		||||
        return txReceipt;
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev For each deployed ERC1155 contract, this function mints a set of fungible/non-fungible
 | 
			
		||||
     *      tokens for each token owner address (`_tokenOwnerAddresses`).
 | 
			
		||||
     * @return Balances of each token owner, across all ERC1155 contracts and tokens.
 | 
			
		||||
     */
 | 
			
		||||
    public async setBalancesAndAllowancesAsync(): Promise<ERC1155HoldingsByOwner> {
 | 
			
		||||
        this._validateDummyTokenContractsExistOrThrow();
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        this._initialTokenIdsByOwner = {
 | 
			
		||||
            fungible: {},
 | 
			
		||||
            nonFungible: {},
 | 
			
		||||
        };
 | 
			
		||||
        const fungibleHoldingsByOwner: ERC1155FungibleHoldingsByOwner = {};
 | 
			
		||||
        const nonFungibleHoldingsByOwner: ERC1155NonFungibleHoldingsByOwner = {};
 | 
			
		||||
        // Set balances accordingly
 | 
			
		||||
        for (const dummyWrapper of this._dummyTokenWrappers) {
 | 
			
		||||
            const dummyAddress = dummyWrapper.getContract().address;
 | 
			
		||||
            // tslint:disable-next-line:no-unused-variable
 | 
			
		||||
            for (const i of _.times(constants.NUM_ERC1155_FUNGIBLE_TOKENS_MINT)) {
 | 
			
		||||
                // Create a fungible token
 | 
			
		||||
                const tokenId = await dummyWrapper.mintFungibleTokensAsync(
 | 
			
		||||
                    this._tokenOwnerAddresses,
 | 
			
		||||
                    constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
 | 
			
		||||
                );
 | 
			
		||||
                const tokenIdAsString = tokenId.toString();
 | 
			
		||||
                this._fungibleTokenIds.push(tokenIdAsString);
 | 
			
		||||
                // Mint tokens for each owner for this token
 | 
			
		||||
                for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
 | 
			
		||||
                    // tslint:disable-next-line:no-unused-variable
 | 
			
		||||
                    if (fungibleHoldingsByOwner[tokenOwnerAddress] === undefined) {
 | 
			
		||||
                        fungibleHoldingsByOwner[tokenOwnerAddress] = {};
 | 
			
		||||
                    }
 | 
			
		||||
                    if (fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] === undefined) {
 | 
			
		||||
                        fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] = {};
 | 
			
		||||
                    }
 | 
			
		||||
                    fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] =
 | 
			
		||||
                        constants.INITIAL_ERC1155_FUNGIBLE_BALANCE;
 | 
			
		||||
                    await dummyWrapper.setApprovalForAllAsync(
 | 
			
		||||
                        tokenOwnerAddress,
 | 
			
		||||
                        (this._proxyContract as ERC1155ProxyContract).address,
 | 
			
		||||
                        true,
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // Non-fungible tokens
 | 
			
		||||
            // tslint:disable-next-line:no-unused-variable
 | 
			
		||||
            for (const j of _.times(constants.NUM_ERC1155_NONFUNGIBLE_TOKENS_MINT)) {
 | 
			
		||||
                const [tokenId, nftIds] = await dummyWrapper.mintNonFungibleTokensAsync(this._tokenOwnerAddresses);
 | 
			
		||||
                const tokenIdAsString = tokenId.toString();
 | 
			
		||||
                this._nonFungibleTokenIds.push(tokenIdAsString);
 | 
			
		||||
                _.each(this._tokenOwnerAddresses, async (tokenOwnerAddress: string, i: number) => {
 | 
			
		||||
                    if (nonFungibleHoldingsByOwner[tokenOwnerAddress] === undefined) {
 | 
			
		||||
                        nonFungibleHoldingsByOwner[tokenOwnerAddress] = {};
 | 
			
		||||
                    }
 | 
			
		||||
                    if (nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] === undefined) {
 | 
			
		||||
                        nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] = {};
 | 
			
		||||
                    }
 | 
			
		||||
                    if (nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] === undefined) {
 | 
			
		||||
                        nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] = [];
 | 
			
		||||
                    }
 | 
			
		||||
                    this._nfts.push({ id: nftIds[i], tokenId });
 | 
			
		||||
                    nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString].push(nftIds[i]);
 | 
			
		||||
                    await dummyWrapper.setApprovalForAllAsync(
 | 
			
		||||
                        tokenOwnerAddress,
 | 
			
		||||
                        (this._proxyContract as ERC1155ProxyContract).address,
 | 
			
		||||
                        true,
 | 
			
		||||
                    );
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        this._initialTokenIdsByOwner = {
 | 
			
		||||
            fungible: fungibleHoldingsByOwner,
 | 
			
		||||
            nonFungible: nonFungibleHoldingsByOwner,
 | 
			
		||||
        };
 | 
			
		||||
        return this._initialTokenIdsByOwner;
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev For each deployed ERC1155 contract, this function quieries the set of fungible/non-fungible
 | 
			
		||||
     *      tokens for each token owner address (`_tokenOwnerAddresses`).
 | 
			
		||||
     * @return Balances of each token owner, across all ERC1155 contracts and tokens.
 | 
			
		||||
     */
 | 
			
		||||
    public async getBalancesAsync(): Promise<ERC1155HoldingsByOwner> {
 | 
			
		||||
        this._validateDummyTokenContractsExistOrThrow();
 | 
			
		||||
        this._validateBalancesAndAllowancesSetOrThrow();
 | 
			
		||||
        const tokenHoldingsByOwner: ERC1155FungibleHoldingsByOwner = {};
 | 
			
		||||
        const nonFungibleHoldingsByOwner: ERC1155NonFungibleHoldingsByOwner = {};
 | 
			
		||||
        for (const dummyTokenWrapper of this._dummyTokenWrappers) {
 | 
			
		||||
            const tokenContract = dummyTokenWrapper.getContract();
 | 
			
		||||
            const tokenAddress = tokenContract.address;
 | 
			
		||||
            // Construct batch balance call
 | 
			
		||||
            const tokenOwners: string[] = [];
 | 
			
		||||
            const tokenIds: BigNumber[] = [];
 | 
			
		||||
            for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
 | 
			
		||||
                for (const tokenId of this._fungibleTokenIds) {
 | 
			
		||||
                    tokenOwners.push(tokenOwnerAddress);
 | 
			
		||||
                    tokenIds.push(new BigNumber(tokenId));
 | 
			
		||||
                }
 | 
			
		||||
                for (const nft of this._nfts) {
 | 
			
		||||
                    tokenOwners.push(tokenOwnerAddress);
 | 
			
		||||
                    tokenIds.push(nft.id);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            const balances = await dummyTokenWrapper.getBalancesAsync(tokenOwners, tokenIds);
 | 
			
		||||
            // Parse out balances into fungible / non-fungible token holdings
 | 
			
		||||
            let i = 0;
 | 
			
		||||
            for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
 | 
			
		||||
                // Fungible tokens
 | 
			
		||||
                for (const tokenId of this._fungibleTokenIds) {
 | 
			
		||||
                    if (tokenHoldingsByOwner[tokenOwnerAddress] === undefined) {
 | 
			
		||||
                        tokenHoldingsByOwner[tokenOwnerAddress] = {};
 | 
			
		||||
                    }
 | 
			
		||||
                    if (tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress] === undefined) {
 | 
			
		||||
                        tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress] = {};
 | 
			
		||||
                    }
 | 
			
		||||
                    tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress][tokenId] = balances[i++];
 | 
			
		||||
                }
 | 
			
		||||
                // Non-fungible tokens
 | 
			
		||||
                for (const nft of this._nfts) {
 | 
			
		||||
                    if (nonFungibleHoldingsByOwner[tokenOwnerAddress] === undefined) {
 | 
			
		||||
                        nonFungibleHoldingsByOwner[tokenOwnerAddress] = {};
 | 
			
		||||
                    }
 | 
			
		||||
                    if (nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress] === undefined) {
 | 
			
		||||
                        nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress] = {};
 | 
			
		||||
                    }
 | 
			
		||||
                    if (
 | 
			
		||||
                        nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()] ===
 | 
			
		||||
                        undefined
 | 
			
		||||
                    ) {
 | 
			
		||||
                        nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()] = [];
 | 
			
		||||
                    }
 | 
			
		||||
                    const isOwner = balances[i++];
 | 
			
		||||
                    if (isOwner.isEqualTo(1)) {
 | 
			
		||||
                        nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()].push(
 | 
			
		||||
                            nft.id,
 | 
			
		||||
                        );
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        const holdingsByOwner = {
 | 
			
		||||
            fungible: tokenHoldingsByOwner,
 | 
			
		||||
            nonFungible: nonFungibleHoldingsByOwner,
 | 
			
		||||
        };
 | 
			
		||||
        return holdingsByOwner;
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Checks if proxy is approved to transfer tokens on behalf of `userAddress`.
 | 
			
		||||
     * @param userAddress owner of ERC1155 tokens.
 | 
			
		||||
     * @param contractAddress address of ERC1155 contract.
 | 
			
		||||
     * @return True iff the proxy is approved for all. False otherwise.
 | 
			
		||||
     */
 | 
			
		||||
    public async isProxyApprovedForAllAsync(userAddress: string, contractAddress: string): Promise<boolean> {
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        const tokenContract = this._getContractFromAddress(contractAddress);
 | 
			
		||||
        const operator = (this._proxyContract as ERC1155ProxyContract).address;
 | 
			
		||||
        const didApproveAll = await tokenContract.isApprovedForAll.callAsync(userAddress, operator);
 | 
			
		||||
        return didApproveAll;
 | 
			
		||||
    }
 | 
			
		||||
    public getFungibleTokenIds(): BigNumber[] {
 | 
			
		||||
        const fungibleTokenIds = _.map(this._fungibleTokenIds, (tokenIdAsString: string) => {
 | 
			
		||||
            return new BigNumber(tokenIdAsString);
 | 
			
		||||
        });
 | 
			
		||||
        return fungibleTokenIds;
 | 
			
		||||
    }
 | 
			
		||||
    public getNonFungibleTokenIds(): BigNumber[] {
 | 
			
		||||
        const nonFungibleTokenIds = _.map(this._nonFungibleTokenIds, (tokenIdAsString: string) => {
 | 
			
		||||
            return new BigNumber(tokenIdAsString);
 | 
			
		||||
        });
 | 
			
		||||
        return nonFungibleTokenIds;
 | 
			
		||||
    }
 | 
			
		||||
    public getTokenOwnerAddresses(): string[] {
 | 
			
		||||
        return this._tokenOwnerAddresses;
 | 
			
		||||
    }
 | 
			
		||||
    public getContractWrapper(contractAddress: string): Erc1155Wrapper {
 | 
			
		||||
        const tokenWrapper = _.find(this._dummyTokenWrappers, (wrapper: Erc1155Wrapper) => {
 | 
			
		||||
            return wrapper.getContract().address === contractAddress;
 | 
			
		||||
        });
 | 
			
		||||
        if (tokenWrapper === undefined) {
 | 
			
		||||
            throw new Error(`Contract: ${contractAddress} was not deployed through ERC1155ProxyWrapper`);
 | 
			
		||||
        }
 | 
			
		||||
        return tokenWrapper;
 | 
			
		||||
    }
 | 
			
		||||
    private _getContractFromAddress(tokenAddress: string): ERC1155MintableContract {
 | 
			
		||||
        const tokenContractIfExists = _.find(this._dummyTokenWrappers, c => c.getContract().address === tokenAddress);
 | 
			
		||||
        if (tokenContractIfExists === undefined) {
 | 
			
		||||
            throw new Error(`Token: ${tokenAddress} was not deployed through ERC1155ProxyWrapper`);
 | 
			
		||||
        }
 | 
			
		||||
        return tokenContractIfExists.getContract();
 | 
			
		||||
    }
 | 
			
		||||
    private _validateDummyTokenContractsExistOrThrow(): void {
 | 
			
		||||
        if (this._dummyTokenWrappers === undefined) {
 | 
			
		||||
            throw new Error('Dummy ERC1155 tokens not yet deployed, please call "deployDummyTokensAsync"');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    private _validateProxyContractExistsOrThrow(): void {
 | 
			
		||||
        if (this._proxyContract === undefined) {
 | 
			
		||||
            throw new Error('ERC1155 proxy contract not yet deployed, please call "deployProxyAsync"');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    private _validateBalancesAndAllowancesSetOrThrow(): void {
 | 
			
		||||
        if (
 | 
			
		||||
            _.keys(this._initialTokenIdsByOwner.fungible).length === 0 ||
 | 
			
		||||
            _.keys(this._initialTokenIdsByOwner.nonFungible).length === 0
 | 
			
		||||
        ) {
 | 
			
		||||
            throw new Error(
 | 
			
		||||
                'Dummy ERC1155 balances and allowances not yet set, please call "setBalancesAndAllowancesAsync"',
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										173
									
								
								contracts/asset-proxy/test/utils/erc20_wrapper.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								contracts/asset-proxy/test/utils/erc20_wrapper.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,173 @@
 | 
			
		||||
import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20';
 | 
			
		||||
import { constants, ERC20BalancesByOwner, txDefaults } from '@0x/contracts-test-utils';
 | 
			
		||||
import { assetDataUtils } from '@0x/order-utils';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
import { ZeroExProvider } from 'ethereum-types';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
import { artifacts, ERC20ProxyContract } from '../../src';
 | 
			
		||||
 | 
			
		||||
export class ERC20Wrapper {
 | 
			
		||||
    private readonly _tokenOwnerAddresses: string[];
 | 
			
		||||
    private readonly _contractOwnerAddress: string;
 | 
			
		||||
    private readonly _provider: ZeroExProvider;
 | 
			
		||||
    private readonly _dummyTokenContracts: DummyERC20TokenContract[];
 | 
			
		||||
    private _proxyContract?: ERC20ProxyContract;
 | 
			
		||||
    private _proxyIdIfExists?: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * Instanitates an ERC20Wrapper
 | 
			
		||||
     * @param provider Web3 provider to use for all JSON RPC requests
 | 
			
		||||
     * @param tokenOwnerAddresses Addresses that we want to endow as owners for dummy ERC20 tokens
 | 
			
		||||
     * @param contractOwnerAddress Desired owner of the contract
 | 
			
		||||
     * Instance of ERC20Wrapper
 | 
			
		||||
     */
 | 
			
		||||
    constructor(provider: ZeroExProvider, tokenOwnerAddresses: string[], contractOwnerAddress: string) {
 | 
			
		||||
        this._dummyTokenContracts = [];
 | 
			
		||||
        this._provider = provider;
 | 
			
		||||
        this._tokenOwnerAddresses = tokenOwnerAddresses;
 | 
			
		||||
        this._contractOwnerAddress = contractOwnerAddress;
 | 
			
		||||
    }
 | 
			
		||||
    public async deployDummyTokensAsync(
 | 
			
		||||
        numberToDeploy: number,
 | 
			
		||||
        decimals: BigNumber,
 | 
			
		||||
    ): Promise<DummyERC20TokenContract[]> {
 | 
			
		||||
        for (let i = 0; i < numberToDeploy; i++) {
 | 
			
		||||
            this._dummyTokenContracts.push(
 | 
			
		||||
                await DummyERC20TokenContract.deployFrom0xArtifactAsync(
 | 
			
		||||
                    erc20Artifacts.DummyERC20Token,
 | 
			
		||||
                    this._provider,
 | 
			
		||||
                    txDefaults,
 | 
			
		||||
                    artifacts,
 | 
			
		||||
                    constants.DUMMY_TOKEN_NAME,
 | 
			
		||||
                    constants.DUMMY_TOKEN_SYMBOL,
 | 
			
		||||
                    decimals,
 | 
			
		||||
                    constants.DUMMY_TOKEN_TOTAL_SUPPLY,
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        return this._dummyTokenContracts;
 | 
			
		||||
    }
 | 
			
		||||
    public async deployProxyAsync(): Promise<ERC20ProxyContract> {
 | 
			
		||||
        this._proxyContract = await ERC20ProxyContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.ERC20Proxy,
 | 
			
		||||
            this._provider,
 | 
			
		||||
            txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
        this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync();
 | 
			
		||||
        return this._proxyContract;
 | 
			
		||||
    }
 | 
			
		||||
    public getProxyId(): string {
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        return this._proxyIdIfExists as string;
 | 
			
		||||
    }
 | 
			
		||||
    public async setBalancesAndAllowancesAsync(): Promise<void> {
 | 
			
		||||
        this._validateDummyTokenContractsExistOrThrow();
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        for (const dummyTokenContract of this._dummyTokenContracts) {
 | 
			
		||||
            for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
 | 
			
		||||
                await dummyTokenContract.setBalance.awaitTransactionSuccessAsync(
 | 
			
		||||
                    tokenOwnerAddress,
 | 
			
		||||
                    constants.INITIAL_ERC20_BALANCE,
 | 
			
		||||
                    { from: this._contractOwnerAddress },
 | 
			
		||||
                    constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
                );
 | 
			
		||||
                await dummyTokenContract.approve.awaitTransactionSuccessAsync(
 | 
			
		||||
                    (this._proxyContract as ERC20ProxyContract).address,
 | 
			
		||||
                    constants.INITIAL_ERC20_ALLOWANCE,
 | 
			
		||||
                    { from: tokenOwnerAddress },
 | 
			
		||||
                    constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    public async getBalanceAsync(userAddress: string, assetData: string): Promise<BigNumber> {
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(assetData);
 | 
			
		||||
        const balance = new BigNumber(await tokenContract.balanceOf.callAsync(userAddress));
 | 
			
		||||
        return balance;
 | 
			
		||||
    }
 | 
			
		||||
    public async setBalanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> {
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(assetData);
 | 
			
		||||
        await tokenContract.setBalance.awaitTransactionSuccessAsync(
 | 
			
		||||
            userAddress,
 | 
			
		||||
            amount,
 | 
			
		||||
            { from: this._contractOwnerAddress },
 | 
			
		||||
            constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise<BigNumber> {
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(assetData);
 | 
			
		||||
        const proxyAddress = (this._proxyContract as ERC20ProxyContract).address;
 | 
			
		||||
        const allowance = new BigNumber(await tokenContract.allowance.callAsync(userAddress, proxyAddress));
 | 
			
		||||
        return allowance;
 | 
			
		||||
    }
 | 
			
		||||
    public async setAllowanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> {
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(assetData);
 | 
			
		||||
        const proxyAddress = (this._proxyContract as ERC20ProxyContract).address;
 | 
			
		||||
        await tokenContract.approve.awaitTransactionSuccessAsync(
 | 
			
		||||
            proxyAddress,
 | 
			
		||||
            amount,
 | 
			
		||||
            { from: userAddress },
 | 
			
		||||
            constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    public async getBalancesAsync(): Promise<ERC20BalancesByOwner> {
 | 
			
		||||
        this._validateDummyTokenContractsExistOrThrow();
 | 
			
		||||
        const balancesByOwner: ERC20BalancesByOwner = {};
 | 
			
		||||
        const balances: BigNumber[] = [];
 | 
			
		||||
        const balanceInfo: Array<{ tokenOwnerAddress: string; tokenAddress: string }> = [];
 | 
			
		||||
        for (const dummyTokenContract of this._dummyTokenContracts) {
 | 
			
		||||
            for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
 | 
			
		||||
                balances.push(await dummyTokenContract.balanceOf.callAsync(tokenOwnerAddress));
 | 
			
		||||
                balanceInfo.push({
 | 
			
		||||
                    tokenOwnerAddress,
 | 
			
		||||
                    tokenAddress: dummyTokenContract.address,
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        _.forEach(balances, (balance, balanceIndex) => {
 | 
			
		||||
            const tokenAddress = balanceInfo[balanceIndex].tokenAddress;
 | 
			
		||||
            const tokenOwnerAddress = balanceInfo[balanceIndex].tokenOwnerAddress;
 | 
			
		||||
            if (balancesByOwner[tokenOwnerAddress] === undefined) {
 | 
			
		||||
                balancesByOwner[tokenOwnerAddress] = {};
 | 
			
		||||
            }
 | 
			
		||||
            const wrappedBalance = new BigNumber(balance);
 | 
			
		||||
            balancesByOwner[tokenOwnerAddress][tokenAddress] = wrappedBalance;
 | 
			
		||||
        });
 | 
			
		||||
        return balancesByOwner;
 | 
			
		||||
    }
 | 
			
		||||
    public addDummyTokenContract(dummy: DummyERC20TokenContract): void {
 | 
			
		||||
        if (this._dummyTokenContracts !== undefined) {
 | 
			
		||||
            this._dummyTokenContracts.push(dummy);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    public addTokenOwnerAddress(address: string): void {
 | 
			
		||||
        this._tokenOwnerAddresses.push(address);
 | 
			
		||||
    }
 | 
			
		||||
    public getTokenOwnerAddresses(): string[] {
 | 
			
		||||
        return this._tokenOwnerAddresses;
 | 
			
		||||
    }
 | 
			
		||||
    public getTokenAddresses(): string[] {
 | 
			
		||||
        const tokenAddresses = _.map(this._dummyTokenContracts, dummyTokenContract => dummyTokenContract.address);
 | 
			
		||||
        return tokenAddresses;
 | 
			
		||||
    }
 | 
			
		||||
    private _getTokenContractFromAssetData(assetData: string): DummyERC20TokenContract {
 | 
			
		||||
        const erc20ProxyData = assetDataUtils.decodeERC20AssetData(assetData);
 | 
			
		||||
        const tokenAddress = erc20ProxyData.tokenAddress;
 | 
			
		||||
        const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress);
 | 
			
		||||
        if (tokenContractIfExists === undefined) {
 | 
			
		||||
            throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`);
 | 
			
		||||
        }
 | 
			
		||||
        return tokenContractIfExists;
 | 
			
		||||
    }
 | 
			
		||||
    private _validateDummyTokenContractsExistOrThrow(): void {
 | 
			
		||||
        if (this._dummyTokenContracts === undefined) {
 | 
			
		||||
            throw new Error('Dummy ERC20 tokens not yet deployed, please call "deployDummyTokensAsync"');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    private _validateProxyContractExistsOrThrow(): void {
 | 
			
		||||
        if (this._proxyContract === undefined) {
 | 
			
		||||
            throw new Error('ERC20 proxy contract not yet deployed, please call "deployProxyAsync"');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										235
									
								
								contracts/asset-proxy/test/utils/erc721_wrapper.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										235
									
								
								contracts/asset-proxy/test/utils/erc721_wrapper.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,235 @@
 | 
			
		||||
import { artifacts as erc721Artifacts, DummyERC721TokenContract } from '@0x/contracts-erc721';
 | 
			
		||||
import { constants, ERC721TokenIdsByOwner, txDefaults } from '@0x/contracts-test-utils';
 | 
			
		||||
import { generatePseudoRandomSalt } from '@0x/order-utils';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
import { ZeroExProvider } from 'ethereum-types';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
import { artifacts, ERC721ProxyContract } from '../../src';
 | 
			
		||||
 | 
			
		||||
export class ERC721Wrapper {
 | 
			
		||||
    private readonly _tokenOwnerAddresses: string[];
 | 
			
		||||
    private readonly _contractOwnerAddress: string;
 | 
			
		||||
    private readonly _provider: ZeroExProvider;
 | 
			
		||||
    private readonly _dummyTokenContracts: DummyERC721TokenContract[];
 | 
			
		||||
    private _proxyContract?: ERC721ProxyContract;
 | 
			
		||||
    private _proxyIdIfExists?: string;
 | 
			
		||||
    private _initialTokenIdsByOwner: ERC721TokenIdsByOwner = {};
 | 
			
		||||
    constructor(provider: ZeroExProvider, tokenOwnerAddresses: string[], contractOwnerAddress: string) {
 | 
			
		||||
        this._provider = provider;
 | 
			
		||||
        this._dummyTokenContracts = [];
 | 
			
		||||
        this._tokenOwnerAddresses = tokenOwnerAddresses;
 | 
			
		||||
        this._contractOwnerAddress = contractOwnerAddress;
 | 
			
		||||
    }
 | 
			
		||||
    public async deployDummyTokensAsync(): Promise<DummyERC721TokenContract[]> {
 | 
			
		||||
        // tslint:disable-next-line:no-unused-variable
 | 
			
		||||
        for (const i of _.times(constants.NUM_DUMMY_ERC721_TO_DEPLOY)) {
 | 
			
		||||
            this._dummyTokenContracts.push(
 | 
			
		||||
                await DummyERC721TokenContract.deployFrom0xArtifactAsync(
 | 
			
		||||
                    erc721Artifacts.DummyERC721Token,
 | 
			
		||||
                    this._provider,
 | 
			
		||||
                    txDefaults,
 | 
			
		||||
                    artifacts,
 | 
			
		||||
                    constants.DUMMY_TOKEN_NAME,
 | 
			
		||||
                    constants.DUMMY_TOKEN_SYMBOL,
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        return this._dummyTokenContracts;
 | 
			
		||||
    }
 | 
			
		||||
    public async deployProxyAsync(): Promise<ERC721ProxyContract> {
 | 
			
		||||
        this._proxyContract = await ERC721ProxyContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.ERC721Proxy,
 | 
			
		||||
            this._provider,
 | 
			
		||||
            txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
        this._proxyIdIfExists = await this._proxyContract.getProxyId.callAsync();
 | 
			
		||||
        return this._proxyContract;
 | 
			
		||||
    }
 | 
			
		||||
    public getProxyId(): string {
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        return this._proxyIdIfExists as string;
 | 
			
		||||
    }
 | 
			
		||||
    public async setBalancesAndAllowancesAsync(): Promise<void> {
 | 
			
		||||
        this._validateDummyTokenContractsExistOrThrow();
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        this._initialTokenIdsByOwner = {};
 | 
			
		||||
        for (const dummyTokenContract of this._dummyTokenContracts) {
 | 
			
		||||
            for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
 | 
			
		||||
                // tslint:disable-next-line:no-unused-variable
 | 
			
		||||
                for (const i of _.times(constants.NUM_ERC721_TOKENS_TO_MINT)) {
 | 
			
		||||
                    const tokenId = generatePseudoRandomSalt();
 | 
			
		||||
                    await this.mintAsync(dummyTokenContract.address, tokenId, tokenOwnerAddress);
 | 
			
		||||
                    if (this._initialTokenIdsByOwner[tokenOwnerAddress] === undefined) {
 | 
			
		||||
                        this._initialTokenIdsByOwner[tokenOwnerAddress] = {
 | 
			
		||||
                            [dummyTokenContract.address]: [],
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                    if (this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address] === undefined) {
 | 
			
		||||
                        this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address] = [];
 | 
			
		||||
                    }
 | 
			
		||||
                    this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address].push(tokenId);
 | 
			
		||||
 | 
			
		||||
                    await this.approveProxyAsync(dummyTokenContract.address, tokenId);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    public async doesTokenExistAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> {
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
 | 
			
		||||
        const owner = await tokenContract.ownerOf.callAsync(tokenId);
 | 
			
		||||
        const doesExist = owner !== constants.NULL_ADDRESS;
 | 
			
		||||
        return doesExist;
 | 
			
		||||
    }
 | 
			
		||||
    public async approveProxyAsync(tokenAddress: string, tokenId: BigNumber): Promise<void> {
 | 
			
		||||
        const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
 | 
			
		||||
        await this.approveAsync(proxyAddress, tokenAddress, tokenId);
 | 
			
		||||
    }
 | 
			
		||||
    public async approveProxyForAllAsync(tokenAddress: string, tokenId: BigNumber, isApproved: boolean): Promise<void> {
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
 | 
			
		||||
        const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId);
 | 
			
		||||
        const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
 | 
			
		||||
        await tokenContract.setApprovalForAll.awaitTransactionSuccessAsync(
 | 
			
		||||
            proxyAddress,
 | 
			
		||||
            isApproved,
 | 
			
		||||
            { from: tokenOwner },
 | 
			
		||||
            constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    public async approveAsync(to: string, tokenAddress: string, tokenId: BigNumber): Promise<void> {
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
 | 
			
		||||
        const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId);
 | 
			
		||||
        await tokenContract.approve.awaitTransactionSuccessAsync(
 | 
			
		||||
            to,
 | 
			
		||||
            tokenId,
 | 
			
		||||
            { from: tokenOwner },
 | 
			
		||||
            constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    public async transferFromAsync(
 | 
			
		||||
        tokenAddress: string,
 | 
			
		||||
        tokenId: BigNumber,
 | 
			
		||||
        currentOwner: string,
 | 
			
		||||
        userAddress: string,
 | 
			
		||||
    ): Promise<void> {
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
 | 
			
		||||
        await tokenContract.transferFrom.awaitTransactionSuccessAsync(
 | 
			
		||||
            currentOwner,
 | 
			
		||||
            userAddress,
 | 
			
		||||
            tokenId,
 | 
			
		||||
            { from: currentOwner },
 | 
			
		||||
            constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    public async mintAsync(tokenAddress: string, tokenId: BigNumber, userAddress: string): Promise<void> {
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
 | 
			
		||||
        await tokenContract.mint.awaitTransactionSuccessAsync(
 | 
			
		||||
            userAddress,
 | 
			
		||||
            tokenId,
 | 
			
		||||
            { from: this._contractOwnerAddress },
 | 
			
		||||
            constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    public async burnAsync(tokenAddress: string, tokenId: BigNumber, owner: string): Promise<void> {
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
 | 
			
		||||
        await tokenContract.burn.awaitTransactionSuccessAsync(
 | 
			
		||||
            owner,
 | 
			
		||||
            tokenId,
 | 
			
		||||
            { from: this._contractOwnerAddress },
 | 
			
		||||
            constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    public async ownerOfAsync(tokenAddress: string, tokenId: BigNumber): Promise<string> {
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
 | 
			
		||||
        const owner = await tokenContract.ownerOf.callAsync(tokenId);
 | 
			
		||||
        return owner;
 | 
			
		||||
    }
 | 
			
		||||
    public async isOwnerAsync(userAddress: string, tokenAddress: string, tokenId: BigNumber): Promise<boolean> {
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
 | 
			
		||||
        const tokenOwner = await tokenContract.ownerOf.callAsync(tokenId);
 | 
			
		||||
        const isOwner = tokenOwner === userAddress;
 | 
			
		||||
        return isOwner;
 | 
			
		||||
    }
 | 
			
		||||
    public async isProxyApprovedForAllAsync(userAddress: string, tokenAddress: string): Promise<boolean> {
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
 | 
			
		||||
        const operator = (this._proxyContract as ERC721ProxyContract).address;
 | 
			
		||||
        const didApproveAll = await tokenContract.isApprovedForAll.callAsync(userAddress, operator);
 | 
			
		||||
        return didApproveAll;
 | 
			
		||||
    }
 | 
			
		||||
    public async isProxyApprovedAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> {
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
 | 
			
		||||
        const approvedAddress = await tokenContract.getApproved.callAsync(tokenId);
 | 
			
		||||
        const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
 | 
			
		||||
        const isProxyAnApprovedOperator = approvedAddress === proxyAddress;
 | 
			
		||||
        return isProxyAnApprovedOperator;
 | 
			
		||||
    }
 | 
			
		||||
    public async getBalancesAsync(): Promise<ERC721TokenIdsByOwner> {
 | 
			
		||||
        this._validateDummyTokenContractsExistOrThrow();
 | 
			
		||||
        this._validateBalancesAndAllowancesSetOrThrow();
 | 
			
		||||
        const tokenIdsByOwner: ERC721TokenIdsByOwner = {};
 | 
			
		||||
        const tokenOwnerAddresses: string[] = [];
 | 
			
		||||
        const tokenInfo: Array<{ tokenId: BigNumber; tokenAddress: string }> = [];
 | 
			
		||||
        for (const dummyTokenContract of this._dummyTokenContracts) {
 | 
			
		||||
            for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
 | 
			
		||||
                const initialTokenOwnerIds = this._initialTokenIdsByOwner[tokenOwnerAddress][
 | 
			
		||||
                    dummyTokenContract.address
 | 
			
		||||
                ];
 | 
			
		||||
                for (const tokenId of initialTokenOwnerIds) {
 | 
			
		||||
                    tokenOwnerAddresses.push(await dummyTokenContract.ownerOf.callAsync(tokenId));
 | 
			
		||||
                    tokenInfo.push({
 | 
			
		||||
                        tokenId,
 | 
			
		||||
                        tokenAddress: dummyTokenContract.address,
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        _.forEach(tokenOwnerAddresses, (tokenOwnerAddress, ownerIndex) => {
 | 
			
		||||
            const tokenAddress = tokenInfo[ownerIndex].tokenAddress;
 | 
			
		||||
            const tokenId = tokenInfo[ownerIndex].tokenId;
 | 
			
		||||
            if (tokenIdsByOwner[tokenOwnerAddress] === undefined) {
 | 
			
		||||
                tokenIdsByOwner[tokenOwnerAddress] = {
 | 
			
		||||
                    [tokenAddress]: [],
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
            if (tokenIdsByOwner[tokenOwnerAddress][tokenAddress] === undefined) {
 | 
			
		||||
                tokenIdsByOwner[tokenOwnerAddress][tokenAddress] = [];
 | 
			
		||||
            }
 | 
			
		||||
            tokenIdsByOwner[tokenOwnerAddress][tokenAddress].push(tokenId);
 | 
			
		||||
        });
 | 
			
		||||
        return tokenIdsByOwner;
 | 
			
		||||
    }
 | 
			
		||||
    public getTokenOwnerAddresses(): string[] {
 | 
			
		||||
        return this._tokenOwnerAddresses;
 | 
			
		||||
    }
 | 
			
		||||
    public getTokenAddresses(): string[] {
 | 
			
		||||
        const tokenAddresses = _.map(this._dummyTokenContracts, dummyTokenContract => dummyTokenContract.address);
 | 
			
		||||
        return tokenAddresses;
 | 
			
		||||
    }
 | 
			
		||||
    private _getTokenContractFromAssetData(tokenAddress: string): DummyERC721TokenContract {
 | 
			
		||||
        const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress);
 | 
			
		||||
        if (tokenContractIfExists === undefined) {
 | 
			
		||||
            throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`);
 | 
			
		||||
        }
 | 
			
		||||
        return tokenContractIfExists;
 | 
			
		||||
    }
 | 
			
		||||
    private _validateDummyTokenContractsExistOrThrow(): void {
 | 
			
		||||
        if (this._dummyTokenContracts === undefined) {
 | 
			
		||||
            throw new Error('Dummy ERC721 tokens not yet deployed, please call "deployDummyTokensAsync"');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    private _validateProxyContractExistsOrThrow(): void {
 | 
			
		||||
        if (this._proxyContract === undefined) {
 | 
			
		||||
            throw new Error('ERC721 proxy contract not yet deployed, please call "deployProxyAsync"');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    private _validateBalancesAndAllowancesSetOrThrow(): void {
 | 
			
		||||
        if (_.keys(this._initialTokenIdsByOwner).length === 0) {
 | 
			
		||||
            throw new Error(
 | 
			
		||||
                'Dummy ERC721 balances and allowances not yet set, please call "setBalancesAndAllowancesAsync"',
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3
									
								
								contracts/asset-proxy/test/utils/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								contracts/asset-proxy/test/utils/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
export * from './erc20_wrapper';
 | 
			
		||||
export * from './erc721_wrapper';
 | 
			
		||||
export * from './erc1155_proxy_wrapper';
 | 
			
		||||
							
								
								
									
										18
									
								
								contracts/asset-proxy/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								contracts/asset-proxy/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
{
 | 
			
		||||
    "extends": "../../tsconfig",
 | 
			
		||||
    "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
 | 
			
		||||
    "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
 | 
			
		||||
    "files": [
 | 
			
		||||
        "generated-artifacts/ERC1155Proxy.json",
 | 
			
		||||
        "generated-artifacts/ERC20Proxy.json",
 | 
			
		||||
        "generated-artifacts/ERC721Proxy.json",
 | 
			
		||||
        "generated-artifacts/IAssetData.json",
 | 
			
		||||
        "generated-artifacts/IAssetProxy.json",
 | 
			
		||||
        "generated-artifacts/IAuthorizable.json",
 | 
			
		||||
        "generated-artifacts/MixinAuthorizable.json",
 | 
			
		||||
        "generated-artifacts/MultiAssetProxy.json",
 | 
			
		||||
        "generated-artifacts/StaticCallProxy.json",
 | 
			
		||||
        "generated-artifacts/TestStaticCallTarget.json"
 | 
			
		||||
    ],
 | 
			
		||||
    "exclude": ["./deploy/solc/solc_bin"]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								contracts/asset-proxy/tslint.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								contracts/asset-proxy/tslint.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "extends": ["@0x/tslint-config"],
 | 
			
		||||
    "rules": {
 | 
			
		||||
        "custom-no-magic-numbers": false
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										147
									
								
								contracts/coordinator/CHANGELOG.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								contracts/coordinator/CHANGELOG.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,147 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1566446343,
 | 
			
		||||
        "version": "2.0.11",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1565296576,
 | 
			
		||||
        "version": "2.0.10",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "2.0.9",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Updated calls to <contract wrapper>.deployFrom0xArtifactAsync to include artifact dependencies.",
 | 
			
		||||
                "pr": 1995
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1564607468
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1563957393,
 | 
			
		||||
        "version": "2.0.8",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1563193019,
 | 
			
		||||
        "version": "2.0.7",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1563047529,
 | 
			
		||||
        "version": "2.0.6",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1563006338,
 | 
			
		||||
        "version": "2.0.5",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1558712885,
 | 
			
		||||
        "version": "2.0.4",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1557961111,
 | 
			
		||||
        "version": "2.0.3",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1557799313,
 | 
			
		||||
        "version": "2.0.2",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1557507213,
 | 
			
		||||
        "version": "2.0.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "2.0.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Make `decodeOrdersFromFillData`, `getCoordinatorApprovalHash`, and `getTransactionHash` public",
 | 
			
		||||
                "pr": 1729
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Make `assertValidTransactionOrdersApproval` internal",
 | 
			
		||||
                "pr": 1729
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1554997931
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "1.1.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Run Web3ProviderEngine without excess block polling",
 | 
			
		||||
                "pr": 1695
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1553183790
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "1.0.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Created Coordinator package"
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Use separate EIP712 domains for transactions and approvals",
 | 
			
		||||
                "pr": 1705
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add `SignatureType.Invalid`",
 | 
			
		||||
                "pr": 1705
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Set `evmVersion` to `constantinople`",
 | 
			
		||||
                "pr": 1707
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1553091633
 | 
			
		||||
    }
 | 
			
		||||
]
 | 
			
		||||
							
								
								
									
										66
									
								
								contracts/coordinator/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								contracts/coordinator/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
<!--
 | 
			
		||||
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
 | 
			
		||||
Edit the package's CHANGELOG.json file only.
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v2.0.11 - _August 22, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.0.10 - _August 8, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.0.9 - _July 31, 2019_
 | 
			
		||||
 | 
			
		||||
    * Updated calls to <contract wrapper>.deployFrom0xArtifactAsync to include artifact dependencies. (#1995)
 | 
			
		||||
 | 
			
		||||
## v2.0.8 - _July 24, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.0.7 - _July 15, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.0.6 - _July 13, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.0.5 - _July 13, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.0.4 - _May 24, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.0.3 - _May 15, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.0.2 - _May 14, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.0.1 - _May 10, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.0.0 - _April 11, 2019_
 | 
			
		||||
 | 
			
		||||
    * Make `decodeOrdersFromFillData`, `getCoordinatorApprovalHash`, and `getTransactionHash` public (#1729)
 | 
			
		||||
    * Make `assertValidTransactionOrdersApproval` internal (#1729)
 | 
			
		||||
 | 
			
		||||
## v1.1.0 - _March 21, 2019_
 | 
			
		||||
 | 
			
		||||
    * Run Web3ProviderEngine without excess block polling (#1695)
 | 
			
		||||
 | 
			
		||||
## v1.0.0 - _March 20, 2019_
 | 
			
		||||
 | 
			
		||||
    * Created Coordinator package
 | 
			
		||||
    * Use separate EIP712 domains for transactions and approvals (#1705)
 | 
			
		||||
    * Add `SignatureType.Invalid` (#1705)
 | 
			
		||||
    * Set `evmVersion` to `constantinople` (#1707)
 | 
			
		||||
							
								
								
									
										73
									
								
								contracts/coordinator/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								contracts/coordinator/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
## Coordinator
 | 
			
		||||
 | 
			
		||||
This package contains a contract that allows users to call arbitrary functions on the Exchange contract with permission from one or more Coordinators. Addresses of the deployed contracts can be found in the 0x [wiki](https://0xproject.com/wiki#Deployed-Addresses) or the [DEPLOYS](./DEPLOYS.json) file within this package.
 | 
			
		||||
 | 
			
		||||
## Installation
 | 
			
		||||
 | 
			
		||||
**Install**
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npm install @0x/contracts-coordinator --save
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 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-coordinator yarn build
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Or continuously rebuild on change:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
PKG=@0x/contracts-coordinator 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).
 | 
			
		||||
							
								
								
									
										26
									
								
								contracts/coordinator/compiler.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								contracts/coordinator/compiler.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
{
 | 
			
		||||
    "artifactsDir": "./generated-artifacts",
 | 
			
		||||
    "contractsDir": "./contracts",
 | 
			
		||||
    "useDockerisedSolc": false,
 | 
			
		||||
    "compilerSettings": {
 | 
			
		||||
        "evmVersion": "constantinople",
 | 
			
		||||
        "optimizer": {
 | 
			
		||||
            "enabled": true,
 | 
			
		||||
            "runs": 1000000,
 | 
			
		||||
            "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true }
 | 
			
		||||
        },
 | 
			
		||||
        "outputSelection": {
 | 
			
		||||
            "*": {
 | 
			
		||||
                "*": [
 | 
			
		||||
                    "abi",
 | 
			
		||||
                    "devdoc",
 | 
			
		||||
                    "evm.bytecode.object",
 | 
			
		||||
                    "evm.bytecode.sourceMap",
 | 
			
		||||
                    "evm.deployedBytecode.object",
 | 
			
		||||
                    "evm.deployedBytecode.sourceMap"
 | 
			
		||||
                ]
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    "contracts": ["src/Coordinator.sol", "src/registry/CoordinatorRegistry.sol"]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								contracts/coordinator/contracts/src/Coordinator.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								contracts/coordinator/contracts/src/Coordinator.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
pragma experimental "ABIEncoderV2";
 | 
			
		||||
 | 
			
		||||
import "./libs/LibConstants.sol";
 | 
			
		||||
import "./MixinSignatureValidator.sol";
 | 
			
		||||
import "./MixinCoordinatorApprovalVerifier.sol";
 | 
			
		||||
import "./MixinCoordinatorCore.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable no-empty-blocks
 | 
			
		||||
contract Coordinator is
 | 
			
		||||
    LibConstants,
 | 
			
		||||
    MixinSignatureValidator,
 | 
			
		||||
    MixinCoordinatorApprovalVerifier,
 | 
			
		||||
    MixinCoordinatorCore
 | 
			
		||||
{
 | 
			
		||||
    constructor (address _exchange)
 | 
			
		||||
        public
 | 
			
		||||
        LibConstants(_exchange)
 | 
			
		||||
    {}
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,203 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
pragma experimental "ABIEncoderV2";
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/LibExchangeSelectors.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
 | 
			
		||||
import "./libs/LibCoordinatorApproval.sol";
 | 
			
		||||
import "./libs/LibZeroExTransaction.sol";
 | 
			
		||||
import "./mixins/MSignatureValidator.sol";
 | 
			
		||||
import "./mixins/MCoordinatorApprovalVerifier.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable avoid-tx-origin
 | 
			
		||||
contract MixinCoordinatorApprovalVerifier is
 | 
			
		||||
    LibExchangeSelectors,
 | 
			
		||||
    LibCoordinatorApproval,
 | 
			
		||||
    LibZeroExTransaction,
 | 
			
		||||
    MSignatureValidator,
 | 
			
		||||
    MCoordinatorApprovalVerifier
 | 
			
		||||
{
 | 
			
		||||
    using LibBytes for bytes;
 | 
			
		||||
    using LibAddressArray for address[];
 | 
			
		||||
 | 
			
		||||
    /// @dev Validates that the 0x transaction has been approved by all of the feeRecipients
 | 
			
		||||
    ///      that correspond to each order in the transaction's Exchange calldata.
 | 
			
		||||
    /// @param transaction 0x transaction containing salt, signerAddress, and data.
 | 
			
		||||
    /// @param txOrigin Required signer of Ethereum transaction calling this function.
 | 
			
		||||
    /// @param transactionSignature Proof that the transaction has been signed by the signer.
 | 
			
		||||
    /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.
 | 
			
		||||
    /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.
 | 
			
		||||
    function assertValidCoordinatorApprovals(
 | 
			
		||||
        LibZeroExTransaction.ZeroExTransaction memory transaction,
 | 
			
		||||
        address txOrigin,
 | 
			
		||||
        bytes memory transactionSignature,
 | 
			
		||||
        uint256[] memory approvalExpirationTimeSeconds,
 | 
			
		||||
        bytes[] memory approvalSignatures
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
    {
 | 
			
		||||
        // Get the orders from the the Exchange calldata in the 0x transaction
 | 
			
		||||
        LibOrder.Order[] memory orders = decodeOrdersFromFillData(transaction.data);
 | 
			
		||||
 | 
			
		||||
        // No approval is required for non-fill methods
 | 
			
		||||
        if (orders.length > 0) {
 | 
			
		||||
            // Revert if approval is invalid for transaction orders
 | 
			
		||||
            assertValidTransactionOrdersApproval(
 | 
			
		||||
                transaction,
 | 
			
		||||
                orders,
 | 
			
		||||
                txOrigin,
 | 
			
		||||
                transactionSignature,
 | 
			
		||||
                approvalExpirationTimeSeconds,
 | 
			
		||||
                approvalSignatures
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Decodes the orders from Exchange calldata representing any fill method.
 | 
			
		||||
    /// @param data Exchange calldata representing a fill method.
 | 
			
		||||
    /// @return The orders from the Exchange calldata.
 | 
			
		||||
    function decodeOrdersFromFillData(bytes memory data)
 | 
			
		||||
        public
 | 
			
		||||
        pure
 | 
			
		||||
        returns (LibOrder.Order[] memory orders)
 | 
			
		||||
    {
 | 
			
		||||
        bytes4 selector = data.readBytes4(0);
 | 
			
		||||
        if (
 | 
			
		||||
            selector == FILL_ORDER_SELECTOR ||
 | 
			
		||||
            selector == FILL_ORDER_NO_THROW_SELECTOR ||
 | 
			
		||||
            selector == FILL_OR_KILL_ORDER_SELECTOR
 | 
			
		||||
        ) {
 | 
			
		||||
            // Decode single order
 | 
			
		||||
            (LibOrder.Order memory order) = abi.decode(
 | 
			
		||||
                data.slice(4, data.length),
 | 
			
		||||
                (LibOrder.Order)
 | 
			
		||||
            );
 | 
			
		||||
            orders = new LibOrder.Order[](1);
 | 
			
		||||
            orders[0] = order;
 | 
			
		||||
        } else if (
 | 
			
		||||
            selector == BATCH_FILL_ORDERS_SELECTOR ||
 | 
			
		||||
            selector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR ||
 | 
			
		||||
            selector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR ||
 | 
			
		||||
            selector == MARKET_BUY_ORDERS_SELECTOR ||
 | 
			
		||||
            selector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR ||
 | 
			
		||||
            selector == MARKET_SELL_ORDERS_SELECTOR ||
 | 
			
		||||
            selector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR
 | 
			
		||||
        ) {
 | 
			
		||||
            // Decode all orders
 | 
			
		||||
            // solhint-disable indent
 | 
			
		||||
            (orders) = abi.decode(
 | 
			
		||||
                data.slice(4, data.length),
 | 
			
		||||
                (LibOrder.Order[])
 | 
			
		||||
            );
 | 
			
		||||
        } else if (selector == MATCH_ORDERS_SELECTOR) {
 | 
			
		||||
            // Decode left and right orders
 | 
			
		||||
            (LibOrder.Order memory leftOrder, LibOrder.Order memory rightOrder) = abi.decode(
 | 
			
		||||
                data.slice(4, data.length),
 | 
			
		||||
                (LibOrder.Order, LibOrder.Order)
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // Create array of orders
 | 
			
		||||
            orders = new LibOrder.Order[](2);
 | 
			
		||||
            orders[0] = leftOrder;
 | 
			
		||||
            orders[1] = rightOrder;
 | 
			
		||||
        }
 | 
			
		||||
        return orders;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Validates that the feeRecipients of a batch of order have approved a 0x transaction.
 | 
			
		||||
    /// @param transaction 0x transaction containing salt, signerAddress, and data.
 | 
			
		||||
    /// @param orders Array of order structs containing order specifications.
 | 
			
		||||
    /// @param txOrigin Required signer of Ethereum transaction calling this function.
 | 
			
		||||
    /// @param transactionSignature Proof that the transaction has been signed by the signer.
 | 
			
		||||
    /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.
 | 
			
		||||
    /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order.
 | 
			
		||||
    function assertValidTransactionOrdersApproval(
 | 
			
		||||
        LibZeroExTransaction.ZeroExTransaction memory transaction,
 | 
			
		||||
        LibOrder.Order[] memory orders,
 | 
			
		||||
        address txOrigin,
 | 
			
		||||
        bytes memory transactionSignature,
 | 
			
		||||
        uint256[] memory approvalExpirationTimeSeconds,
 | 
			
		||||
        bytes[] memory approvalSignatures
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
    {
 | 
			
		||||
        // Verify that Ethereum tx signer is the same as the approved txOrigin
 | 
			
		||||
        require(
 | 
			
		||||
            tx.origin == txOrigin,
 | 
			
		||||
            "INVALID_ORIGIN"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Hash 0x transaction
 | 
			
		||||
        bytes32 transactionHash = getTransactionHash(transaction);
 | 
			
		||||
 | 
			
		||||
        // Create empty list of approval signers
 | 
			
		||||
        address[] memory approvalSignerAddresses = new address[](0);
 | 
			
		||||
 | 
			
		||||
        uint256 signaturesLength = approvalSignatures.length;
 | 
			
		||||
        for (uint256 i = 0; i != signaturesLength; i++) {
 | 
			
		||||
            // Create approval message
 | 
			
		||||
            uint256 currentApprovalExpirationTimeSeconds = approvalExpirationTimeSeconds[i];
 | 
			
		||||
            CoordinatorApproval memory approval = CoordinatorApproval({
 | 
			
		||||
                txOrigin: txOrigin,
 | 
			
		||||
                transactionHash: transactionHash,
 | 
			
		||||
                transactionSignature: transactionSignature,
 | 
			
		||||
                approvalExpirationTimeSeconds: currentApprovalExpirationTimeSeconds
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Ensure approval has not expired
 | 
			
		||||
            require(
 | 
			
		||||
                // solhint-disable-next-line not-rely-on-time
 | 
			
		||||
                currentApprovalExpirationTimeSeconds > block.timestamp,
 | 
			
		||||
                "APPROVAL_EXPIRED"
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // Hash approval message and recover signer address
 | 
			
		||||
            bytes32 approvalHash = getCoordinatorApprovalHash(approval);
 | 
			
		||||
            address approvalSignerAddress = getSignerAddress(approvalHash, approvalSignatures[i]);
 | 
			
		||||
 | 
			
		||||
            // Add approval signer to list of signers
 | 
			
		||||
            approvalSignerAddresses = approvalSignerAddresses.append(approvalSignerAddress);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Ethereum transaction signer gives implicit signature of approval
 | 
			
		||||
        approvalSignerAddresses = approvalSignerAddresses.append(tx.origin);
 | 
			
		||||
 | 
			
		||||
        uint256 ordersLength = orders.length;
 | 
			
		||||
        for (uint256 i = 0; i != ordersLength; i++) {
 | 
			
		||||
            // Do not check approval if the order's senderAddress is null
 | 
			
		||||
            if (orders[i].senderAddress == address(0)) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Ensure feeRecipient of order has approved this 0x transaction
 | 
			
		||||
            address approverAddress = orders[i].feeRecipientAddress;
 | 
			
		||||
            bool isOrderApproved = approvalSignerAddresses.contains(approverAddress);
 | 
			
		||||
            require(
 | 
			
		||||
                isOrderApproved,
 | 
			
		||||
                "INVALID_APPROVAL_SIGNATURE"
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										65
									
								
								contracts/coordinator/contracts/src/MixinCoordinatorCore.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								contracts/coordinator/contracts/src/MixinCoordinatorCore.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
pragma experimental "ABIEncoderV2";
 | 
			
		||||
 | 
			
		||||
import "./libs/LibZeroExTransaction.sol";
 | 
			
		||||
import "./libs/LibConstants.sol";
 | 
			
		||||
import "./mixins/MCoordinatorApprovalVerifier.sol";
 | 
			
		||||
import "./interfaces/ICoordinatorCore.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract MixinCoordinatorCore is
 | 
			
		||||
    LibConstants,
 | 
			
		||||
    MCoordinatorApprovalVerifier,
 | 
			
		||||
    ICoordinatorCore
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Executes a 0x transaction that has been signed by the feeRecipients that correspond to each order in the transaction's Exchange calldata.
 | 
			
		||||
    /// @param transaction 0x transaction containing salt, signerAddress, and data.
 | 
			
		||||
    /// @param txOrigin Required signer of Ethereum transaction calling this function.
 | 
			
		||||
    /// @param transactionSignature Proof that the transaction has been signed by the signer.
 | 
			
		||||
    /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.
 | 
			
		||||
    /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.
 | 
			
		||||
    function executeTransaction(
 | 
			
		||||
        LibZeroExTransaction.ZeroExTransaction memory transaction,
 | 
			
		||||
        address txOrigin,
 | 
			
		||||
        bytes memory transactionSignature,
 | 
			
		||||
        uint256[] memory approvalExpirationTimeSeconds,
 | 
			
		||||
        bytes[] memory approvalSignatures
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
    {
 | 
			
		||||
        // Validate that the 0x transaction has been approves by each feeRecipient
 | 
			
		||||
        assertValidCoordinatorApprovals(
 | 
			
		||||
            transaction,
 | 
			
		||||
            txOrigin,
 | 
			
		||||
            transactionSignature,
 | 
			
		||||
            approvalExpirationTimeSeconds,
 | 
			
		||||
            approvalSignatures
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Execute the transaction
 | 
			
		||||
        EXCHANGE.executeTransaction(
 | 
			
		||||
            transaction.salt,
 | 
			
		||||
            transaction.signerAddress,
 | 
			
		||||
            transaction.data,
 | 
			
		||||
            transactionSignature
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										118
									
								
								contracts/coordinator/contracts/src/MixinSignatureValidator.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								contracts/coordinator/contracts/src/MixinSignatureValidator.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,118 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
 | 
			
		||||
import "./mixins/MSignatureValidator.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract MixinSignatureValidator is
 | 
			
		||||
    MSignatureValidator
 | 
			
		||||
{
 | 
			
		||||
    using LibBytes for bytes;
 | 
			
		||||
 | 
			
		||||
    /// @dev Recovers the address of a signer given a hash and signature.
 | 
			
		||||
    /// @param hash Any 32 byte hash.
 | 
			
		||||
    /// @param signature Proof that the hash has been signed by signer.
 | 
			
		||||
    function getSignerAddress(bytes32 hash, bytes memory signature)
 | 
			
		||||
        public
 | 
			
		||||
        pure
 | 
			
		||||
        returns (address signerAddress)
 | 
			
		||||
    {
 | 
			
		||||
        require(
 | 
			
		||||
            signature.length > 0,
 | 
			
		||||
            "LENGTH_GREATER_THAN_0_REQUIRED"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Pop last byte off of signature byte array.
 | 
			
		||||
        uint8 signatureTypeRaw = uint8(signature.popLastByte());
 | 
			
		||||
 | 
			
		||||
        // Ensure signature is supported
 | 
			
		||||
        require(
 | 
			
		||||
            signatureTypeRaw < uint8(SignatureType.NSignatureTypes),
 | 
			
		||||
            "SIGNATURE_UNSUPPORTED"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        SignatureType signatureType = SignatureType(signatureTypeRaw);
 | 
			
		||||
 | 
			
		||||
        // Always illegal signature.
 | 
			
		||||
        // This is always an implicit option since a signer can create a
 | 
			
		||||
        // signature array with invalid type or length. We may as well make
 | 
			
		||||
        // it an explicit option. This aids testing and analysis. It is
 | 
			
		||||
        // also the initialization value for the enum type.
 | 
			
		||||
        if (signatureType == SignatureType.Illegal) {
 | 
			
		||||
            revert("SIGNATURE_ILLEGAL");
 | 
			
		||||
 | 
			
		||||
        // Always invalid signature.
 | 
			
		||||
        // Like Illegal, this is always implicitly available and therefore
 | 
			
		||||
        // offered explicitly. It can be implicitly created by providing
 | 
			
		||||
        // a correctly formatted but incorrect signature.
 | 
			
		||||
        } else if (signatureType == SignatureType.Invalid) {
 | 
			
		||||
            require(
 | 
			
		||||
                signature.length == 0,
 | 
			
		||||
                "LENGTH_0_REQUIRED"
 | 
			
		||||
            );
 | 
			
		||||
            revert("SIGNATURE_INVALID");
 | 
			
		||||
 | 
			
		||||
        // Signature using EIP712
 | 
			
		||||
        } else if (signatureType == SignatureType.EIP712) {
 | 
			
		||||
            require(
 | 
			
		||||
                signature.length == 65,
 | 
			
		||||
                "LENGTH_65_REQUIRED"
 | 
			
		||||
            );
 | 
			
		||||
            uint8 v = uint8(signature[0]);
 | 
			
		||||
            bytes32 r = signature.readBytes32(1);
 | 
			
		||||
            bytes32 s = signature.readBytes32(33);
 | 
			
		||||
            signerAddress = ecrecover(
 | 
			
		||||
                hash,
 | 
			
		||||
                v,
 | 
			
		||||
                r,
 | 
			
		||||
                s
 | 
			
		||||
            );
 | 
			
		||||
            return signerAddress;
 | 
			
		||||
 | 
			
		||||
        // Signed using web3.eth_sign
 | 
			
		||||
        } else if (signatureType == SignatureType.EthSign) {
 | 
			
		||||
            require(
 | 
			
		||||
                signature.length == 65,
 | 
			
		||||
                "LENGTH_65_REQUIRED"
 | 
			
		||||
            );
 | 
			
		||||
            uint8 v = uint8(signature[0]);
 | 
			
		||||
            bytes32 r = signature.readBytes32(1);
 | 
			
		||||
            bytes32 s = signature.readBytes32(33);
 | 
			
		||||
            signerAddress = ecrecover(
 | 
			
		||||
                keccak256(abi.encodePacked(
 | 
			
		||||
                    "\x19Ethereum Signed Message:\n32",
 | 
			
		||||
                    hash
 | 
			
		||||
                )),
 | 
			
		||||
                v,
 | 
			
		||||
                r,
 | 
			
		||||
                s
 | 
			
		||||
            );
 | 
			
		||||
            return signerAddress;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Anything else is illegal (We do not return false because
 | 
			
		||||
        // the signature may actually be valid, just not in a format
 | 
			
		||||
        // that we currently support. In this case returning false
 | 
			
		||||
        // may lead the caller to incorrectly believe that the
 | 
			
		||||
        // signature was invalid.)
 | 
			
		||||
        revert("SIGNATURE_UNSUPPORTED");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,52 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
pragma experimental "ABIEncoderV2";
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
 | 
			
		||||
import "../libs/LibZeroExTransaction.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract ICoordinatorApprovalVerifier {
 | 
			
		||||
 | 
			
		||||
    /// @dev Validates that the 0x transaction has been approved by all of the feeRecipients
 | 
			
		||||
    ///      that correspond to each order in the transaction's Exchange calldata.
 | 
			
		||||
    /// @param transaction 0x transaction containing salt, signerAddress, and data.
 | 
			
		||||
    /// @param txOrigin Required signer of Ethereum transaction calling this function.
 | 
			
		||||
    /// @param transactionSignature Proof that the transaction has been signed by the signer.
 | 
			
		||||
    /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.
 | 
			
		||||
    /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.
 | 
			
		||||
    function assertValidCoordinatorApprovals(
 | 
			
		||||
        LibZeroExTransaction.ZeroExTransaction memory transaction,
 | 
			
		||||
        address txOrigin,
 | 
			
		||||
        bytes memory transactionSignature,
 | 
			
		||||
        uint256[] memory approvalExpirationTimeSeconds,
 | 
			
		||||
        bytes[] memory approvalSignatures
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        view;
 | 
			
		||||
 | 
			
		||||
    /// @dev Decodes the orders from Exchange calldata representing any fill method.
 | 
			
		||||
    /// @param data Exchange calldata representing a fill method.
 | 
			
		||||
    /// @return The orders from the Exchange calldata.
 | 
			
		||||
    function decodeOrdersFromFillData(bytes memory data)
 | 
			
		||||
        public
 | 
			
		||||
        pure
 | 
			
		||||
        returns (LibOrder.Order[] memory orders);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,41 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
pragma experimental "ABIEncoderV2";
 | 
			
		||||
 | 
			
		||||
import "../libs/LibZeroExTransaction.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract ICoordinatorCore {
 | 
			
		||||
 | 
			
		||||
    /// @dev Executes a 0x transaction that has been signed by the feeRecipients that correspond to each order in the transaction's Exchange calldata.
 | 
			
		||||
    /// @param transaction 0x transaction containing salt, signerAddress, and data.
 | 
			
		||||
    /// @param txOrigin Required signer of Ethereum transaction calling this function.
 | 
			
		||||
    /// @param transactionSignature Proof that the transaction has been signed by the signer.
 | 
			
		||||
    /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.
 | 
			
		||||
    /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order in the transaction's Exchange calldata.
 | 
			
		||||
    function executeTransaction(
 | 
			
		||||
        LibZeroExTransaction.ZeroExTransaction memory transaction,
 | 
			
		||||
        address txOrigin,
 | 
			
		||||
        bytes memory transactionSignature,
 | 
			
		||||
        uint256[] memory approvalExpirationTimeSeconds,
 | 
			
		||||
        bytes[] memory approvalSignatures
 | 
			
		||||
    )
 | 
			
		||||
        public;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,31 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract ISignatureValidator {
 | 
			
		||||
 | 
			
		||||
    /// @dev Recovers the address of a signer given a hash and signature.
 | 
			
		||||
    /// @param hash Any 32 byte hash.
 | 
			
		||||
    /// @param signature Proof that the hash has been signed by signer.
 | 
			
		||||
    function getSignerAddress(bytes32 hash, bytes memory signature)
 | 
			
		||||
        public
 | 
			
		||||
        pure
 | 
			
		||||
        returns (address signerAddress);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,35 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract ITransactions {
 | 
			
		||||
 | 
			
		||||
    /// @dev Executes an exchange method call in the context of signer.
 | 
			
		||||
    /// @param salt Arbitrary number to ensure uniqueness of transaction hash.
 | 
			
		||||
    /// @param signerAddress Address of transaction signer.
 | 
			
		||||
    /// @param data AbiV2 encoded calldata.
 | 
			
		||||
    /// @param signature Proof of signer transaction by signer.
 | 
			
		||||
    function executeTransaction(
 | 
			
		||||
        uint256 salt,
 | 
			
		||||
        address signerAddress,
 | 
			
		||||
        bytes calldata data,
 | 
			
		||||
        bytes calldata signature
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								contracts/coordinator/contracts/src/libs/LibConstants.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								contracts/coordinator/contracts/src/libs/LibConstants.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
 | 
			
		||||
import "../interfaces/ITransactions.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract LibConstants {
 | 
			
		||||
 | 
			
		||||
     // solhint-disable-next-line var-name-mixedcase
 | 
			
		||||
    ITransactions internal EXCHANGE;
 | 
			
		||||
 | 
			
		||||
    constructor (address _exchange)
 | 
			
		||||
        public
 | 
			
		||||
    {
 | 
			
		||||
        EXCHANGE = ITransactions(_exchange);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,98 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
pragma experimental "ABIEncoderV2";
 | 
			
		||||
 | 
			
		||||
import "./LibEIP712Domain.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract LibCoordinatorApproval is
 | 
			
		||||
    LibEIP712Domain
 | 
			
		||||
{
 | 
			
		||||
    // Hash for the EIP712 Coordinator approval message
 | 
			
		||||
    // keccak256(abi.encodePacked(
 | 
			
		||||
    //     "CoordinatorApproval(",
 | 
			
		||||
    //     "address txOrigin,",
 | 
			
		||||
    //     "bytes32 transactionHash,",
 | 
			
		||||
    //     "bytes transactionSignature,",
 | 
			
		||||
    //     "uint256 approvalExpirationTimeSeconds",
 | 
			
		||||
    //     ")"
 | 
			
		||||
    // ));
 | 
			
		||||
    bytes32 constant internal EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH = 0x2fbcdbaa76bc7589916958ae919dfbef04d23f6bbf26de6ff317b32c6cc01e05;
 | 
			
		||||
 | 
			
		||||
    struct CoordinatorApproval {
 | 
			
		||||
        address txOrigin;                       // Required signer of Ethereum transaction that is submitting approval.
 | 
			
		||||
        bytes32 transactionHash;                // EIP712 hash of the transaction.
 | 
			
		||||
        bytes transactionSignature;             // Signature of the 0x transaction.
 | 
			
		||||
        uint256 approvalExpirationTimeSeconds;  // Timestamp in seconds for which the approval expires.
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calculated the EIP712 hash of the Coordinator approval mesasage using the domain separator of this contract.
 | 
			
		||||
    /// @param approval Coordinator approval message containing the transaction hash, transaction signature, and expiration of the approval.
 | 
			
		||||
    /// @return EIP712 hash of the Coordinator approval message with the domain separator of this contract.
 | 
			
		||||
    function getCoordinatorApprovalHash(CoordinatorApproval memory approval)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes32 approvalHash)
 | 
			
		||||
    {
 | 
			
		||||
        approvalHash = hashEIP712CoordinatorMessage(hashCoordinatorApproval(approval));
 | 
			
		||||
        return approvalHash;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calculated the EIP712 hash of the Coordinator approval mesasage with no domain separator.
 | 
			
		||||
    /// @param approval Coordinator approval message containing the transaction hash, transaction signature, and expiration of the approval.
 | 
			
		||||
    /// @return EIP712 hash of the Coordinator approval message with no domain separator.
 | 
			
		||||
    function hashCoordinatorApproval(CoordinatorApproval memory approval)
 | 
			
		||||
        internal
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes32 result)
 | 
			
		||||
    {
 | 
			
		||||
        bytes32 schemaHash = EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH;
 | 
			
		||||
        bytes memory transactionSignature = approval.transactionSignature;
 | 
			
		||||
        address txOrigin = approval.txOrigin;
 | 
			
		||||
        bytes32 transactionHash = approval.transactionHash;
 | 
			
		||||
        uint256 approvalExpirationTimeSeconds = approval.approvalExpirationTimeSeconds;
 | 
			
		||||
 | 
			
		||||
        // Assembly for more efficiently computing:
 | 
			
		||||
        // keccak256(abi.encodePacked(
 | 
			
		||||
        //     EIP712_COORDINATOR_APPROVAL_SCHEMA_HASH,
 | 
			
		||||
        //     approval.txOrigin,
 | 
			
		||||
        //     approval.transactionHash,
 | 
			
		||||
        //     keccak256(approval.transactionSignature)
 | 
			
		||||
        //     approval.approvalExpirationTimeSeconds,
 | 
			
		||||
        // ));
 | 
			
		||||
 | 
			
		||||
        assembly {
 | 
			
		||||
            // Compute hash of transaction signature
 | 
			
		||||
            let transactionSignatureHash := keccak256(add(transactionSignature, 32), mload(transactionSignature))
 | 
			
		||||
 | 
			
		||||
            // Load free memory pointer
 | 
			
		||||
            let memPtr := mload(64)
 | 
			
		||||
 | 
			
		||||
            mstore(memPtr, schemaHash)                               // hash of schema
 | 
			
		||||
            mstore(add(memPtr, 32), txOrigin)                        // txOrigin
 | 
			
		||||
            mstore(add(memPtr, 64), transactionHash)                 // transactionHash
 | 
			
		||||
            mstore(add(memPtr, 96), transactionSignatureHash)        // transactionSignatureHash
 | 
			
		||||
            mstore(add(memPtr, 128), approvalExpirationTimeSeconds)  // approvalExpirationTimeSeconds
 | 
			
		||||
            // Compute hash
 | 
			
		||||
            result := keccak256(memPtr, 160)
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										131
									
								
								contracts/coordinator/contracts/src/libs/LibEIP712Domain.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								contracts/coordinator/contracts/src/libs/LibEIP712Domain.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,131 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
 | 
			
		||||
import "./LibConstants.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract LibEIP712Domain is
 | 
			
		||||
    LibConstants
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    // EIP191 header for EIP712 prefix
 | 
			
		||||
    string constant internal EIP191_HEADER = "\x19\x01";
 | 
			
		||||
 | 
			
		||||
    // EIP712 Domain Name value for the Coordinator
 | 
			
		||||
    string constant internal EIP712_COORDINATOR_DOMAIN_NAME = "0x Protocol Coordinator";
 | 
			
		||||
 | 
			
		||||
    // EIP712 Domain Version value for the Coordinator
 | 
			
		||||
    string constant internal EIP712_COORDINATOR_DOMAIN_VERSION = "1.0.0";
 | 
			
		||||
 | 
			
		||||
    // EIP712 Domain Name value for the Exchange
 | 
			
		||||
    string constant internal EIP712_EXCHANGE_DOMAIN_NAME = "0x Protocol";
 | 
			
		||||
 | 
			
		||||
    // EIP712 Domain Version value for the Exchange
 | 
			
		||||
    string constant internal EIP712_EXCHANGE_DOMAIN_VERSION = "2";
 | 
			
		||||
 | 
			
		||||
    // Hash of the EIP712 Domain Separator Schema
 | 
			
		||||
    bytes32 constant internal EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH = keccak256(abi.encodePacked(
 | 
			
		||||
        "EIP712Domain(",
 | 
			
		||||
        "string name,",
 | 
			
		||||
        "string version,",
 | 
			
		||||
        "address verifyingContract",
 | 
			
		||||
        ")"
 | 
			
		||||
    ));
 | 
			
		||||
 | 
			
		||||
    // Hash of the EIP712 Domain Separator data for the Coordinator
 | 
			
		||||
    // solhint-disable-next-line var-name-mixedcase
 | 
			
		||||
    bytes32 public EIP712_COORDINATOR_DOMAIN_HASH;
 | 
			
		||||
 | 
			
		||||
    // Hash of the EIP712 Domain Separator data for the Exchange
 | 
			
		||||
    // solhint-disable-next-line var-name-mixedcase
 | 
			
		||||
    bytes32 public EIP712_EXCHANGE_DOMAIN_HASH;
 | 
			
		||||
 | 
			
		||||
    constructor ()
 | 
			
		||||
        public
 | 
			
		||||
    {
 | 
			
		||||
        EIP712_COORDINATOR_DOMAIN_HASH = keccak256(abi.encodePacked(
 | 
			
		||||
            EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,
 | 
			
		||||
            keccak256(bytes(EIP712_COORDINATOR_DOMAIN_NAME)),
 | 
			
		||||
            keccak256(bytes(EIP712_COORDINATOR_DOMAIN_VERSION)),
 | 
			
		||||
            uint256(address(this))
 | 
			
		||||
        ));
 | 
			
		||||
 | 
			
		||||
        EIP712_EXCHANGE_DOMAIN_HASH = keccak256(abi.encodePacked(
 | 
			
		||||
            EIP712_DOMAIN_SEPARATOR_SCHEMA_HASH,
 | 
			
		||||
            keccak256(bytes(EIP712_EXCHANGE_DOMAIN_NAME)),
 | 
			
		||||
            keccak256(bytes(EIP712_EXCHANGE_DOMAIN_VERSION)),
 | 
			
		||||
            uint256(address(EXCHANGE))
 | 
			
		||||
        ));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calculates EIP712 encoding for a hash struct in the EIP712 domain
 | 
			
		||||
    ///      of this contract.
 | 
			
		||||
    /// @param hashStruct The EIP712 hash struct.
 | 
			
		||||
    /// @return EIP712 hash applied to this EIP712 Domain.
 | 
			
		||||
    function hashEIP712CoordinatorMessage(bytes32 hashStruct)
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes32 result)
 | 
			
		||||
    {
 | 
			
		||||
        return hashEIP712Message(EIP712_COORDINATOR_DOMAIN_HASH, hashStruct);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calculates EIP712 encoding for a hash struct in the EIP712 domain
 | 
			
		||||
    ///      of the Exchange contract.
 | 
			
		||||
    /// @param hashStruct The EIP712 hash struct.
 | 
			
		||||
    /// @return EIP712 hash applied to the Exchange EIP712 Domain.
 | 
			
		||||
    function hashEIP712ExchangeMessage(bytes32 hashStruct)
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes32 result)
 | 
			
		||||
    {
 | 
			
		||||
        return hashEIP712Message(EIP712_EXCHANGE_DOMAIN_HASH, hashStruct);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calculates EIP712 encoding for a hash struct with a given domain hash.
 | 
			
		||||
    /// @param eip712DomainHash Hash of the domain domain separator data.
 | 
			
		||||
    /// @param hashStruct The EIP712 hash struct.
 | 
			
		||||
    /// @return EIP712 hash applied to the Exchange EIP712 Domain.
 | 
			
		||||
    function hashEIP712Message(bytes32 eip712DomainHash, bytes32 hashStruct)
 | 
			
		||||
        internal
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes32 result)
 | 
			
		||||
    {
 | 
			
		||||
        // Assembly for more efficient computing:
 | 
			
		||||
        // keccak256(abi.encodePacked(
 | 
			
		||||
        //     EIP191_HEADER,
 | 
			
		||||
        //     EIP712_DOMAIN_HASH,
 | 
			
		||||
        //     hashStruct
 | 
			
		||||
        // ));
 | 
			
		||||
 | 
			
		||||
        assembly {
 | 
			
		||||
            // Load free memory pointer
 | 
			
		||||
            let memPtr := mload(64)
 | 
			
		||||
 | 
			
		||||
            mstore(memPtr, 0x1901000000000000000000000000000000000000000000000000000000000000)  // EIP191 header
 | 
			
		||||
            mstore(add(memPtr, 2), eip712DomainHash)                                            // EIP712 domain hash
 | 
			
		||||
            mstore(add(memPtr, 34), hashStruct)                                                 // Hash of struct
 | 
			
		||||
 | 
			
		||||
            // Compute hash
 | 
			
		||||
            result := keccak256(memPtr, 66)
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,95 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
pragma experimental "ABIEncoderV2";
 | 
			
		||||
 | 
			
		||||
import "./LibEIP712Domain.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract LibZeroExTransaction is
 | 
			
		||||
    LibEIP712Domain
 | 
			
		||||
{
 | 
			
		||||
    // Hash for the EIP712 0x transaction schema
 | 
			
		||||
    // keccak256(abi.encodePacked(
 | 
			
		||||
    //    "ZeroExTransaction(",
 | 
			
		||||
    //    "uint256 salt,",
 | 
			
		||||
    //    "address signerAddress,",
 | 
			
		||||
    //    "bytes data",
 | 
			
		||||
    //    ")"
 | 
			
		||||
    // ));
 | 
			
		||||
    bytes32 constant internal EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH = 0x213c6f636f3ea94e701c0adf9b2624aa45a6c694f9a292c094f9a81c24b5df4c;
 | 
			
		||||
 | 
			
		||||
    struct ZeroExTransaction {
 | 
			
		||||
        uint256 salt;           // Arbitrary number to ensure uniqueness of transaction hash.
 | 
			
		||||
        address signerAddress;  // Address of transaction signer.
 | 
			
		||||
        bytes data;             // AbiV2 encoded calldata.
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calculates the EIP712 hash of a 0x transaction using the domain separator of the Exchange contract.
 | 
			
		||||
    /// @param transaction 0x transaction containing salt, signerAddress, and data.
 | 
			
		||||
    /// @return EIP712 hash of the transaction with the domain separator of this contract.
 | 
			
		||||
    function getTransactionHash(ZeroExTransaction memory transaction)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes32 transactionHash)
 | 
			
		||||
    {
 | 
			
		||||
        // Hash the transaction with the domain separator of the Exchange contract.
 | 
			
		||||
        transactionHash = hashEIP712ExchangeMessage(hashZeroExTransaction(transaction));
 | 
			
		||||
        return transactionHash;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calculates EIP712 hash of the 0x transaction with no domain separator.
 | 
			
		||||
    /// @param transaction 0x transaction containing salt, signerAddress, and data.
 | 
			
		||||
    /// @return EIP712 hash of the transaction with no domain separator.
 | 
			
		||||
    function hashZeroExTransaction(ZeroExTransaction memory transaction)
 | 
			
		||||
        internal
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes32 result)
 | 
			
		||||
    {
 | 
			
		||||
        bytes32 schemaHash = EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH;
 | 
			
		||||
        bytes memory data = transaction.data;
 | 
			
		||||
        uint256 salt = transaction.salt;
 | 
			
		||||
        address signerAddress = transaction.signerAddress;
 | 
			
		||||
 | 
			
		||||
        // Assembly for more efficiently computing:
 | 
			
		||||
        // keccak256(abi.encodePacked(
 | 
			
		||||
        //     EIP712_ZEROEX_TRANSACTION_SCHEMA_HASH,
 | 
			
		||||
        //     transaction.salt,
 | 
			
		||||
        //     uint256(transaction.signerAddress),
 | 
			
		||||
        //     keccak256(transaction.data)
 | 
			
		||||
        // ));
 | 
			
		||||
 | 
			
		||||
        assembly {
 | 
			
		||||
            // Compute hash of data
 | 
			
		||||
            let dataHash := keccak256(add(data, 32), mload(data))
 | 
			
		||||
 | 
			
		||||
            // Load free memory pointer
 | 
			
		||||
            let memPtr := mload(64)
 | 
			
		||||
 | 
			
		||||
            mstore(memPtr, schemaHash)                                                               // hash of schema
 | 
			
		||||
            mstore(add(memPtr, 32), salt)                                                            // salt
 | 
			
		||||
            mstore(add(memPtr, 64), and(signerAddress, 0xffffffffffffffffffffffffffffffffffffffff))  // signerAddress
 | 
			
		||||
            mstore(add(memPtr, 96), dataHash)                                                        // hash of data
 | 
			
		||||
 | 
			
		||||
            // Compute hash
 | 
			
		||||
            result := keccak256(memPtr, 128)
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,46 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
pragma experimental "ABIEncoderV2";
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
 | 
			
		||||
import "../interfaces/ICoordinatorApprovalVerifier.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract MCoordinatorApprovalVerifier is
 | 
			
		||||
    ICoordinatorApprovalVerifier
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Validates that the feeRecipients of a batch of order have approved a 0x transaction.
 | 
			
		||||
    /// @param transaction 0x transaction containing salt, signerAddress, and data.
 | 
			
		||||
    /// @param orders Array of order structs containing order specifications.
 | 
			
		||||
    /// @param txOrigin Required signer of Ethereum transaction calling this function.
 | 
			
		||||
    /// @param transactionSignature Proof that the transaction has been signed by the signer.
 | 
			
		||||
    /// @param approvalExpirationTimeSeconds Array of expiration times in seconds for which each corresponding approval signature expires.
 | 
			
		||||
    /// @param approvalSignatures Array of signatures that correspond to the feeRecipients of each order.
 | 
			
		||||
    function assertValidTransactionOrdersApproval(
 | 
			
		||||
        LibZeroExTransaction.ZeroExTransaction memory transaction,
 | 
			
		||||
        LibOrder.Order[] memory orders,
 | 
			
		||||
        address txOrigin,
 | 
			
		||||
        bytes memory transactionSignature,
 | 
			
		||||
        uint256[] memory approvalExpirationTimeSeconds,
 | 
			
		||||
        bytes[] memory approvalSignatures
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
        view;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,35 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
 | 
			
		||||
import "../interfaces/ISignatureValidator.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract MSignatureValidator is
 | 
			
		||||
    ISignatureValidator
 | 
			
		||||
{
 | 
			
		||||
    // Allowed signature types.
 | 
			
		||||
    enum SignatureType {
 | 
			
		||||
        Illegal,         // 0x00, default value
 | 
			
		||||
        Invalid,         // 0x01
 | 
			
		||||
        EIP712,          // 0x02
 | 
			
		||||
        EthSign,         // 0x03
 | 
			
		||||
        NSignatureTypes  // 0x04, number of signature types. Always leave at end.
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,32 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
 | 
			
		||||
import "./MixinCoordinatorRegistryCore.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable no-empty-blocks
 | 
			
		||||
contract CoordinatorRegistry is
 | 
			
		||||
    MixinCoordinatorRegistryCore
 | 
			
		||||
{
 | 
			
		||||
    constructor ()
 | 
			
		||||
        public
 | 
			
		||||
        MixinCoordinatorRegistryCore()
 | 
			
		||||
    {}
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,48 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
 | 
			
		||||
import "./interfaces/ICoordinatorRegistryCore.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable no-empty-blocks
 | 
			
		||||
contract MixinCoordinatorRegistryCore is
 | 
			
		||||
    ICoordinatorRegistryCore
 | 
			
		||||
{
 | 
			
		||||
    // mapping from `coordinatorOperator` -> `coordinatorEndpoint`
 | 
			
		||||
    mapping (address => string) internal coordinatorEndpoints;
 | 
			
		||||
 | 
			
		||||
    /// @dev Called by a Coordinator operator to set the endpoint of their Coordinator.
 | 
			
		||||
    /// @param coordinatorEndpoint endpoint of the Coordinator.
 | 
			
		||||
    function setCoordinatorEndpoint(string calldata coordinatorEndpoint) external {
 | 
			
		||||
        address coordinatorOperator = msg.sender;
 | 
			
		||||
        coordinatorEndpoints[coordinatorOperator] = coordinatorEndpoint;
 | 
			
		||||
        emit CoordinatorEndpointSet(coordinatorOperator, coordinatorEndpoint);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets the endpoint for a Coordinator.
 | 
			
		||||
    /// @param coordinatorOperator operator of the Coordinator endpoint.
 | 
			
		||||
    function getCoordinatorEndpoint(address coordinatorOperator)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (string memory coordinatorEndpoint)
 | 
			
		||||
    {
 | 
			
		||||
        return coordinatorEndpoints[coordinatorOperator];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,41 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable no-empty-blocks
 | 
			
		||||
contract ICoordinatorRegistryCore
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Emitted when a Coordinator endpoint is set.
 | 
			
		||||
    event CoordinatorEndpointSet(
 | 
			
		||||
        address coordinatorOperator,
 | 
			
		||||
        string coordinatorEndpoint
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    /// @dev Called by a Coordinator operator to set the endpoint of their Coordinator.
 | 
			
		||||
    /// @param coordinatorEndpoint endpoint of the Coordinator.
 | 
			
		||||
    function setCoordinatorEndpoint(string calldata coordinatorEndpoint) external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets the endpoint for a Coordinator.
 | 
			
		||||
    /// @param coordinatorOperator operator of the Coordinator endpoint.
 | 
			
		||||
    function getCoordinatorEndpoint(address coordinatorOperator)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (string memory coordinatorEndpoint);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										90
									
								
								contracts/coordinator/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								contracts/coordinator/package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contracts-coordinator",
 | 
			
		||||
    "version": "2.0.11",
 | 
			
		||||
    "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",
 | 
			
		||||
        "fix": "tslint --fix --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",
 | 
			
		||||
        "contracts:gen": "contracts-gen",
 | 
			
		||||
        "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol"
 | 
			
		||||
    },
 | 
			
		||||
    "config": {
 | 
			
		||||
        "abis": "./generated-artifacts/@(Coordinator|CoordinatorRegistry).json",
 | 
			
		||||
        "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
 | 
			
		||||
    },
 | 
			
		||||
    "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": "^4.1.1",
 | 
			
		||||
        "@0x/contracts-gen": "^1.0.13",
 | 
			
		||||
        "@0x/contracts-test-utils": "^3.1.14",
 | 
			
		||||
        "@0x/dev-utils": "^2.3.1",
 | 
			
		||||
        "@0x/sol-compiler": "^3.1.13",
 | 
			
		||||
        "@0x/tslint-config": "^3.0.1",
 | 
			
		||||
        "@types/lodash": "4.14.104",
 | 
			
		||||
        "@types/mocha": "^5.2.7",
 | 
			
		||||
        "@types/node": "*",
 | 
			
		||||
        "chai": "^4.0.1",
 | 
			
		||||
        "chai-as-promised": "^7.1.0",
 | 
			
		||||
        "chai-bignumber": "^3.0.0",
 | 
			
		||||
        "dirty-chai": "^2.0.1",
 | 
			
		||||
        "make-promises-safe": "^1.1.0",
 | 
			
		||||
        "mocha": "^6.2.0",
 | 
			
		||||
        "npm-run-all": "^4.1.2",
 | 
			
		||||
        "shx": "^0.2.2",
 | 
			
		||||
        "solhint": "^1.4.1",
 | 
			
		||||
        "tslint": "5.11.0",
 | 
			
		||||
        "typescript": "3.0.1"
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@0x/base-contract": "^5.3.2",
 | 
			
		||||
        "@0x/contracts-asset-proxy": "^2.2.6",
 | 
			
		||||
        "@0x/contracts-erc20": "^2.2.12",
 | 
			
		||||
        "@0x/contracts-exchange": "^2.1.12",
 | 
			
		||||
        "@0x/contracts-exchange-libs": "^3.0.6",
 | 
			
		||||
        "@0x/contracts-utils": "^3.2.2",
 | 
			
		||||
        "@0x/order-utils": "^8.3.0",
 | 
			
		||||
        "@0x/types": "^2.4.1",
 | 
			
		||||
        "@0x/typescript-typings": "^4.2.4",
 | 
			
		||||
        "@0x/utils": "^4.5.0",
 | 
			
		||||
        "@0x/web3-wrapper": "^6.0.11",
 | 
			
		||||
        "ethereum-types": "^2.1.4",
 | 
			
		||||
        "ethereumjs-util": "^5.1.1",
 | 
			
		||||
        "lodash": "^4.17.11"
 | 
			
		||||
    },
 | 
			
		||||
    "publishConfig": {
 | 
			
		||||
        "access": "public"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								contracts/coordinator/src/artifacts.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								contracts/coordinator/src/artifacts.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
/*
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 * Warning: This file is auto-generated by contracts-gen. Don't edit manually.
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
import { ContractArtifact } from 'ethereum-types';
 | 
			
		||||
 | 
			
		||||
import * as Coordinator from '../generated-artifacts/Coordinator.json';
 | 
			
		||||
import * as CoordinatorRegistry from '../generated-artifacts/CoordinatorRegistry.json';
 | 
			
		||||
export const artifacts = {
 | 
			
		||||
    Coordinator: Coordinator as ContractArtifact,
 | 
			
		||||
    CoordinatorRegistry: CoordinatorRegistry as ContractArtifact,
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										3
									
								
								contracts/coordinator/src/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								contracts/coordinator/src/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
export * from './artifacts';
 | 
			
		||||
export * from './wrappers';
 | 
			
		||||
export * from '../test/utils';
 | 
			
		||||
							
								
								
									
										7
									
								
								contracts/coordinator/src/wrappers.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								contracts/coordinator/src/wrappers.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
/*
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 * Warning: This file is auto-generated by contracts-gen. Don't edit manually.
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
export * from '../generated-wrappers/coordinator';
 | 
			
		||||
export * from '../generated-wrappers/coordinator_registry';
 | 
			
		||||
							
								
								
									
										523
									
								
								contracts/coordinator/test/coordinator.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										523
									
								
								contracts/coordinator/test/coordinator.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,523 @@
 | 
			
		||||
import { ERC20ProxyContract, ERC20Wrapper } from '@0x/contracts-asset-proxy';
 | 
			
		||||
import { DummyERC20TokenContract } from '@0x/contracts-erc20';
 | 
			
		||||
import {
 | 
			
		||||
    artifacts as exchangeArtifacts,
 | 
			
		||||
    ExchangeCancelEventArgs,
 | 
			
		||||
    ExchangeCancelUpToEventArgs,
 | 
			
		||||
    ExchangeContract,
 | 
			
		||||
    ExchangeFillEventArgs,
 | 
			
		||||
} from '@0x/contracts-exchange';
 | 
			
		||||
import {
 | 
			
		||||
    chaiSetup,
 | 
			
		||||
    constants as devConstants,
 | 
			
		||||
    expectTransactionFailedAsync,
 | 
			
		||||
    getLatestBlockTimestampAsync,
 | 
			
		||||
    OrderFactory,
 | 
			
		||||
    provider,
 | 
			
		||||
    TransactionFactory,
 | 
			
		||||
    txDefaults,
 | 
			
		||||
    web3Wrapper,
 | 
			
		||||
} from '@0x/contracts-test-utils';
 | 
			
		||||
import { BlockchainLifecycle } from '@0x/dev-utils';
 | 
			
		||||
import { assetDataUtils, orderHashUtils } from '@0x/order-utils';
 | 
			
		||||
import { RevertReason, SignedOrder } from '@0x/types';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
import * as chai from 'chai';
 | 
			
		||||
import { LogWithDecodedArgs } from 'ethereum-types';
 | 
			
		||||
 | 
			
		||||
import { ApprovalFactory, artifacts, constants, CoordinatorContract, exchangeDataEncoder } from '../src';
 | 
			
		||||
 | 
			
		||||
chaiSetup.configure();
 | 
			
		||||
const expect = chai.expect;
 | 
			
		||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
 | 
			
		||||
web3Wrapper.abiDecoder.addABI(exchangeArtifacts.Exchange.compilerOutput.abi);
 | 
			
		||||
// tslint:disable:no-unnecessary-type-assertion
 | 
			
		||||
describe('Coordinator tests', () => {
 | 
			
		||||
    let makerAddress: string;
 | 
			
		||||
    let owner: string;
 | 
			
		||||
    let takerAddress: string;
 | 
			
		||||
    let feeRecipientAddress: string;
 | 
			
		||||
 | 
			
		||||
    let erc20Proxy: ERC20ProxyContract;
 | 
			
		||||
    let erc20TokenA: DummyERC20TokenContract;
 | 
			
		||||
    let erc20TokenB: DummyERC20TokenContract;
 | 
			
		||||
    let zrxToken: DummyERC20TokenContract;
 | 
			
		||||
    let coordinatorContract: CoordinatorContract;
 | 
			
		||||
    let exchange: ExchangeContract;
 | 
			
		||||
 | 
			
		||||
    let erc20Wrapper: ERC20Wrapper;
 | 
			
		||||
    let orderFactory: OrderFactory;
 | 
			
		||||
    let takerTransactionFactory: TransactionFactory;
 | 
			
		||||
    let makerTransactionFactory: TransactionFactory;
 | 
			
		||||
    let approvalFactory: ApprovalFactory;
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        await blockchainLifecycle.startAsync();
 | 
			
		||||
    });
 | 
			
		||||
    after(async () => {
 | 
			
		||||
        await blockchainLifecycle.revertAsync();
 | 
			
		||||
    });
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        const accounts = await web3Wrapper.getAvailableAddressesAsync();
 | 
			
		||||
        const usedAddresses = ([owner, makerAddress, takerAddress, feeRecipientAddress] = accounts.slice(0, 4));
 | 
			
		||||
 | 
			
		||||
        erc20Wrapper = new ERC20Wrapper(provider, usedAddresses, owner);
 | 
			
		||||
        erc20Proxy = await erc20Wrapper.deployProxyAsync();
 | 
			
		||||
        const numDummyErc20ToDeploy = 3;
 | 
			
		||||
        [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(
 | 
			
		||||
            numDummyErc20ToDeploy,
 | 
			
		||||
            devConstants.DUMMY_TOKEN_DECIMALS,
 | 
			
		||||
        );
 | 
			
		||||
        await erc20Wrapper.setBalancesAndAllowancesAsync();
 | 
			
		||||
 | 
			
		||||
        exchange = await ExchangeContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            exchangeArtifacts.Exchange,
 | 
			
		||||
            provider,
 | 
			
		||||
            txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
            assetDataUtils.encodeERC20AssetData(zrxToken.address),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
            await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: owner }),
 | 
			
		||||
            devConstants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
            await exchange.registerAssetProxy.sendTransactionAsync(erc20Proxy.address, { from: owner }),
 | 
			
		||||
            devConstants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        coordinatorContract = await CoordinatorContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.Coordinator,
 | 
			
		||||
            provider,
 | 
			
		||||
            txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
            exchange.address,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Configure order defaults
 | 
			
		||||
        const defaultOrderParams = {
 | 
			
		||||
            ...devConstants.STATIC_ORDER_PARAMS,
 | 
			
		||||
            exchangeAddress: exchange.address,
 | 
			
		||||
            senderAddress: coordinatorContract.address,
 | 
			
		||||
            makerAddress,
 | 
			
		||||
            feeRecipientAddress,
 | 
			
		||||
            makerAssetData: assetDataUtils.encodeERC20AssetData(erc20TokenA.address),
 | 
			
		||||
            takerAssetData: assetDataUtils.encodeERC20AssetData(erc20TokenB.address),
 | 
			
		||||
        };
 | 
			
		||||
        const makerPrivateKey = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)];
 | 
			
		||||
        const takerPrivateKey = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)];
 | 
			
		||||
        const feeRecipientPrivateKey = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(feeRecipientAddress)];
 | 
			
		||||
        orderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams);
 | 
			
		||||
        makerTransactionFactory = new TransactionFactory(makerPrivateKey, exchange.address);
 | 
			
		||||
        takerTransactionFactory = new TransactionFactory(takerPrivateKey, exchange.address);
 | 
			
		||||
        approvalFactory = new ApprovalFactory(feeRecipientPrivateKey, coordinatorContract.address);
 | 
			
		||||
    });
 | 
			
		||||
    beforeEach(async () => {
 | 
			
		||||
        await blockchainLifecycle.startAsync();
 | 
			
		||||
    });
 | 
			
		||||
    afterEach(async () => {
 | 
			
		||||
        await blockchainLifecycle.revertAsync();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('single order fills', () => {
 | 
			
		||||
        for (const fnName of constants.SINGLE_FILL_FN_NAMES) {
 | 
			
		||||
            it(`${fnName} should fill the order with a signed approval`, async () => {
 | 
			
		||||
                const orders = [await orderFactory.newSignedOrderAsync()];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = takerTransactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval = approvalFactory.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    takerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                    await coordinatorContract.executeTransaction.sendTransactionAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        takerAddress,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [approvalExpirationTimeSeconds],
 | 
			
		||||
                        [approval.signature],
 | 
			
		||||
                        { from: takerAddress },
 | 
			
		||||
                    ),
 | 
			
		||||
                    devConstants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
                );
 | 
			
		||||
                const fillLogs = transactionReceipt.logs.filter(
 | 
			
		||||
                    log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
 | 
			
		||||
                );
 | 
			
		||||
                expect(fillLogs.length).to.eq(1);
 | 
			
		||||
                const fillLogArgs = (fillLogs[0] as LogWithDecodedArgs<ExchangeFillEventArgs>).args;
 | 
			
		||||
                expect(fillLogArgs.makerAddress).to.eq(makerAddress);
 | 
			
		||||
                expect(fillLogArgs.takerAddress).to.eq(takerAddress);
 | 
			
		||||
                expect(fillLogArgs.senderAddress).to.eq(coordinatorContract.address);
 | 
			
		||||
                expect(fillLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
 | 
			
		||||
                expect(fillLogArgs.makerAssetData).to.eq(orders[0].makerAssetData);
 | 
			
		||||
                expect(fillLogArgs.takerAssetData).to.eq(orders[0].takerAssetData);
 | 
			
		||||
                expect(fillLogArgs.makerAssetFilledAmount).to.bignumber.eq(orders[0].makerAssetAmount);
 | 
			
		||||
                expect(fillLogArgs.takerAssetFilledAmount).to.bignumber.eq(orders[0].takerAssetAmount);
 | 
			
		||||
                expect(fillLogArgs.makerFeePaid).to.bignumber.eq(orders[0].makerFee);
 | 
			
		||||
                expect(fillLogArgs.takerFeePaid).to.bignumber.eq(orders[0].takerFee);
 | 
			
		||||
                expect(fillLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(orders[0]));
 | 
			
		||||
            });
 | 
			
		||||
            it(`${fnName} should fill the order if called by approver`, async () => {
 | 
			
		||||
                const orders = [await orderFactory.newSignedOrderAsync()];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = takerTransactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                    await coordinatorContract.executeTransaction.sendTransactionAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        feeRecipientAddress,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [],
 | 
			
		||||
                        [],
 | 
			
		||||
                        { from: feeRecipientAddress },
 | 
			
		||||
                    ),
 | 
			
		||||
                    devConstants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
                );
 | 
			
		||||
                const fillLogs = transactionReceipt.logs.filter(
 | 
			
		||||
                    log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
 | 
			
		||||
                );
 | 
			
		||||
                expect(fillLogs.length).to.eq(1);
 | 
			
		||||
                const fillLogArgs = (fillLogs[0] as LogWithDecodedArgs<ExchangeFillEventArgs>).args;
 | 
			
		||||
                expect(fillLogArgs.makerAddress).to.eq(makerAddress);
 | 
			
		||||
                expect(fillLogArgs.takerAddress).to.eq(takerAddress);
 | 
			
		||||
                expect(fillLogArgs.senderAddress).to.eq(coordinatorContract.address);
 | 
			
		||||
                expect(fillLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
 | 
			
		||||
                expect(fillLogArgs.makerAssetData).to.eq(orders[0].makerAssetData);
 | 
			
		||||
                expect(fillLogArgs.takerAssetData).to.eq(orders[0].takerAssetData);
 | 
			
		||||
                expect(fillLogArgs.makerAssetFilledAmount).to.bignumber.eq(orders[0].makerAssetAmount);
 | 
			
		||||
                expect(fillLogArgs.takerAssetFilledAmount).to.bignumber.eq(orders[0].takerAssetAmount);
 | 
			
		||||
                expect(fillLogArgs.makerFeePaid).to.bignumber.eq(orders[0].makerFee);
 | 
			
		||||
                expect(fillLogArgs.takerFeePaid).to.bignumber.eq(orders[0].takerFee);
 | 
			
		||||
                expect(fillLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(orders[0]));
 | 
			
		||||
            });
 | 
			
		||||
            it(`${fnName} should revert with no approval signature`, async () => {
 | 
			
		||||
                const orders = [await orderFactory.newSignedOrderAsync()];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = takerTransactionFactory.newSignedTransaction(data);
 | 
			
		||||
                await expectTransactionFailedAsync(
 | 
			
		||||
                    coordinatorContract.executeTransaction.sendTransactionAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        takerAddress,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [],
 | 
			
		||||
                        [],
 | 
			
		||||
                        {
 | 
			
		||||
                            from: takerAddress,
 | 
			
		||||
                            gas: devConstants.MAX_EXECUTE_TRANSACTION_GAS,
 | 
			
		||||
                        },
 | 
			
		||||
                    ),
 | 
			
		||||
                    RevertReason.InvalidApprovalSignature,
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`${fnName} should revert with an invalid approval signature`, async () => {
 | 
			
		||||
                const orders = [await orderFactory.newSignedOrderAsync()];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = takerTransactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval = approvalFactory.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    takerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`;
 | 
			
		||||
                await expectTransactionFailedAsync(
 | 
			
		||||
                    coordinatorContract.executeTransaction.sendTransactionAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        takerAddress,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [approvalExpirationTimeSeconds],
 | 
			
		||||
                        [signature],
 | 
			
		||||
                        { from: takerAddress },
 | 
			
		||||
                    ),
 | 
			
		||||
                    RevertReason.InvalidApprovalSignature,
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`${fnName} should revert with an expired approval`, async () => {
 | 
			
		||||
                const orders = [await orderFactory.newSignedOrderAsync()];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = takerTransactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval = approvalFactory.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    takerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                await expectTransactionFailedAsync(
 | 
			
		||||
                    coordinatorContract.executeTransaction.sendTransactionAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        takerAddress,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [approvalExpirationTimeSeconds],
 | 
			
		||||
                        [approval.signature],
 | 
			
		||||
                        { from: takerAddress },
 | 
			
		||||
                    ),
 | 
			
		||||
                    RevertReason.ApprovalExpired,
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`${fnName} should revert if not called by tx signer or approver`, async () => {
 | 
			
		||||
                const orders = [await orderFactory.newSignedOrderAsync()];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = takerTransactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval = approvalFactory.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    takerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                await expectTransactionFailedAsync(
 | 
			
		||||
                    coordinatorContract.executeTransaction.sendTransactionAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        takerAddress,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [approvalExpirationTimeSeconds],
 | 
			
		||||
                        [approval.signature],
 | 
			
		||||
                        { from: owner },
 | 
			
		||||
                    ),
 | 
			
		||||
                    RevertReason.InvalidOrigin,
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    describe('batch order fills', () => {
 | 
			
		||||
        for (const fnName of [...constants.MARKET_FILL_FN_NAMES, ...constants.BATCH_FILL_FN_NAMES]) {
 | 
			
		||||
            it(`${fnName} should fill the orders with a signed approval`, async () => {
 | 
			
		||||
                const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = takerTransactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval = approvalFactory.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    takerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                    await coordinatorContract.executeTransaction.sendTransactionAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        takerAddress,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [approvalExpirationTimeSeconds],
 | 
			
		||||
                        [approval.signature],
 | 
			
		||||
                        { from: takerAddress, gas: devConstants.MAX_EXECUTE_TRANSACTION_GAS },
 | 
			
		||||
                    ),
 | 
			
		||||
                    devConstants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
                );
 | 
			
		||||
                const fillLogs = transactionReceipt.logs.filter(
 | 
			
		||||
                    log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
 | 
			
		||||
                );
 | 
			
		||||
                expect(fillLogs.length).to.eq(orders.length);
 | 
			
		||||
                orders.forEach((order, index) => {
 | 
			
		||||
                    const fillLogArgs = (fillLogs[index] as LogWithDecodedArgs<ExchangeFillEventArgs>).args;
 | 
			
		||||
                    expect(fillLogArgs.makerAddress).to.eq(makerAddress);
 | 
			
		||||
                    expect(fillLogArgs.takerAddress).to.eq(takerAddress);
 | 
			
		||||
                    expect(fillLogArgs.senderAddress).to.eq(coordinatorContract.address);
 | 
			
		||||
                    expect(fillLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
 | 
			
		||||
                    expect(fillLogArgs.makerAssetData).to.eq(order.makerAssetData);
 | 
			
		||||
                    expect(fillLogArgs.takerAssetData).to.eq(order.takerAssetData);
 | 
			
		||||
                    expect(fillLogArgs.makerAssetFilledAmount).to.bignumber.eq(order.makerAssetAmount);
 | 
			
		||||
                    expect(fillLogArgs.takerAssetFilledAmount).to.bignumber.eq(order.takerAssetAmount);
 | 
			
		||||
                    expect(fillLogArgs.makerFeePaid).to.bignumber.eq(order.makerFee);
 | 
			
		||||
                    expect(fillLogArgs.takerFeePaid).to.bignumber.eq(order.takerFee);
 | 
			
		||||
                    expect(fillLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order));
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
            it(`${fnName} should fill the orders if called by approver`, async () => {
 | 
			
		||||
                const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = takerTransactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                    await coordinatorContract.executeTransaction.sendTransactionAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        feeRecipientAddress,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [],
 | 
			
		||||
                        [],
 | 
			
		||||
                        { from: feeRecipientAddress, gas: devConstants.MAX_EXECUTE_TRANSACTION_GAS },
 | 
			
		||||
                    ),
 | 
			
		||||
                    devConstants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
                );
 | 
			
		||||
                const fillLogs = transactionReceipt.logs.filter(
 | 
			
		||||
                    log => (log as LogWithDecodedArgs<ExchangeFillEventArgs>).event === 'Fill',
 | 
			
		||||
                );
 | 
			
		||||
                expect(fillLogs.length).to.eq(orders.length);
 | 
			
		||||
                orders.forEach((order, index) => {
 | 
			
		||||
                    const fillLogArgs = (fillLogs[index] as LogWithDecodedArgs<ExchangeFillEventArgs>).args;
 | 
			
		||||
                    expect(fillLogArgs.makerAddress).to.eq(makerAddress);
 | 
			
		||||
                    expect(fillLogArgs.takerAddress).to.eq(takerAddress);
 | 
			
		||||
                    expect(fillLogArgs.senderAddress).to.eq(coordinatorContract.address);
 | 
			
		||||
                    expect(fillLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
 | 
			
		||||
                    expect(fillLogArgs.makerAssetData).to.eq(order.makerAssetData);
 | 
			
		||||
                    expect(fillLogArgs.takerAssetData).to.eq(order.takerAssetData);
 | 
			
		||||
                    expect(fillLogArgs.makerAssetFilledAmount).to.bignumber.eq(order.makerAssetAmount);
 | 
			
		||||
                    expect(fillLogArgs.takerAssetFilledAmount).to.bignumber.eq(order.takerAssetAmount);
 | 
			
		||||
                    expect(fillLogArgs.makerFeePaid).to.bignumber.eq(order.makerFee);
 | 
			
		||||
                    expect(fillLogArgs.takerFeePaid).to.bignumber.eq(order.takerFee);
 | 
			
		||||
                    expect(fillLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order));
 | 
			
		||||
                });
 | 
			
		||||
            });
 | 
			
		||||
            it(`${fnName} should revert with an invalid approval signature`, async () => {
 | 
			
		||||
                const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = takerTransactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval = approvalFactory.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    takerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`;
 | 
			
		||||
                await expectTransactionFailedAsync(
 | 
			
		||||
                    coordinatorContract.executeTransaction.sendTransactionAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        takerAddress,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [approvalExpirationTimeSeconds],
 | 
			
		||||
                        [signature],
 | 
			
		||||
                        { from: takerAddress },
 | 
			
		||||
                    ),
 | 
			
		||||
                    RevertReason.InvalidApprovalSignature,
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`${fnName} should revert with an expired approval`, async () => {
 | 
			
		||||
                const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = takerTransactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval = approvalFactory.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    takerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                await expectTransactionFailedAsync(
 | 
			
		||||
                    coordinatorContract.executeTransaction.sendTransactionAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        takerAddress,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [approvalExpirationTimeSeconds],
 | 
			
		||||
                        [approval.signature],
 | 
			
		||||
                        { from: takerAddress },
 | 
			
		||||
                    ),
 | 
			
		||||
                    RevertReason.ApprovalExpired,
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`${fnName} should revert if not called by tx signer or approver`, async () => {
 | 
			
		||||
                const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = takerTransactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval = approvalFactory.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    takerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                await expectTransactionFailedAsync(
 | 
			
		||||
                    coordinatorContract.executeTransaction.sendTransactionAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        takerAddress,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [approvalExpirationTimeSeconds],
 | 
			
		||||
                        [approval.signature],
 | 
			
		||||
                        { from: owner },
 | 
			
		||||
                    ),
 | 
			
		||||
                    RevertReason.InvalidOrigin,
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    describe('cancels', () => {
 | 
			
		||||
        it('cancelOrder call should be successful without an approval', async () => {
 | 
			
		||||
            const orders = [await orderFactory.newSignedOrderAsync()];
 | 
			
		||||
            const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDER, orders);
 | 
			
		||||
            const transaction = makerTransactionFactory.newSignedTransaction(data);
 | 
			
		||||
            const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                await coordinatorContract.executeTransaction.sendTransactionAsync(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    makerAddress,
 | 
			
		||||
                    transaction.signature,
 | 
			
		||||
                    [],
 | 
			
		||||
                    [],
 | 
			
		||||
                    {
 | 
			
		||||
                        from: makerAddress,
 | 
			
		||||
                    },
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
            const cancelLogs = transactionReceipt.logs.filter(
 | 
			
		||||
                log => (log as LogWithDecodedArgs<ExchangeCancelEventArgs>).event === 'Cancel',
 | 
			
		||||
            );
 | 
			
		||||
            expect(cancelLogs.length).to.eq(1);
 | 
			
		||||
            const cancelLogArgs = (cancelLogs[0] as LogWithDecodedArgs<ExchangeCancelEventArgs>).args;
 | 
			
		||||
            expect(cancelLogArgs.makerAddress).to.eq(makerAddress);
 | 
			
		||||
            expect(cancelLogArgs.senderAddress).to.eq(coordinatorContract.address);
 | 
			
		||||
            expect(cancelLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
 | 
			
		||||
            expect(cancelLogArgs.makerAssetData).to.eq(orders[0].makerAssetData);
 | 
			
		||||
            expect(cancelLogArgs.takerAssetData).to.eq(orders[0].takerAssetData);
 | 
			
		||||
            expect(cancelLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(orders[0]));
 | 
			
		||||
        });
 | 
			
		||||
        it('batchCancelOrders call should be successful without an approval', async () => {
 | 
			
		||||
            const orders = [await orderFactory.newSignedOrderAsync(), await orderFactory.newSignedOrderAsync()];
 | 
			
		||||
            const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.BATCH_CANCEL_ORDERS, orders);
 | 
			
		||||
            const transaction = makerTransactionFactory.newSignedTransaction(data);
 | 
			
		||||
            const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                await coordinatorContract.executeTransaction.sendTransactionAsync(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    makerAddress,
 | 
			
		||||
                    transaction.signature,
 | 
			
		||||
                    [],
 | 
			
		||||
                    [],
 | 
			
		||||
                    {
 | 
			
		||||
                        from: makerAddress,
 | 
			
		||||
                    },
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
            const cancelLogs = transactionReceipt.logs.filter(
 | 
			
		||||
                log => (log as LogWithDecodedArgs<ExchangeCancelEventArgs>).event === 'Cancel',
 | 
			
		||||
            );
 | 
			
		||||
            expect(cancelLogs.length).to.eq(orders.length);
 | 
			
		||||
            orders.forEach((order, index) => {
 | 
			
		||||
                const cancelLogArgs = (cancelLogs[index] as LogWithDecodedArgs<ExchangeCancelEventArgs>).args;
 | 
			
		||||
                expect(cancelLogArgs.makerAddress).to.eq(makerAddress);
 | 
			
		||||
                expect(cancelLogArgs.senderAddress).to.eq(coordinatorContract.address);
 | 
			
		||||
                expect(cancelLogArgs.feeRecipientAddress).to.eq(feeRecipientAddress);
 | 
			
		||||
                expect(cancelLogArgs.makerAssetData).to.eq(order.makerAssetData);
 | 
			
		||||
                expect(cancelLogArgs.takerAssetData).to.eq(order.takerAssetData);
 | 
			
		||||
                expect(cancelLogArgs.orderHash).to.eq(orderHashUtils.getOrderHashHex(order));
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
        it('cancelOrdersUpTo call should be successful without an approval', async () => {
 | 
			
		||||
            const orders: SignedOrder[] = [];
 | 
			
		||||
            const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDERS_UP_TO, orders);
 | 
			
		||||
            const transaction = makerTransactionFactory.newSignedTransaction(data);
 | 
			
		||||
            const transactionReceipt = await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                await coordinatorContract.executeTransaction.sendTransactionAsync(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    makerAddress,
 | 
			
		||||
                    transaction.signature,
 | 
			
		||||
                    [],
 | 
			
		||||
                    [],
 | 
			
		||||
                    {
 | 
			
		||||
                        from: makerAddress,
 | 
			
		||||
                    },
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
            const cancelLogs = transactionReceipt.logs.filter(
 | 
			
		||||
                log => (log as LogWithDecodedArgs<ExchangeCancelUpToEventArgs>).event === 'CancelUpTo',
 | 
			
		||||
            );
 | 
			
		||||
            expect(cancelLogs.length).to.eq(1);
 | 
			
		||||
            const cancelLogArgs = (cancelLogs[0] as LogWithDecodedArgs<ExchangeCancelUpToEventArgs>).args;
 | 
			
		||||
            expect(cancelLogArgs.makerAddress).to.eq(makerAddress);
 | 
			
		||||
            expect(cancelLogArgs.senderAddress).to.eq(coordinatorContract.address);
 | 
			
		||||
            expect(cancelLogArgs.orderEpoch).to.bignumber.eq(new BigNumber(1));
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
// tslint:disable:max-file-line-count
 | 
			
		||||
							
								
								
									
										81
									
								
								contracts/coordinator/test/coordinator_registry.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								contracts/coordinator/test/coordinator_registry.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
			
		||||
import { artifacts as exchangeArtifacts } from '@0x/contracts-exchange';
 | 
			
		||||
import { chaiSetup, provider, web3Wrapper } from '@0x/contracts-test-utils';
 | 
			
		||||
import { BlockchainLifecycle } from '@0x/dev-utils';
 | 
			
		||||
import * as chai from 'chai';
 | 
			
		||||
import { LogWithDecodedArgs } from 'ethereum-types';
 | 
			
		||||
 | 
			
		||||
import { CoordinatorRegistryCoordinatorEndpointSetEventArgs } from '../src';
 | 
			
		||||
 | 
			
		||||
import { CoordinatorRegistryWrapper } from './utils/coordinator_registry_wrapper';
 | 
			
		||||
 | 
			
		||||
chaiSetup.configure();
 | 
			
		||||
const expect = chai.expect;
 | 
			
		||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
 | 
			
		||||
web3Wrapper.abiDecoder.addABI(exchangeArtifacts.Exchange.compilerOutput.abi);
 | 
			
		||||
// tslint:disable:no-unnecessary-type-assertion
 | 
			
		||||
describe('Coordinator Registry tests', () => {
 | 
			
		||||
    let coordinatorOperator: string;
 | 
			
		||||
    const coordinatorEndpoint = 'http://sometec.0x.org';
 | 
			
		||||
    const nilCoordinatorEndpoint = '';
 | 
			
		||||
    let coordinatorRegistryWrapper: CoordinatorRegistryWrapper;
 | 
			
		||||
    // tests
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        await blockchainLifecycle.startAsync();
 | 
			
		||||
    });
 | 
			
		||||
    after(async () => {
 | 
			
		||||
        await blockchainLifecycle.revertAsync();
 | 
			
		||||
    });
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        // setup accounts (skip owner)
 | 
			
		||||
        const accounts = await web3Wrapper.getAvailableAddressesAsync();
 | 
			
		||||
        [, coordinatorOperator] = accounts;
 | 
			
		||||
        // deploy coordinator registry
 | 
			
		||||
        coordinatorRegistryWrapper = new CoordinatorRegistryWrapper(provider);
 | 
			
		||||
        await coordinatorRegistryWrapper.deployCoordinatorRegistryAsync();
 | 
			
		||||
    });
 | 
			
		||||
    beforeEach(async () => {
 | 
			
		||||
        await blockchainLifecycle.startAsync();
 | 
			
		||||
    });
 | 
			
		||||
    afterEach(async () => {
 | 
			
		||||
        await blockchainLifecycle.revertAsync();
 | 
			
		||||
    });
 | 
			
		||||
    describe('core', () => {
 | 
			
		||||
        it('Should successfully set a Coordinator endpoint', async () => {
 | 
			
		||||
            await coordinatorRegistryWrapper.setCoordinatorEndpointAsync(coordinatorOperator, coordinatorEndpoint);
 | 
			
		||||
            const recordedCoordinatorEndpoint = await coordinatorRegistryWrapper.getCoordinatorEndpointAsync(
 | 
			
		||||
                coordinatorOperator,
 | 
			
		||||
            );
 | 
			
		||||
            expect(recordedCoordinatorEndpoint).to.be.equal(coordinatorEndpoint);
 | 
			
		||||
        });
 | 
			
		||||
        it('Should successfully unset a Coordinator endpoint', async () => {
 | 
			
		||||
            // set Coordinator endpoint
 | 
			
		||||
            await coordinatorRegistryWrapper.setCoordinatorEndpointAsync(coordinatorOperator, coordinatorEndpoint);
 | 
			
		||||
            let recordedCoordinatorEndpoint = await coordinatorRegistryWrapper.getCoordinatorEndpointAsync(
 | 
			
		||||
                coordinatorOperator,
 | 
			
		||||
            );
 | 
			
		||||
            expect(recordedCoordinatorEndpoint).to.be.equal(coordinatorEndpoint);
 | 
			
		||||
            // unset Coordinator endpoint
 | 
			
		||||
            await coordinatorRegistryWrapper.setCoordinatorEndpointAsync(coordinatorOperator, nilCoordinatorEndpoint);
 | 
			
		||||
            recordedCoordinatorEndpoint = await coordinatorRegistryWrapper.getCoordinatorEndpointAsync(
 | 
			
		||||
                coordinatorOperator,
 | 
			
		||||
            );
 | 
			
		||||
            expect(recordedCoordinatorEndpoint).to.be.equal(nilCoordinatorEndpoint);
 | 
			
		||||
        });
 | 
			
		||||
        it('Should emit an event when setting Coordinator endpoint', async () => {
 | 
			
		||||
            // set Coordinator endpoint
 | 
			
		||||
            const txReceipt = await coordinatorRegistryWrapper.setCoordinatorEndpointAsync(
 | 
			
		||||
                coordinatorOperator,
 | 
			
		||||
                coordinatorEndpoint,
 | 
			
		||||
            );
 | 
			
		||||
            const recordedCoordinatorEndpoint = await coordinatorRegistryWrapper.getCoordinatorEndpointAsync(
 | 
			
		||||
                coordinatorOperator,
 | 
			
		||||
            );
 | 
			
		||||
            expect(recordedCoordinatorEndpoint).to.be.equal(coordinatorEndpoint);
 | 
			
		||||
            // validate event
 | 
			
		||||
            expect(txReceipt.logs.length).to.be.equal(1);
 | 
			
		||||
            const log = txReceipt.logs[0] as LogWithDecodedArgs<CoordinatorRegistryCoordinatorEndpointSetEventArgs>;
 | 
			
		||||
            expect(log.args.coordinatorOperator).to.be.equal(coordinatorOperator);
 | 
			
		||||
            expect(log.args.coordinatorEndpoint).to.be.equal(coordinatorEndpoint);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										19
									
								
								contracts/coordinator/test/global_hooks.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								contracts/coordinator/test/global_hooks.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
import { env, EnvVars } from '@0x/dev-utils';
 | 
			
		||||
 | 
			
		||||
import { coverage, profiler, provider } from '@0x/contracts-test-utils';
 | 
			
		||||
import { providerUtils } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
before('start web3 provider', () => {
 | 
			
		||||
    providerUtils.startProviderEngine(provider);
 | 
			
		||||
});
 | 
			
		||||
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();
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										80
									
								
								contracts/coordinator/test/libs.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								contracts/coordinator/test/libs.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,80 @@
 | 
			
		||||
import { addressUtils, chaiSetup, constants, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
 | 
			
		||||
import { BlockchainLifecycle } from '@0x/dev-utils';
 | 
			
		||||
import { transactionHashUtils } from '@0x/order-utils';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
import * as chai from 'chai';
 | 
			
		||||
 | 
			
		||||
import { artifacts, CoordinatorContract, hashUtils } from '../src';
 | 
			
		||||
 | 
			
		||||
chaiSetup.configure();
 | 
			
		||||
const expect = chai.expect;
 | 
			
		||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
 | 
			
		||||
 | 
			
		||||
describe('Libs tests', () => {
 | 
			
		||||
    let coordinatorContract: CoordinatorContract;
 | 
			
		||||
    const exchangeAddress = addressUtils.generatePseudoRandomAddress();
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        await blockchainLifecycle.startAsync();
 | 
			
		||||
    });
 | 
			
		||||
    after(async () => {
 | 
			
		||||
        await blockchainLifecycle.revertAsync();
 | 
			
		||||
    });
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        coordinatorContract = await CoordinatorContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.Coordinator,
 | 
			
		||||
            provider,
 | 
			
		||||
            txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
            exchangeAddress,
 | 
			
		||||
        );
 | 
			
		||||
    });
 | 
			
		||||
    beforeEach(async () => {
 | 
			
		||||
        await blockchainLifecycle.startAsync();
 | 
			
		||||
    });
 | 
			
		||||
    afterEach(async () => {
 | 
			
		||||
        await blockchainLifecycle.revertAsync();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('getTransactionHash', () => {
 | 
			
		||||
        it('should return the correct transaction hash', async () => {
 | 
			
		||||
            const tx = {
 | 
			
		||||
                verifyingContractAddress: exchangeAddress,
 | 
			
		||||
                salt: new BigNumber(0),
 | 
			
		||||
                signerAddress: constants.NULL_ADDRESS,
 | 
			
		||||
                data: '0x1234',
 | 
			
		||||
            };
 | 
			
		||||
            const expectedTxHash = transactionHashUtils.getTransactionHashHex(tx);
 | 
			
		||||
            const txHash = await coordinatorContract.getTransactionHash.callAsync(tx);
 | 
			
		||||
            expect(expectedTxHash).to.eq(txHash);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('getApprovalHash', () => {
 | 
			
		||||
        it('should return the correct approval hash', async () => {
 | 
			
		||||
            const signedTx = {
 | 
			
		||||
                verifyingContractAddress: exchangeAddress,
 | 
			
		||||
                salt: new BigNumber(0),
 | 
			
		||||
                signerAddress: constants.NULL_ADDRESS,
 | 
			
		||||
                data: '0x1234',
 | 
			
		||||
                signature: '0x5678',
 | 
			
		||||
            };
 | 
			
		||||
            const approvalExpirationTimeSeconds = new BigNumber(0);
 | 
			
		||||
            const txOrigin = constants.NULL_ADDRESS;
 | 
			
		||||
            const approval = {
 | 
			
		||||
                txOrigin,
 | 
			
		||||
                transactionHash: transactionHashUtils.getTransactionHashHex(signedTx),
 | 
			
		||||
                transactionSignature: signedTx.signature,
 | 
			
		||||
                approvalExpirationTimeSeconds,
 | 
			
		||||
            };
 | 
			
		||||
            const expectedApprovalHash = hashUtils.getApprovalHashHex(
 | 
			
		||||
                signedTx,
 | 
			
		||||
                coordinatorContract.address,
 | 
			
		||||
                txOrigin,
 | 
			
		||||
                approvalExpirationTimeSeconds,
 | 
			
		||||
            );
 | 
			
		||||
            const approvalHash = await coordinatorContract.getCoordinatorApprovalHash.callAsync(approval);
 | 
			
		||||
            expect(expectedApprovalHash).to.eq(approvalHash);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										729
									
								
								contracts/coordinator/test/mixins.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										729
									
								
								contracts/coordinator/test/mixins.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,729 @@
 | 
			
		||||
import {
 | 
			
		||||
    addressUtils,
 | 
			
		||||
    chaiSetup,
 | 
			
		||||
    constants as devConstants,
 | 
			
		||||
    expectContractCallFailedAsync,
 | 
			
		||||
    getLatestBlockTimestampAsync,
 | 
			
		||||
    provider,
 | 
			
		||||
    TransactionFactory,
 | 
			
		||||
    txDefaults,
 | 
			
		||||
    web3Wrapper,
 | 
			
		||||
} from '@0x/contracts-test-utils';
 | 
			
		||||
import { BlockchainLifecycle } from '@0x/dev-utils';
 | 
			
		||||
import { transactionHashUtils } from '@0x/order-utils';
 | 
			
		||||
import { RevertReason, SignatureType, SignedOrder } from '@0x/types';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
import * as chai from 'chai';
 | 
			
		||||
import * as ethUtil from 'ethereumjs-util';
 | 
			
		||||
 | 
			
		||||
import { ApprovalFactory, artifacts, constants, CoordinatorContract, exchangeDataEncoder } from '../src';
 | 
			
		||||
 | 
			
		||||
chaiSetup.configure();
 | 
			
		||||
const expect = chai.expect;
 | 
			
		||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
 | 
			
		||||
 | 
			
		||||
describe('Mixins tests', () => {
 | 
			
		||||
    let transactionSignerAddress: string;
 | 
			
		||||
    let approvalSignerAddress1: string;
 | 
			
		||||
    let approvalSignerAddress2: string;
 | 
			
		||||
    let mixins: CoordinatorContract;
 | 
			
		||||
    let transactionFactory: TransactionFactory;
 | 
			
		||||
    let approvalFactory1: ApprovalFactory;
 | 
			
		||||
    let approvalFactory2: ApprovalFactory;
 | 
			
		||||
    let defaultOrder: SignedOrder;
 | 
			
		||||
    const exchangeAddress = addressUtils.generatePseudoRandomAddress();
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        await blockchainLifecycle.startAsync();
 | 
			
		||||
    });
 | 
			
		||||
    after(async () => {
 | 
			
		||||
        await blockchainLifecycle.revertAsync();
 | 
			
		||||
    });
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        mixins = await CoordinatorContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.Coordinator,
 | 
			
		||||
            provider,
 | 
			
		||||
            txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
            exchangeAddress,
 | 
			
		||||
        );
 | 
			
		||||
        const accounts = await web3Wrapper.getAvailableAddressesAsync();
 | 
			
		||||
        [transactionSignerAddress, approvalSignerAddress1, approvalSignerAddress2] = accounts.slice(0, 3);
 | 
			
		||||
        defaultOrder = {
 | 
			
		||||
            exchangeAddress: devConstants.NULL_ADDRESS,
 | 
			
		||||
            makerAddress: devConstants.NULL_ADDRESS,
 | 
			
		||||
            takerAddress: devConstants.NULL_ADDRESS,
 | 
			
		||||
            senderAddress: mixins.address,
 | 
			
		||||
            feeRecipientAddress: approvalSignerAddress1,
 | 
			
		||||
            makerAssetData: devConstants.NULL_BYTES,
 | 
			
		||||
            takerAssetData: devConstants.NULL_BYTES,
 | 
			
		||||
            makerAssetAmount: devConstants.ZERO_AMOUNT,
 | 
			
		||||
            takerAssetAmount: devConstants.ZERO_AMOUNT,
 | 
			
		||||
            makerFee: devConstants.ZERO_AMOUNT,
 | 
			
		||||
            takerFee: devConstants.ZERO_AMOUNT,
 | 
			
		||||
            expirationTimeSeconds: devConstants.ZERO_AMOUNT,
 | 
			
		||||
            salt: devConstants.ZERO_AMOUNT,
 | 
			
		||||
            signature: devConstants.NULL_BYTES,
 | 
			
		||||
        };
 | 
			
		||||
        const transactionSignerPrivateKey =
 | 
			
		||||
            devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(transactionSignerAddress)];
 | 
			
		||||
        const approvalSignerPrivateKey1 = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress1)];
 | 
			
		||||
        const approvalSignerPrivateKey2 = devConstants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(approvalSignerAddress2)];
 | 
			
		||||
        transactionFactory = new TransactionFactory(transactionSignerPrivateKey, exchangeAddress);
 | 
			
		||||
        approvalFactory1 = new ApprovalFactory(approvalSignerPrivateKey1, mixins.address);
 | 
			
		||||
        approvalFactory2 = new ApprovalFactory(approvalSignerPrivateKey2, mixins.address);
 | 
			
		||||
    });
 | 
			
		||||
    beforeEach(async () => {
 | 
			
		||||
        await blockchainLifecycle.startAsync();
 | 
			
		||||
    });
 | 
			
		||||
    afterEach(async () => {
 | 
			
		||||
        await blockchainLifecycle.revertAsync();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('getSignerAddress', () => {
 | 
			
		||||
        it('should return the correct address using the EthSign signature type', async () => {
 | 
			
		||||
            const data = devConstants.NULL_BYTES;
 | 
			
		||||
            const transaction = transactionFactory.newSignedTransaction(data, SignatureType.EthSign);
 | 
			
		||||
            const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
 | 
			
		||||
            const signerAddress = await mixins.getSignerAddress.callAsync(transactionHash, transaction.signature);
 | 
			
		||||
            expect(transaction.signerAddress).to.eq(signerAddress);
 | 
			
		||||
        });
 | 
			
		||||
        it('should return the correct address using the EIP712 signature type', async () => {
 | 
			
		||||
            const data = devConstants.NULL_BYTES;
 | 
			
		||||
            const transaction = transactionFactory.newSignedTransaction(data, SignatureType.EIP712);
 | 
			
		||||
            const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
 | 
			
		||||
            const signerAddress = await mixins.getSignerAddress.callAsync(transactionHash, transaction.signature);
 | 
			
		||||
            expect(transaction.signerAddress).to.eq(signerAddress);
 | 
			
		||||
        });
 | 
			
		||||
        it('should revert with with the Illegal signature type', async () => {
 | 
			
		||||
            const data = devConstants.NULL_BYTES;
 | 
			
		||||
            const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
            const illegalSignatureByte = ethUtil.toBuffer(SignatureType.Illegal).toString('hex');
 | 
			
		||||
            transaction.signature = `${transaction.signature.slice(
 | 
			
		||||
                0,
 | 
			
		||||
                transaction.signature.length - 2,
 | 
			
		||||
            )}${illegalSignatureByte}`;
 | 
			
		||||
            const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
 | 
			
		||||
            expectContractCallFailedAsync(
 | 
			
		||||
                mixins.getSignerAddress.callAsync(transactionHash, transaction.signature),
 | 
			
		||||
                RevertReason.SignatureIllegal,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('should revert with with the Invalid signature type', async () => {
 | 
			
		||||
            const data = devConstants.NULL_BYTES;
 | 
			
		||||
            const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
            const invalidSignatureByte = ethUtil.toBuffer(SignatureType.Invalid).toString('hex');
 | 
			
		||||
            transaction.signature = `0x${invalidSignatureByte}`;
 | 
			
		||||
            const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
 | 
			
		||||
            expectContractCallFailedAsync(
 | 
			
		||||
                mixins.getSignerAddress.callAsync(transactionHash, transaction.signature),
 | 
			
		||||
                RevertReason.SignatureInvalid,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it("should revert with with a signature type that doesn't exist", async () => {
 | 
			
		||||
            const data = devConstants.NULL_BYTES;
 | 
			
		||||
            const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
            const invalidSignatureByte = '04';
 | 
			
		||||
            transaction.signature = `${transaction.signature.slice(
 | 
			
		||||
                0,
 | 
			
		||||
                transaction.signature.length - 2,
 | 
			
		||||
            )}${invalidSignatureByte}`;
 | 
			
		||||
            const transactionHash = transactionHashUtils.getTransactionHashHex(transaction);
 | 
			
		||||
            expectContractCallFailedAsync(
 | 
			
		||||
                mixins.getSignerAddress.callAsync(transactionHash, transaction.signature),
 | 
			
		||||
                RevertReason.SignatureUnsupported,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('decodeOrdersFromFillData', () => {
 | 
			
		||||
        for (const fnName of constants.SINGLE_FILL_FN_NAMES) {
 | 
			
		||||
            it(`should correctly decode the orders for ${fnName} data`, async () => {
 | 
			
		||||
                const orders = [defaultOrder];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const decodedOrders = await mixins.decodeOrdersFromFillData.callAsync(data);
 | 
			
		||||
                const decodedSignedOrders = decodedOrders.map(order => ({
 | 
			
		||||
                    ...order,
 | 
			
		||||
                    exchangeAddress: devConstants.NULL_ADDRESS,
 | 
			
		||||
                    signature: devConstants.NULL_BYTES,
 | 
			
		||||
                }));
 | 
			
		||||
                expect(orders).to.deep.eq(decodedSignedOrders);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        for (const fnName of constants.BATCH_FILL_FN_NAMES) {
 | 
			
		||||
            it(`should correctly decode the orders for ${fnName} data`, async () => {
 | 
			
		||||
                const orders = [defaultOrder, defaultOrder];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const decodedOrders = await mixins.decodeOrdersFromFillData.callAsync(data);
 | 
			
		||||
                const decodedSignedOrders = decodedOrders.map(order => ({
 | 
			
		||||
                    ...order,
 | 
			
		||||
                    exchangeAddress: devConstants.NULL_ADDRESS,
 | 
			
		||||
                    signature: devConstants.NULL_BYTES,
 | 
			
		||||
                }));
 | 
			
		||||
                expect(orders).to.deep.eq(decodedSignedOrders);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        for (const fnName of constants.MARKET_FILL_FN_NAMES) {
 | 
			
		||||
            it(`should correctly decode the orders for ${fnName} data`, async () => {
 | 
			
		||||
                const orders = [defaultOrder, defaultOrder];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const decodedOrders = await mixins.decodeOrdersFromFillData.callAsync(data);
 | 
			
		||||
                const decodedSignedOrders = decodedOrders.map(order => ({
 | 
			
		||||
                    ...order,
 | 
			
		||||
                    exchangeAddress: devConstants.NULL_ADDRESS,
 | 
			
		||||
                    signature: devConstants.NULL_BYTES,
 | 
			
		||||
                }));
 | 
			
		||||
                expect(orders).to.deep.eq(decodedSignedOrders);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        for (const fnName of [constants.CANCEL_ORDER, constants.BATCH_CANCEL_ORDERS, constants.CANCEL_ORDERS_UP_TO]) {
 | 
			
		||||
            it(`should correctly decode the orders for ${fnName} data`, async () => {
 | 
			
		||||
                const orders = [defaultOrder, defaultOrder];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const decodedOrders = await mixins.decodeOrdersFromFillData.callAsync(data);
 | 
			
		||||
                const emptyArray: any[] = [];
 | 
			
		||||
                expect(emptyArray).to.deep.eq(decodedOrders);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        it('should decode an empty array for invalid data', async () => {
 | 
			
		||||
            const data = '0x0123456789';
 | 
			
		||||
            const decodedOrders = await mixins.decodeOrdersFromFillData.callAsync(data);
 | 
			
		||||
            const emptyArray: any[] = [];
 | 
			
		||||
            expect(emptyArray).to.deep.eq(decodedOrders);
 | 
			
		||||
        });
 | 
			
		||||
        it('should revert if data is less than 4 bytes long', async () => {
 | 
			
		||||
            const data = '0x010203';
 | 
			
		||||
            await expectContractCallFailedAsync(
 | 
			
		||||
                mixins.decodeOrdersFromFillData.callAsync(data),
 | 
			
		||||
                RevertReason.LibBytesGreaterOrEqualTo4LengthRequired,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('Single order approvals', () => {
 | 
			
		||||
        for (const fnName of constants.SINGLE_FILL_FN_NAMES) {
 | 
			
		||||
            it(`Should be successful: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[approver1], expiration=[valid]`, async () => {
 | 
			
		||||
                const orders = [defaultOrder];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval = approvalFactory1.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                await mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    transaction.signature,
 | 
			
		||||
                    [approvalExpirationTimeSeconds],
 | 
			
		||||
                    [approval.signature],
 | 
			
		||||
                    { from: transactionSignerAddress },
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`Should be successful: function=${fnName}, caller=tx_signer, senderAddress=[null], approval_sig=[approver1], expiration=[valid]`, async () => {
 | 
			
		||||
                const order = {
 | 
			
		||||
                    ...defaultOrder,
 | 
			
		||||
                    senderAddress: devConstants.NULL_ADDRESS,
 | 
			
		||||
                };
 | 
			
		||||
                const orders = [order];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval = approvalFactory1.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                await mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    transaction.signature,
 | 
			
		||||
                    [approvalExpirationTimeSeconds],
 | 
			
		||||
                    [approval.signature],
 | 
			
		||||
                    { from: transactionSignerAddress },
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[], expiration=[]`, async () => {
 | 
			
		||||
                const orders = [defaultOrder];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                await mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    approvalSignerAddress1,
 | 
			
		||||
                    transaction.signature,
 | 
			
		||||
                    [],
 | 
			
		||||
                    [],
 | 
			
		||||
                    {
 | 
			
		||||
                        from: approvalSignerAddress1,
 | 
			
		||||
                    },
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[approver1], expiration=[invalid]`, async () => {
 | 
			
		||||
                const orders = [defaultOrder];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval = approvalFactory1.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                await mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    approvalSignerAddress1,
 | 
			
		||||
                    transaction.signature,
 | 
			
		||||
                    [approvalExpirationTimeSeconds],
 | 
			
		||||
                    [approval.signature],
 | 
			
		||||
                    { from: approvalSignerAddress1 },
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`Should be successful: function=${fnName}, caller=approver1, senderAddress=[verifier], approval_sig=[], expiration=[]`, async () => {
 | 
			
		||||
                const orders = [defaultOrder];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                await mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    approvalSignerAddress1,
 | 
			
		||||
                    transaction.signature,
 | 
			
		||||
                    [],
 | 
			
		||||
                    [],
 | 
			
		||||
                    {
 | 
			
		||||
                        from: approvalSignerAddress1,
 | 
			
		||||
                    },
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`Should revert: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[invalid], expiration=[valid]`, async () => {
 | 
			
		||||
                const orders = [defaultOrder];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval = approvalFactory1.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`;
 | 
			
		||||
                expectContractCallFailedAsync(
 | 
			
		||||
                    mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        transactionSignerAddress,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [approvalExpirationTimeSeconds],
 | 
			
		||||
                        [signature],
 | 
			
		||||
                        { from: transactionSignerAddress },
 | 
			
		||||
                    ),
 | 
			
		||||
                    RevertReason.InvalidApprovalSignature,
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`Should revert: function=${fnName}, caller=tx_signer, senderAddress=[verifier], approval_sig=[approver1], expiration=[invalid]`, async () => {
 | 
			
		||||
                const orders = [defaultOrder];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval = approvalFactory1.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                expectContractCallFailedAsync(
 | 
			
		||||
                    mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        transactionSignerAddress,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [approvalExpirationTimeSeconds],
 | 
			
		||||
                        [approval.signature],
 | 
			
		||||
                        { from: transactionSignerAddress },
 | 
			
		||||
                    ),
 | 
			
		||||
                    RevertReason.ApprovalExpired,
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`Should revert: function=${fnName}, caller=approver2, senderAddress=[verifier], approval_sig=[approver1], expiration=[valid]`, async () => {
 | 
			
		||||
                const orders = [defaultOrder];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval = approvalFactory1.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                expectContractCallFailedAsync(
 | 
			
		||||
                    mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        transactionSignerAddress,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [approvalExpirationTimeSeconds],
 | 
			
		||||
                        [approval.signature],
 | 
			
		||||
                        { from: approvalSignerAddress2 },
 | 
			
		||||
                    ),
 | 
			
		||||
                    RevertReason.InvalidOrigin,
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    describe('Batch order approvals', () => {
 | 
			
		||||
        for (const fnName of [
 | 
			
		||||
            ...constants.BATCH_FILL_FN_NAMES,
 | 
			
		||||
            ...constants.MARKET_FILL_FN_NAMES,
 | 
			
		||||
            constants.MATCH_ORDERS,
 | 
			
		||||
        ]) {
 | 
			
		||||
            it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[approver1], expiration=[valid]`, async () => {
 | 
			
		||||
                const orders = [defaultOrder, defaultOrder];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval = approvalFactory1.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                await mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    transaction.signature,
 | 
			
		||||
                    [approvalExpirationTimeSeconds],
 | 
			
		||||
                    [approval.signature],
 | 
			
		||||
                    { from: transactionSignerAddress },
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[approver1], expiration=[valid]`, async () => {
 | 
			
		||||
                const orders = [defaultOrder, defaultOrder].map(order => ({
 | 
			
		||||
                    ...order,
 | 
			
		||||
                    senderAddress: devConstants.NULL_ADDRESS,
 | 
			
		||||
                }));
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval = approvalFactory1.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                await mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    transaction.signature,
 | 
			
		||||
                    [approvalExpirationTimeSeconds],
 | 
			
		||||
                    [approval.signature],
 | 
			
		||||
                    { from: transactionSignerAddress },
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[null,null], feeRecipient=[approver1,approver1], approval_sig=[], expiration=[]`, async () => {
 | 
			
		||||
                const orders = [defaultOrder, defaultOrder].map(order => ({
 | 
			
		||||
                    ...order,
 | 
			
		||||
                    senderAddress: devConstants.NULL_ADDRESS,
 | 
			
		||||
                }));
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                await mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    transaction.signature,
 | 
			
		||||
                    [],
 | 
			
		||||
                    [],
 | 
			
		||||
                    { from: transactionSignerAddress },
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,null], feeRecipient=[approver1,approver1], approval_sig=[approver1], expiration=[valid]`, async () => {
 | 
			
		||||
                const orders = [defaultOrder, { ...defaultOrder, senderAddress: devConstants.NULL_ADDRESS }];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval = approvalFactory1.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                await mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    transaction.signature,
 | 
			
		||||
                    [approvalExpirationTimeSeconds],
 | 
			
		||||
                    [approval.signature],
 | 
			
		||||
                    { from: transactionSignerAddress },
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`Should be successful: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver1,approver2], expiration=[valid,valid]`, async () => {
 | 
			
		||||
                const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval1 = approvalFactory1.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                const approval2 = approvalFactory2.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                await mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    transaction.signature,
 | 
			
		||||
                    [approvalExpirationTimeSeconds, approvalExpirationTimeSeconds],
 | 
			
		||||
                    [approval1.signature, approval2.signature],
 | 
			
		||||
                    { from: transactionSignerAddress },
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`Should be successful: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver1], approval_sig=[], expiration=[]`, async () => {
 | 
			
		||||
                const orders = [defaultOrder, defaultOrder];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                await mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    approvalSignerAddress1,
 | 
			
		||||
                    transaction.signature,
 | 
			
		||||
                    [],
 | 
			
		||||
                    [],
 | 
			
		||||
                    { from: approvalSignerAddress1 },
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1,approver2], approval_sig=[approver2], expiration=[valid]`, async () => {
 | 
			
		||||
                const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval2 = approvalFactory2.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                expectContractCallFailedAsync(
 | 
			
		||||
                    mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        transactionSignerAddress,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [approvalExpirationTimeSeconds],
 | 
			
		||||
                        [approval2.signature],
 | 
			
		||||
                        { from: approvalSignerAddress1 },
 | 
			
		||||
                    ),
 | 
			
		||||
                    RevertReason.InvalidOrigin,
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[], expiration=[]`, async () => {
 | 
			
		||||
                const orders = [defaultOrder, defaultOrder];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                expectContractCallFailedAsync(
 | 
			
		||||
                    mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        transactionSignerAddress,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [],
 | 
			
		||||
                        [],
 | 
			
		||||
                        { from: transactionSignerAddress },
 | 
			
		||||
                    ),
 | 
			
		||||
                    RevertReason.InvalidApprovalSignature,
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[invalid], expiration=[valid]`, async () => {
 | 
			
		||||
                const orders = [defaultOrder, defaultOrder];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval = approvalFactory1.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                const signature = `${approval.signature.slice(0, 4)}FFFFFFFF${approval.signature.slice(12)}`;
 | 
			
		||||
                expectContractCallFailedAsync(
 | 
			
		||||
                    mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        transactionSignerAddress,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [approvalExpirationTimeSeconds],
 | 
			
		||||
                        [signature],
 | 
			
		||||
                        { from: transactionSignerAddress },
 | 
			
		||||
                    ),
 | 
			
		||||
                    RevertReason.InvalidApprovalSignature,
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid,invalid], expiration=[valid,valid]`, async () => {
 | 
			
		||||
                const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval1 = approvalFactory1.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                const approval2 = approvalFactory2.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                const approvalSignature2 = `${approval2.signature.slice(0, 4)}FFFFFFFF${approval2.signature.slice(12)}`;
 | 
			
		||||
                expectContractCallFailedAsync(
 | 
			
		||||
                    mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        transactionSignerAddress,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [approvalExpirationTimeSeconds, approvalExpirationTimeSeconds],
 | 
			
		||||
                        [approval1.signature, approvalSignature2],
 | 
			
		||||
                        { from: transactionSignerAddress },
 | 
			
		||||
                    ),
 | 
			
		||||
                    RevertReason.InvalidApprovalSignature,
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[invalid], expiration=[valid]`, async () => {
 | 
			
		||||
                const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval2 = approvalFactory2.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                const approvalSignature2 = `${approval2.signature.slice(0, 4)}FFFFFFFF${approval2.signature.slice(12)}`;
 | 
			
		||||
                expectContractCallFailedAsync(
 | 
			
		||||
                    mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        approvalSignerAddress1,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [approvalExpirationTimeSeconds],
 | 
			
		||||
                        [approvalSignature2],
 | 
			
		||||
                        { from: approvalSignerAddress1 },
 | 
			
		||||
                    ),
 | 
			
		||||
                    RevertReason.InvalidApprovalSignature,
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`Should revert: function=${fnName} caller=tx_signer, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid,valid], expiration=[valid,invalid]`, async () => {
 | 
			
		||||
                const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds1 = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
 | 
			
		||||
                const approvalExpirationTimeSeconds2 = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval1 = approvalFactory1.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds1,
 | 
			
		||||
                );
 | 
			
		||||
                const approval2 = approvalFactory2.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds2,
 | 
			
		||||
                );
 | 
			
		||||
                expectContractCallFailedAsync(
 | 
			
		||||
                    mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        transactionSignerAddress,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [approvalExpirationTimeSeconds1, approvalExpirationTimeSeconds2],
 | 
			
		||||
                        [approval1.signature, approval2.signature],
 | 
			
		||||
                        { from: transactionSignerAddress },
 | 
			
		||||
                    ),
 | 
			
		||||
                    RevertReason.ApprovalExpired,
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`Should revert: function=${fnName} caller=approver1, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver2], approval_sig=[valid], expiration=[invalid]`, async () => {
 | 
			
		||||
                const orders = [defaultOrder, { ...defaultOrder, feeRecipientAddress: approvalSignerAddress2 }];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).minus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval2 = approvalFactory2.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                expectContractCallFailedAsync(
 | 
			
		||||
                    mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        approvalSignerAddress1,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [approvalExpirationTimeSeconds],
 | 
			
		||||
                        [approval2.signature],
 | 
			
		||||
                        { from: approvalSignerAddress1 },
 | 
			
		||||
                    ),
 | 
			
		||||
                    RevertReason.ApprovalExpired,
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
            it(`Should revert: function=${fnName} caller=approver2, senderAddress=[verifier,verifier], feeRecipient=[approver1, approver1], approval_sig=[valid], expiration=[valid]`, async () => {
 | 
			
		||||
                const orders = [defaultOrder, defaultOrder];
 | 
			
		||||
                const data = exchangeDataEncoder.encodeOrdersToExchangeData(fnName, orders);
 | 
			
		||||
                const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
                const currentTimestamp = await getLatestBlockTimestampAsync();
 | 
			
		||||
                const approvalExpirationTimeSeconds = new BigNumber(currentTimestamp).plus(constants.TIME_BUFFER);
 | 
			
		||||
                const approval1 = approvalFactory1.newSignedApproval(
 | 
			
		||||
                    transaction,
 | 
			
		||||
                    transactionSignerAddress,
 | 
			
		||||
                    approvalExpirationTimeSeconds,
 | 
			
		||||
                );
 | 
			
		||||
                expectContractCallFailedAsync(
 | 
			
		||||
                    mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                        transaction,
 | 
			
		||||
                        transactionSignerAddress,
 | 
			
		||||
                        transaction.signature,
 | 
			
		||||
                        [approvalExpirationTimeSeconds],
 | 
			
		||||
                        [approval1.signature],
 | 
			
		||||
                        { from: approvalSignerAddress2 },
 | 
			
		||||
                    ),
 | 
			
		||||
                    RevertReason.InvalidOrigin,
 | 
			
		||||
                );
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    describe('cancels', () => {
 | 
			
		||||
        it('should allow the tx signer to call `cancelOrder` without approval', async () => {
 | 
			
		||||
            const orders = [defaultOrder];
 | 
			
		||||
            const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDER, orders);
 | 
			
		||||
            const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
            await mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                transaction,
 | 
			
		||||
                transactionSignerAddress,
 | 
			
		||||
                transaction.signature,
 | 
			
		||||
                [],
 | 
			
		||||
                [],
 | 
			
		||||
                { from: transactionSignerAddress },
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('should allow the tx signer to call `batchCancelOrders` without approval', async () => {
 | 
			
		||||
            const orders = [defaultOrder, defaultOrder];
 | 
			
		||||
            const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.BATCH_CANCEL_ORDERS, orders);
 | 
			
		||||
            const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
            await mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                transaction,
 | 
			
		||||
                transactionSignerAddress,
 | 
			
		||||
                transaction.signature,
 | 
			
		||||
                [],
 | 
			
		||||
                [],
 | 
			
		||||
                { from: transactionSignerAddress },
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('should allow the tx signer to call `cancelOrdersUpTo` without approval', async () => {
 | 
			
		||||
            const orders: SignedOrder[] = [];
 | 
			
		||||
            const data = exchangeDataEncoder.encodeOrdersToExchangeData(constants.CANCEL_ORDERS_UP_TO, orders);
 | 
			
		||||
            const transaction = transactionFactory.newSignedTransaction(data);
 | 
			
		||||
            await mixins.assertValidCoordinatorApprovals.callAsync(
 | 
			
		||||
                transaction,
 | 
			
		||||
                transactionSignerAddress,
 | 
			
		||||
                transaction.signature,
 | 
			
		||||
                [],
 | 
			
		||||
                [],
 | 
			
		||||
                { from: transactionSignerAddress },
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
// tslint:disable:max-file-line-count
 | 
			
		||||
							
								
								
									
										38
									
								
								contracts/coordinator/test/utils/approval_factory.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								contracts/coordinator/test/utils/approval_factory.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
import { signingUtils } from '@0x/contracts-test-utils';
 | 
			
		||||
import { SignatureType, SignedZeroExTransaction } from '@0x/types';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
import * as ethUtil from 'ethereumjs-util';
 | 
			
		||||
 | 
			
		||||
import { hashUtils, SignedCoordinatorApproval } from './index';
 | 
			
		||||
 | 
			
		||||
export class ApprovalFactory {
 | 
			
		||||
    private readonly _privateKey: Buffer;
 | 
			
		||||
    private readonly _verifyingContractAddress: string;
 | 
			
		||||
 | 
			
		||||
    constructor(privateKey: Buffer, verifyingContractAddress: string) {
 | 
			
		||||
        this._privateKey = privateKey;
 | 
			
		||||
        this._verifyingContractAddress = verifyingContractAddress;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public newSignedApproval(
 | 
			
		||||
        transaction: SignedZeroExTransaction,
 | 
			
		||||
        txOrigin: string,
 | 
			
		||||
        approvalExpirationTimeSeconds: BigNumber,
 | 
			
		||||
        signatureType: SignatureType = SignatureType.EthSign,
 | 
			
		||||
    ): SignedCoordinatorApproval {
 | 
			
		||||
        const approvalHashBuff = hashUtils.getApprovalHashBuffer(
 | 
			
		||||
            transaction,
 | 
			
		||||
            this._verifyingContractAddress,
 | 
			
		||||
            txOrigin,
 | 
			
		||||
            approvalExpirationTimeSeconds,
 | 
			
		||||
        );
 | 
			
		||||
        const signatureBuff = signingUtils.signMessage(approvalHashBuff, this._privateKey, signatureType);
 | 
			
		||||
        const signedApproval = {
 | 
			
		||||
            txOrigin,
 | 
			
		||||
            transaction,
 | 
			
		||||
            approvalExpirationTimeSeconds,
 | 
			
		||||
            signature: ethUtil.addHexPrefix(signatureBuff.toString('hex')),
 | 
			
		||||
        };
 | 
			
		||||
        return signedApproval;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								contracts/coordinator/test/utils/constants.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								contracts/coordinator/test/utils/constants.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
export const constants = {
 | 
			
		||||
    SINGLE_FILL_FN_NAMES: ['fillOrder', 'fillOrKillOrder', 'fillOrderNoThrow'],
 | 
			
		||||
    BATCH_FILL_FN_NAMES: ['batchFillOrders', 'batchFillOrKillOrders', 'batchFillOrdersNoThrow'],
 | 
			
		||||
    MARKET_FILL_FN_NAMES: ['marketBuyOrders', 'marketBuyOrdersNoThrow', 'marketSellOrders', 'marketSellOrdersNoThrow'],
 | 
			
		||||
    MATCH_ORDERS: 'matchOrders',
 | 
			
		||||
    CANCEL_ORDER: 'cancelOrder',
 | 
			
		||||
    BATCH_CANCEL_ORDERS: 'batchCancelOrders',
 | 
			
		||||
    CANCEL_ORDERS_UP_TO: 'cancelOrdersUpTo',
 | 
			
		||||
    TIME_BUFFER: new BigNumber(1000),
 | 
			
		||||
};
 | 
			
		||||
@@ -0,0 +1,65 @@
 | 
			
		||||
import { LogDecoder, txDefaults } from '@0x/contracts-test-utils';
 | 
			
		||||
import { Web3Wrapper } from '@0x/web3-wrapper';
 | 
			
		||||
import { TransactionReceiptWithDecodedLogs, ZeroExProvider } from 'ethereum-types';
 | 
			
		||||
 | 
			
		||||
import { artifacts, CoordinatorRegistryContract } from '../../src';
 | 
			
		||||
 | 
			
		||||
export class CoordinatorRegistryWrapper {
 | 
			
		||||
    private readonly _web3Wrapper: Web3Wrapper;
 | 
			
		||||
    private readonly _provider: ZeroExProvider;
 | 
			
		||||
    private readonly _logDecoder: LogDecoder;
 | 
			
		||||
    private _coordinatorRegistryContract?: CoordinatorRegistryContract;
 | 
			
		||||
    /**
 | 
			
		||||
     * Instanitates an CoordinatorRegistryWrapper
 | 
			
		||||
     * @param provider Web3 provider to use for all JSON RPC requests
 | 
			
		||||
     * Instance of CoordinatorRegistryWrapper
 | 
			
		||||
     */
 | 
			
		||||
    constructor(provider: ZeroExProvider) {
 | 
			
		||||
        this._web3Wrapper = new Web3Wrapper(provider);
 | 
			
		||||
        this._provider = provider;
 | 
			
		||||
        this._logDecoder = new LogDecoder(this._web3Wrapper, artifacts);
 | 
			
		||||
    }
 | 
			
		||||
    public async deployCoordinatorRegistryAsync(): Promise<CoordinatorRegistryContract> {
 | 
			
		||||
        this._coordinatorRegistryContract = await CoordinatorRegistryContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.CoordinatorRegistry,
 | 
			
		||||
            this._provider,
 | 
			
		||||
            txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
        if (this._coordinatorRegistryContract === undefined) {
 | 
			
		||||
            throw new Error(`Failed to deploy Coordinator Registry contract.`);
 | 
			
		||||
        }
 | 
			
		||||
        return this._coordinatorRegistryContract;
 | 
			
		||||
    }
 | 
			
		||||
    public async setCoordinatorEndpointAsync(
 | 
			
		||||
        coordinatorOperator: string,
 | 
			
		||||
        coordinatorEndpoint: string,
 | 
			
		||||
    ): Promise<TransactionReceiptWithDecodedLogs> {
 | 
			
		||||
        this._assertCoordinatorRegistryDeployed();
 | 
			
		||||
        const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(
 | 
			
		||||
            await (this
 | 
			
		||||
                ._coordinatorRegistryContract as CoordinatorRegistryContract).setCoordinatorEndpoint.sendTransactionAsync(
 | 
			
		||||
                coordinatorEndpoint,
 | 
			
		||||
                {
 | 
			
		||||
                    from: coordinatorOperator,
 | 
			
		||||
                },
 | 
			
		||||
            ),
 | 
			
		||||
        );
 | 
			
		||||
        return txReceipt;
 | 
			
		||||
    }
 | 
			
		||||
    public async getCoordinatorEndpointAsync(coordinatorOperator: string): Promise<string> {
 | 
			
		||||
        this._assertCoordinatorRegistryDeployed();
 | 
			
		||||
        const coordinatorEndpoint = await (this
 | 
			
		||||
            ._coordinatorRegistryContract as CoordinatorRegistryContract).getCoordinatorEndpoint.callAsync(
 | 
			
		||||
            coordinatorOperator,
 | 
			
		||||
        );
 | 
			
		||||
        return coordinatorEndpoint;
 | 
			
		||||
    }
 | 
			
		||||
    private _assertCoordinatorRegistryDeployed(): void {
 | 
			
		||||
        if (this._coordinatorRegistryContract === undefined) {
 | 
			
		||||
            throw new Error(
 | 
			
		||||
                'The Coordinator Registry contract was not deployed through the CoordinatorRegistryWrapper. Call `deployCoordinatorRegistryAsync` to deploy.',
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										47
									
								
								contracts/coordinator/test/utils/exchange_data_encoder.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								contracts/coordinator/test/utils/exchange_data_encoder.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
import { IExchangeContract } from '@0x/contracts-exchange';
 | 
			
		||||
import { constants as devConstants, provider } from '@0x/contracts-test-utils';
 | 
			
		||||
import { SignedOrder } from '@0x/types';
 | 
			
		||||
 | 
			
		||||
import { constants } from './index';
 | 
			
		||||
 | 
			
		||||
export const exchangeDataEncoder = {
 | 
			
		||||
    encodeOrdersToExchangeData(fnName: string, orders: SignedOrder[]): string {
 | 
			
		||||
        const exchangeInstance = new IExchangeContract(devConstants.NULL_ADDRESS, provider);
 | 
			
		||||
        let data;
 | 
			
		||||
        if (constants.SINGLE_FILL_FN_NAMES.indexOf(fnName) !== -1) {
 | 
			
		||||
            data = (exchangeInstance as any)[fnName].getABIEncodedTransactionData(
 | 
			
		||||
                orders[0],
 | 
			
		||||
                orders[0].takerAssetAmount,
 | 
			
		||||
                orders[0].signature,
 | 
			
		||||
            );
 | 
			
		||||
        } else if (constants.BATCH_FILL_FN_NAMES.indexOf(fnName) !== -1) {
 | 
			
		||||
            data = (exchangeInstance as any)[fnName].getABIEncodedTransactionData(
 | 
			
		||||
                orders,
 | 
			
		||||
                orders.map(order => order.takerAssetAmount),
 | 
			
		||||
                orders.map(order => order.signature),
 | 
			
		||||
            );
 | 
			
		||||
        } else if (constants.MARKET_FILL_FN_NAMES.indexOf(fnName) !== -1) {
 | 
			
		||||
            data = (exchangeInstance as any)[fnName].getABIEncodedTransactionData(
 | 
			
		||||
                orders,
 | 
			
		||||
                orders.map(order => order.takerAssetAmount).reduce((prev, curr) => prev.plus(curr)),
 | 
			
		||||
                orders.map(order => order.signature),
 | 
			
		||||
            );
 | 
			
		||||
        } else if (fnName === constants.MATCH_ORDERS) {
 | 
			
		||||
            data = exchangeInstance.matchOrders.getABIEncodedTransactionData(
 | 
			
		||||
                orders[0],
 | 
			
		||||
                orders[1],
 | 
			
		||||
                orders[0].signature,
 | 
			
		||||
                orders[1].signature,
 | 
			
		||||
            );
 | 
			
		||||
        } else if (fnName === constants.CANCEL_ORDER) {
 | 
			
		||||
            data = exchangeInstance.cancelOrder.getABIEncodedTransactionData(orders[0]);
 | 
			
		||||
        } else if (fnName === constants.BATCH_CANCEL_ORDERS) {
 | 
			
		||||
            data = exchangeInstance.batchCancelOrders.getABIEncodedTransactionData(orders);
 | 
			
		||||
        } else if (fnName === constants.CANCEL_ORDERS_UP_TO) {
 | 
			
		||||
            data = exchangeInstance.cancelOrdersUpTo.getABIEncodedTransactionData(devConstants.ZERO_AMOUNT);
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new Error(`Error: ${fnName} not a supported function`);
 | 
			
		||||
        }
 | 
			
		||||
        return data;
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										33
									
								
								contracts/coordinator/test/utils/hash_utils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								contracts/coordinator/test/utils/hash_utils.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
import { eip712Utils } from '@0x/order-utils';
 | 
			
		||||
import { SignedZeroExTransaction } from '@0x/types';
 | 
			
		||||
import { BigNumber, signTypedDataUtils } from '@0x/utils';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
export const hashUtils = {
 | 
			
		||||
    getApprovalHashBuffer(
 | 
			
		||||
        transaction: SignedZeroExTransaction,
 | 
			
		||||
        verifyingContractAddress: string,
 | 
			
		||||
        txOrigin: string,
 | 
			
		||||
        approvalExpirationTimeSeconds: BigNumber,
 | 
			
		||||
    ): Buffer {
 | 
			
		||||
        const typedData = eip712Utils.createCoordinatorApprovalTypedData(
 | 
			
		||||
            transaction,
 | 
			
		||||
            verifyingContractAddress,
 | 
			
		||||
            txOrigin,
 | 
			
		||||
            approvalExpirationTimeSeconds,
 | 
			
		||||
        );
 | 
			
		||||
        const hashBuffer = signTypedDataUtils.generateTypedDataHash(typedData);
 | 
			
		||||
        return hashBuffer;
 | 
			
		||||
    },
 | 
			
		||||
    getApprovalHashHex(
 | 
			
		||||
        transaction: SignedZeroExTransaction,
 | 
			
		||||
        verifyingContractAddress: string,
 | 
			
		||||
        txOrigin: string,
 | 
			
		||||
        approvalExpirationTimeSeconds: BigNumber,
 | 
			
		||||
    ): string {
 | 
			
		||||
        const hashHex = `0x${hashUtils
 | 
			
		||||
            .getApprovalHashBuffer(transaction, verifyingContractAddress, txOrigin, approvalExpirationTimeSeconds)
 | 
			
		||||
            .toString('hex')}`;
 | 
			
		||||
        return hashHex;
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										5
									
								
								contracts/coordinator/test/utils/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								contracts/coordinator/test/utils/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
export { hashUtils } from './hash_utils';
 | 
			
		||||
export { ApprovalFactory } from './approval_factory';
 | 
			
		||||
export { constants } from './constants';
 | 
			
		||||
export { exchangeDataEncoder } from './exchange_data_encoder';
 | 
			
		||||
export * from './types';
 | 
			
		||||
							
								
								
									
										12
									
								
								contracts/coordinator/test/utils/types.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								contracts/coordinator/test/utils/types.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
import { SignedZeroExTransaction } from '@0x/types';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
export interface CoordinatorApproval {
 | 
			
		||||
    transaction: SignedZeroExTransaction;
 | 
			
		||||
    txOrigin: string;
 | 
			
		||||
    approvalExpirationTimeSeconds: BigNumber;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SignedCoordinatorApproval extends CoordinatorApproval {
 | 
			
		||||
    signature: string;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								contracts/coordinator/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								contracts/coordinator/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
    "extends": "../../tsconfig",
 | 
			
		||||
    "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
 | 
			
		||||
    "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
 | 
			
		||||
    "files": ["generated-artifacts/Coordinator.json", "generated-artifacts/CoordinatorRegistry.json"],
 | 
			
		||||
    "exclude": ["./deploy/solc/solc_bin"]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								contracts/coordinator/tslint.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								contracts/coordinator/tslint.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "extends": ["@0x/tslint-config"],
 | 
			
		||||
    "rules": {
 | 
			
		||||
        "custom-no-magic-numbers": false
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										104
									
								
								contracts/dev-utils/CHANGELOG.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								contracts/dev-utils/CHANGELOG.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1566446343,
 | 
			
		||||
        "version": "0.0.8",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1565296576,
 | 
			
		||||
        "version": "0.0.7",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1564607468,
 | 
			
		||||
        "version": "0.0.6",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "0.0.5",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Updated calls to <contract wrapper>.deployFrom0xArtifactAsync to include artifact dependencies.",
 | 
			
		||||
                "pr": 1995
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1564604963
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1563957393,
 | 
			
		||||
        "version": "0.0.5",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1563193019,
 | 
			
		||||
        "version": "0.0.4",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1563047529,
 | 
			
		||||
        "version": "0.0.3",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1563006338,
 | 
			
		||||
        "version": "0.0.2",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "0.0.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Create dev-utils package",
 | 
			
		||||
                "pr": 1848
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add `LibAssetData` and `LibTransactionDecoder` contracts",
 | 
			
		||||
                "pr": 1848
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Refactor `LibAssetData` to only check 0x-specific allowances",
 | 
			
		||||
                "pr": 1848
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Refactor `LibAssetData` balance/allowance checks to never revert",
 | 
			
		||||
                "pr": 1848
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Refactor `OrderValidationUtils` to calculate `fillableTakerAssetAmount`",
 | 
			
		||||
                "pr": 1848
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add support for StaticCallProxy",
 | 
			
		||||
                "pr": 1863
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    }
 | 
			
		||||
]
 | 
			
		||||
							
								
								
									
										47
									
								
								contracts/dev-utils/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								contracts/dev-utils/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
<!--
 | 
			
		||||
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
 | 
			
		||||
Edit the package's CHANGELOG.json file only.
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v0.0.8 - _August 22, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v0.0.7 - _August 8, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v0.0.6 - _July 31, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v0.0.5 - _July 31, 2019_
 | 
			
		||||
 | 
			
		||||
    * Updated calls to <contract wrapper>.deployFrom0xArtifactAsync to include artifact dependencies. (#1995)
 | 
			
		||||
 | 
			
		||||
## v0.0.5 - _July 24, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v0.0.4 - _July 15, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v0.0.3 - _July 13, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v0.0.2 - _July 13, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v0.0.1 - _Invalid date_
 | 
			
		||||
 | 
			
		||||
    * Create dev-utils package (#1848)
 | 
			
		||||
    * Add `LibAssetData` and `LibTransactionDecoder` contracts (#1848)
 | 
			
		||||
    * Refactor `LibAssetData` to only check 0x-specific allowances (#1848)
 | 
			
		||||
    * Refactor `LibAssetData` balance/allowance checks to never revert (#1848)
 | 
			
		||||
    * Refactor `OrderValidationUtils` to calculate `fillableTakerAssetAmount` (#1848)
 | 
			
		||||
    * Add support for StaticCallProxy (#1863)
 | 
			
		||||
							
								
								
									
										73
									
								
								contracts/dev-utils/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								contracts/dev-utils/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
## Dev-Utils
 | 
			
		||||
 | 
			
		||||
This package implements various utilities for developers. For example, the `DevUtils` contract can query batches of balances or allowances given some `assetData`, can validate batches of orders, and can decode 0x-specific calldata. Addresses of the deployed contracts can be found in the 0x [wiki](https://0xproject.com/wiki#Deployed-Addresses) or the [DEPLOYS](./DEPLOYS.json) file within this package.
 | 
			
		||||
 | 
			
		||||
## Installation
 | 
			
		||||
 | 
			
		||||
**Install**
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npm install @0x/contracts-dev-utils --save
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 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).
 | 
			
		||||
							
								
								
									
										32
									
								
								contracts/dev-utils/compiler.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								contracts/dev-utils/compiler.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
{
 | 
			
		||||
    "artifactsDir": "./generated-artifacts",
 | 
			
		||||
    "contractsDir": "./contracts",
 | 
			
		||||
    "useDockerisedSolc": false,
 | 
			
		||||
    "isOfflineMode": false,
 | 
			
		||||
    "compilerSettings": {
 | 
			
		||||
        "evmVersion": "constantinople",
 | 
			
		||||
        "optimizer": {
 | 
			
		||||
            "enabled": true,
 | 
			
		||||
            "runs": 1000000,
 | 
			
		||||
            "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true }
 | 
			
		||||
        },
 | 
			
		||||
        "outputSelection": {
 | 
			
		||||
            "*": {
 | 
			
		||||
                "*": [
 | 
			
		||||
                    "abi",
 | 
			
		||||
                    "devdoc",
 | 
			
		||||
                    "evm.bytecode.object",
 | 
			
		||||
                    "evm.bytecode.sourceMap",
 | 
			
		||||
                    "evm.deployedBytecode.object",
 | 
			
		||||
                    "evm.deployedBytecode.sourceMap"
 | 
			
		||||
                ]
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    "contracts": [
 | 
			
		||||
        "src/DevUtils.sol",
 | 
			
		||||
        "src/LibAssetData.sol",
 | 
			
		||||
        "src/LibTransactionDecoder.sol",
 | 
			
		||||
        "src/EthBalanceChecker.sol"
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								contracts/dev-utils/contracts/src/DevUtils.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								contracts/dev-utils/contracts/src/DevUtils.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "./OrderValidationUtils.sol";
 | 
			
		||||
import "./LibTransactionDecoder.sol";
 | 
			
		||||
import "./EthBalanceChecker.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable no-empty-blocks
 | 
			
		||||
contract DevUtils is
 | 
			
		||||
    OrderValidationUtils,
 | 
			
		||||
    LibTransactionDecoder,
 | 
			
		||||
    EthBalanceChecker
 | 
			
		||||
{
 | 
			
		||||
    constructor (address _exchange, bytes memory _zrxAssetData)
 | 
			
		||||
        public
 | 
			
		||||
        OrderValidationUtils(_exchange, _zrxAssetData)
 | 
			
		||||
    {}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								contracts/dev-utils/contracts/src/EthBalanceChecker.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								contracts/dev-utils/contracts/src/EthBalanceChecker.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2018 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract EthBalanceChecker {
 | 
			
		||||
 | 
			
		||||
    /// @dev Batch fetches ETH balances
 | 
			
		||||
    /// @param addresses Array of addresses.
 | 
			
		||||
    /// @return Array of ETH balances.
 | 
			
		||||
    function getEthBalances(address[] memory addresses)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory)
 | 
			
		||||
    {
 | 
			
		||||
        uint256[] memory balances = new uint256[](addresses.length);
 | 
			
		||||
        for (uint256 i = 0; i != addresses.length; i++) {
 | 
			
		||||
            balances[i] = addresses[i].balance;
 | 
			
		||||
        }
 | 
			
		||||
        return balances;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										541
									
								
								contracts/dev-utils/contracts/src/LibAssetData.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										541
									
								
								contracts/dev-utils/contracts/src/LibAssetData.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,541 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2019 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
 | 
			
		||||
import "@0x/contracts-asset-proxy/contracts/src/libs/LibAssetProxyIds.sol";
 | 
			
		||||
import "@0x/contracts-exchange/contracts/src/interfaces/IExchange.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract LibAssetData is
 | 
			
		||||
    LibAssetProxyIds
 | 
			
		||||
{
 | 
			
		||||
    // 2^256 - 1
 | 
			
		||||
    uint256 constant internal _MAX_UINT256 = uint256(-1);
 | 
			
		||||
 | 
			
		||||
    // ERC20 selectors
 | 
			
		||||
    bytes4 constant internal _ERC20_BALANCE_OF_SELECTOR = 0x70a08231;
 | 
			
		||||
    bytes4 constant internal _ERC20_ALLOWANCE_SELECTOR = 0xdd62ed3e;
 | 
			
		||||
 | 
			
		||||
    // ERC721 selectors
 | 
			
		||||
    bytes4 constant internal _ERC721_OWNER_OF_SELECTOR = 0x6352211e;
 | 
			
		||||
    bytes4 constant internal _ERC721_IS_APPROVED_FOR_ALL_SELECTOR = 0xe985e9c5;
 | 
			
		||||
    bytes4 constant internal _ERC721_GET_APPROVED_SELECTOR = 0x081812fc;
 | 
			
		||||
 | 
			
		||||
    // ERC1155 selectors
 | 
			
		||||
    bytes4 constant internal _ERC1155_BALANCE_OF_SELECTOR = 0x00fdd58e;
 | 
			
		||||
    bytes4 constant internal _ERC1155_IS_APPROVED_FOR_ALL_SELECTOR = 0xe985e9c5;
 | 
			
		||||
 | 
			
		||||
    // `transferFrom` selector for all AssetProxy contracts
 | 
			
		||||
    bytes4 constant internal _ASSET_PROXY_TRANSFER_FROM_SELECTOR = 0xa85e59e4;
 | 
			
		||||
 | 
			
		||||
    using LibBytes for bytes;
 | 
			
		||||
 | 
			
		||||
    // solhint-disable var-name-mixedcase
 | 
			
		||||
    IExchange internal _EXCHANGE;
 | 
			
		||||
    address internal _ERC20_PROXY_ADDRESS;
 | 
			
		||||
    address internal _ERC721_PROXY_ADDRESS;
 | 
			
		||||
    address internal _ERC1155_PROXY_ADDRESS;
 | 
			
		||||
    address internal _STATIC_CALL_PROXY_ADDRESS;
 | 
			
		||||
    // solhint-enable var-name-mixedcase
 | 
			
		||||
 | 
			
		||||
    constructor (address _exchange)
 | 
			
		||||
        public
 | 
			
		||||
    {
 | 
			
		||||
        _EXCHANGE = IExchange(_exchange);
 | 
			
		||||
        _ERC20_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(ERC20_PROXY_ID);
 | 
			
		||||
        _ERC721_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(ERC721_PROXY_ID);
 | 
			
		||||
        _ERC1155_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(ERC1155_PROXY_ID);
 | 
			
		||||
        _STATIC_CALL_PROXY_ADDRESS = _EXCHANGE.getAssetProxy(STATIC_CALL_PROXY_ID);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Returns the owner's balance of the assets(s) specified in
 | 
			
		||||
    /// assetData.  When the asset data contains multiple assets (eg in
 | 
			
		||||
    /// ERC1155 or Multi-Asset), the return value indicates how many
 | 
			
		||||
    /// complete "baskets" of those assets are owned by owner.
 | 
			
		||||
    /// @param ownerAddress Owner of the assets specified by assetData.
 | 
			
		||||
    /// @param assetData Details of asset, encoded per the AssetProxy contract specification.
 | 
			
		||||
    /// @return Number of assets (or asset baskets) held by owner.
 | 
			
		||||
    function getBalance(address ownerAddress, bytes memory assetData)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 balance)
 | 
			
		||||
    {
 | 
			
		||||
        // Get id of AssetProxy contract
 | 
			
		||||
        bytes4 assetProxyId = assetData.readBytes4(0);
 | 
			
		||||
 | 
			
		||||
        if (assetProxyId == ERC20_PROXY_ID) {
 | 
			
		||||
            // Get ERC20 token address
 | 
			
		||||
            address tokenAddress = assetData.readAddress(16);
 | 
			
		||||
 | 
			
		||||
            // Encode data for `balanceOf(ownerAddress)`
 | 
			
		||||
            bytes memory balanceOfData = abi.encodeWithSelector(_ERC20_BALANCE_OF_SELECTOR, ownerAddress);
 | 
			
		||||
 | 
			
		||||
            // Query balance
 | 
			
		||||
            (bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData);
 | 
			
		||||
            balance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
 | 
			
		||||
        } else if (assetProxyId == ERC721_PROXY_ID) {
 | 
			
		||||
            // Get ERC721 token address and id
 | 
			
		||||
            (, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
 | 
			
		||||
 | 
			
		||||
            // Check if id is owned by ownerAddress
 | 
			
		||||
            balance = getERC721TokenOwner(tokenAddress, tokenId) == ownerAddress ? 1 : 0;
 | 
			
		||||
        } else if (assetProxyId == ERC1155_PROXY_ID) {
 | 
			
		||||
            // Get ERC1155 token address, array of ids, and array of values
 | 
			
		||||
            (, address tokenAddress, uint256[] memory tokenIds, uint256[] memory tokenValues,) = decodeERC1155AssetData(assetData);
 | 
			
		||||
 | 
			
		||||
            uint256 length = tokenIds.length;
 | 
			
		||||
            for (uint256 i = 0; i != length; i++) {
 | 
			
		||||
                // Encode data for `balanceOf(ownerAddress, tokenIds[i])
 | 
			
		||||
                bytes memory balanceOfData = abi.encodeWithSelector(
 | 
			
		||||
                    _ERC1155_BALANCE_OF_SELECTOR,
 | 
			
		||||
                    ownerAddress,
 | 
			
		||||
                    tokenIds[i]
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                // Query balance
 | 
			
		||||
                (bool success, bytes memory returnData) = tokenAddress.staticcall(balanceOfData);
 | 
			
		||||
                uint256 totalBalance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
 | 
			
		||||
 | 
			
		||||
                // Scale total balance down by corresponding value in assetData
 | 
			
		||||
                uint256 scaledBalance = totalBalance / tokenValues[i];
 | 
			
		||||
                if (scaledBalance < balance || balance == 0) {
 | 
			
		||||
                    balance = scaledBalance;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else if (assetProxyId == STATIC_CALL_PROXY_ID) {
 | 
			
		||||
            // Encode data for `staticCallProxy.transferFrom(assetData,...)`
 | 
			
		||||
            bytes memory transferFromData = abi.encodeWithSelector(
 | 
			
		||||
                _ASSET_PROXY_TRANSFER_FROM_SELECTOR,
 | 
			
		||||
                assetData,
 | 
			
		||||
                address(0),  // `from` address is not used
 | 
			
		||||
                address(0),  // `to` address is not used
 | 
			
		||||
                0            // `amount` is not used
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // Check if staticcall would be successful
 | 
			
		||||
            (bool success,) = _STATIC_CALL_PROXY_ADDRESS.staticcall(transferFromData);
 | 
			
		||||
 | 
			
		||||
            // Success means that the staticcall can be made an unlimited amount of times
 | 
			
		||||
            balance = success ? _MAX_UINT256 : 0;
 | 
			
		||||
        } else if (assetProxyId == MULTI_ASSET_PROXY_ID) {
 | 
			
		||||
            // Get array of values and array of assetDatas
 | 
			
		||||
            (, uint256[] memory assetAmounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
 | 
			
		||||
 | 
			
		||||
            uint256 length = nestedAssetData.length;
 | 
			
		||||
            for (uint256 i = 0; i != length; i++) {
 | 
			
		||||
                // Query balance of individual assetData
 | 
			
		||||
                uint256 totalBalance = getBalance(ownerAddress, nestedAssetData[i]);
 | 
			
		||||
 | 
			
		||||
                // Scale total balance down by corresponding value in assetData
 | 
			
		||||
                uint256 scaledBalance = totalBalance / assetAmounts[i];
 | 
			
		||||
                if (scaledBalance < balance || balance == 0) {
 | 
			
		||||
                    balance = scaledBalance;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } 
 | 
			
		||||
 | 
			
		||||
        // Balance will be 0 if assetProxyId is unknown
 | 
			
		||||
        return balance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls getBalance() for each element of assetData.
 | 
			
		||||
    /// @param ownerAddress Owner of the assets specified by assetData.
 | 
			
		||||
    /// @param assetData Array of asset details, each encoded per the AssetProxy contract specification.
 | 
			
		||||
    /// @return Array of asset balances from getBalance(), with each element
 | 
			
		||||
    /// corresponding to the same-indexed element in the assetData input.
 | 
			
		||||
    function getBatchBalances(address ownerAddress, bytes[] memory assetData)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory balances)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 length = assetData.length;
 | 
			
		||||
        balances = new uint256[](length);
 | 
			
		||||
        for (uint256 i = 0; i != length; i++) {
 | 
			
		||||
            balances[i] = getBalance(ownerAddress, assetData[i]);
 | 
			
		||||
        }
 | 
			
		||||
        return balances;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Returns the number of asset(s) (described by assetData) that
 | 
			
		||||
    /// the corresponding AssetProxy contract is authorized to spend.  When the asset data contains
 | 
			
		||||
    /// multiple assets (eg for Multi-Asset), the return value indicates
 | 
			
		||||
    /// how many complete "baskets" of those assets may be spent by all of the corresponding
 | 
			
		||||
    /// AssetProxy contracts.
 | 
			
		||||
    /// @param ownerAddress Owner of the assets specified by assetData.
 | 
			
		||||
    /// @param assetData Details of asset, encoded per the AssetProxy contract specification.
 | 
			
		||||
    /// @return Number of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
 | 
			
		||||
    function getAssetProxyAllowance(address ownerAddress, bytes memory assetData)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 allowance)
 | 
			
		||||
    {
 | 
			
		||||
        // Get id of AssetProxy contract
 | 
			
		||||
        bytes4 assetProxyId = assetData.readBytes4(0);
 | 
			
		||||
 | 
			
		||||
        if (assetProxyId == MULTI_ASSET_PROXY_ID) {
 | 
			
		||||
            // Get array of values and array of assetDatas
 | 
			
		||||
            (, uint256[] memory amounts, bytes[] memory nestedAssetData) = decodeMultiAssetData(assetData);
 | 
			
		||||
 | 
			
		||||
            uint256 length = nestedAssetData.length;
 | 
			
		||||
            for (uint256 i = 0; i != length; i++) {
 | 
			
		||||
                // Query allowance of individual assetData
 | 
			
		||||
                uint256 totalAllowance = getAssetProxyAllowance(ownerAddress, nestedAssetData[i]);
 | 
			
		||||
 | 
			
		||||
                // Scale total allowance down by corresponding value in assetData
 | 
			
		||||
                uint256 scaledAllowance = totalAllowance / amounts[i];
 | 
			
		||||
                if (scaledAllowance < allowance || allowance == 0) {
 | 
			
		||||
                    allowance = scaledAllowance;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return allowance;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (assetProxyId == ERC20_PROXY_ID) {
 | 
			
		||||
            // Get ERC20 token address
 | 
			
		||||
            address tokenAddress = assetData.readAddress(16);
 | 
			
		||||
 | 
			
		||||
            // Encode data for `allowance(ownerAddress, _ERC20_PROXY_ADDRESS)`
 | 
			
		||||
            bytes memory allowanceData = abi.encodeWithSelector(
 | 
			
		||||
                _ERC20_ALLOWANCE_SELECTOR,
 | 
			
		||||
                ownerAddress,
 | 
			
		||||
                _ERC20_PROXY_ADDRESS
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // Query allowance
 | 
			
		||||
            (bool success, bytes memory returnData) = tokenAddress.staticcall(allowanceData);
 | 
			
		||||
            allowance = success && returnData.length == 32 ? returnData.readUint256(0) : 0;
 | 
			
		||||
        } else if (assetProxyId == ERC721_PROXY_ID) {
 | 
			
		||||
            // Get ERC721 token address and id
 | 
			
		||||
            (, address tokenAddress, uint256 tokenId) = decodeERC721AssetData(assetData);
 | 
			
		||||
 | 
			
		||||
            // Encode data for `isApprovedForAll(ownerAddress, _ERC721_PROXY_ADDRESS)`
 | 
			
		||||
            bytes memory isApprovedForAllData = abi.encodeWithSelector(
 | 
			
		||||
                _ERC721_IS_APPROVED_FOR_ALL_SELECTOR,
 | 
			
		||||
                ownerAddress,
 | 
			
		||||
                _ERC721_PROXY_ADDRESS
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            (bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
 | 
			
		||||
 | 
			
		||||
            // If not approved for all, call `getApproved(tokenId)`
 | 
			
		||||
            if (!success || returnData.length != 32 || returnData.readUint256(0) != 1) {
 | 
			
		||||
                // Encode data for `getApproved(tokenId)`
 | 
			
		||||
                bytes memory getApprovedData = abi.encodeWithSelector(_ERC721_GET_APPROVED_SELECTOR, tokenId);
 | 
			
		||||
                (success, returnData) = tokenAddress.staticcall(getApprovedData);
 | 
			
		||||
 | 
			
		||||
                // Allowance is 1 if successful and the approved address is the ERC721Proxy
 | 
			
		||||
                allowance = success && returnData.length == 32 && returnData.readAddress(12) == _ERC721_PROXY_ADDRESS ? 1 : 0;
 | 
			
		||||
            } else {
 | 
			
		||||
                // Allowance is 2^256 - 1 if `isApprovedForAll` returned true
 | 
			
		||||
                allowance = _MAX_UINT256;
 | 
			
		||||
            }
 | 
			
		||||
        } else if (assetProxyId == ERC1155_PROXY_ID) {
 | 
			
		||||
            // Get ERC1155 token address
 | 
			
		||||
            (, address tokenAddress, , , ) = decodeERC1155AssetData(assetData);
 | 
			
		||||
 | 
			
		||||
            // Encode data for `isApprovedForAll(ownerAddress, _ERC1155_PROXY_ADDRESS)`
 | 
			
		||||
            bytes memory isApprovedForAllData = abi.encodeWithSelector(
 | 
			
		||||
                _ERC1155_IS_APPROVED_FOR_ALL_SELECTOR,
 | 
			
		||||
                ownerAddress,
 | 
			
		||||
                _ERC1155_PROXY_ADDRESS
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // Query allowance
 | 
			
		||||
            (bool success, bytes memory returnData) = tokenAddress.staticcall(isApprovedForAllData);
 | 
			
		||||
            allowance = success && returnData.length == 32 && returnData.readUint256(0) == 1 ? _MAX_UINT256 : 0;
 | 
			
		||||
        } else if (assetProxyId == STATIC_CALL_PROXY_ID) {
 | 
			
		||||
            // The StaticCallProxy does not require any approvals
 | 
			
		||||
            allowance = _MAX_UINT256;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Allowance will be 0 if the assetProxyId is unknown
 | 
			
		||||
        return allowance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls getAssetProxyAllowance() for each element of assetData.
 | 
			
		||||
    /// @param ownerAddress Owner of the assets specified by assetData.
 | 
			
		||||
    /// @param assetData Array of asset details, each encoded per the AssetProxy contract specification.
 | 
			
		||||
    /// @return An array of asset allowances from getAllowance(), with each
 | 
			
		||||
    /// element corresponding to the same-indexed element in the assetData input.
 | 
			
		||||
    function getBatchAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory allowances)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 length = assetData.length;
 | 
			
		||||
        allowances = new uint256[](length);
 | 
			
		||||
        for (uint256 i = 0; i != length; i++) {
 | 
			
		||||
            allowances[i] = getAssetProxyAllowance(ownerAddress, assetData[i]);
 | 
			
		||||
        }
 | 
			
		||||
        return allowances;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls getBalance() and getAllowance() for assetData.
 | 
			
		||||
    /// @param ownerAddress Owner of the assets specified by assetData.
 | 
			
		||||
    /// @param assetData Details of asset, encoded per the AssetProxy contract specification.
 | 
			
		||||
    /// @return Number of assets (or asset baskets) held by owner, and number
 | 
			
		||||
    /// of assets (or asset baskets) that the corresponding AssetProxy is authorized to spend.
 | 
			
		||||
    function getBalanceAndAssetProxyAllowance(address ownerAddress, bytes memory assetData)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 balance, uint256 allowance)
 | 
			
		||||
    {
 | 
			
		||||
        balance = getBalance(ownerAddress, assetData);
 | 
			
		||||
        allowance = getAssetProxyAllowance(ownerAddress, assetData);
 | 
			
		||||
        return (balance, allowance);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls getBatchBalances() and getBatchAllowances() for each element of assetData.
 | 
			
		||||
    /// @param ownerAddress Owner of the assets specified by assetData.
 | 
			
		||||
    /// @param assetData Array of asset details, each encoded per the AssetProxy contract specification.
 | 
			
		||||
    /// @return An array of asset balances from getBalance(), and an array of
 | 
			
		||||
    /// asset allowances from getAllowance(), with each element
 | 
			
		||||
    /// corresponding to the same-indexed element in the assetData input.
 | 
			
		||||
    function getBatchBalancesAndAssetProxyAllowances(address ownerAddress, bytes[] memory assetData)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256[] memory balances, uint256[] memory allowances)
 | 
			
		||||
    {
 | 
			
		||||
        balances = getBatchBalances(ownerAddress, assetData);
 | 
			
		||||
        allowances = getBatchAssetProxyAllowances(ownerAddress, assetData);
 | 
			
		||||
        return (balances, allowances);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Encode ERC-20 asset data into the format described in the AssetProxy contract specification.
 | 
			
		||||
    /// @param tokenAddress The address of the ERC-20 contract hosting the asset to be traded.
 | 
			
		||||
    /// @return AssetProxy-compliant data describing the asset.
 | 
			
		||||
    function encodeERC20AssetData(address tokenAddress)
 | 
			
		||||
        public
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes memory assetData)
 | 
			
		||||
    {
 | 
			
		||||
        assetData = abi.encodeWithSelector(ERC20_PROXY_ID, tokenAddress);
 | 
			
		||||
        return assetData;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Decode ERC-20 asset data from the format described in the AssetProxy contract specification.
 | 
			
		||||
    /// @param assetData AssetProxy-compliant asset data describing an ERC-20 asset.
 | 
			
		||||
    /// @return The ERC-20 AssetProxy identifier, and the address of the ERC-20 
 | 
			
		||||
    /// contract hosting this asset.
 | 
			
		||||
    function decodeERC20AssetData(bytes memory assetData)
 | 
			
		||||
        public
 | 
			
		||||
        pure
 | 
			
		||||
        returns (
 | 
			
		||||
            bytes4 assetProxyId,
 | 
			
		||||
            address tokenAddress
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        assetProxyId = assetData.readBytes4(0);
 | 
			
		||||
 | 
			
		||||
        require(
 | 
			
		||||
            assetProxyId == ERC20_PROXY_ID,
 | 
			
		||||
            "WRONG_PROXY_ID"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        tokenAddress = assetData.readAddress(16);
 | 
			
		||||
        return (assetProxyId, tokenAddress);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Encode ERC-721 asset data into the format described in the AssetProxy specification.
 | 
			
		||||
    /// @param tokenAddress The address of the ERC-721 contract hosting the asset to be traded.
 | 
			
		||||
    /// @param tokenId The identifier of the specific asset to be traded.
 | 
			
		||||
    /// @return AssetProxy-compliant asset data describing the asset.
 | 
			
		||||
    function encodeERC721AssetData(address tokenAddress, uint256 tokenId)
 | 
			
		||||
        public
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes memory assetData)
 | 
			
		||||
    {
 | 
			
		||||
        assetData = abi.encodeWithSelector(
 | 
			
		||||
            ERC721_PROXY_ID,
 | 
			
		||||
            tokenAddress,
 | 
			
		||||
            tokenId
 | 
			
		||||
        );
 | 
			
		||||
        return assetData;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Decode ERC-721 asset data from the format described in the AssetProxy contract specification.
 | 
			
		||||
    /// @param assetData AssetProxy-compliant asset data describing an ERC-721 asset.
 | 
			
		||||
    /// @return The ERC-721 AssetProxy identifier, the address of the ERC-721
 | 
			
		||||
    /// contract hosting this asset, and the identifier of the specific
 | 
			
		||||
    /// asset to be traded.
 | 
			
		||||
    function decodeERC721AssetData(bytes memory assetData)
 | 
			
		||||
        public
 | 
			
		||||
        pure
 | 
			
		||||
        returns (
 | 
			
		||||
            bytes4 assetProxyId,
 | 
			
		||||
            address tokenAddress,
 | 
			
		||||
            uint256 tokenId
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        assetProxyId = assetData.readBytes4(0);
 | 
			
		||||
 | 
			
		||||
        require(
 | 
			
		||||
            assetProxyId == ERC721_PROXY_ID,
 | 
			
		||||
            "WRONG_PROXY_ID"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        tokenAddress = assetData.readAddress(16);
 | 
			
		||||
        tokenId = assetData.readUint256(36);
 | 
			
		||||
        return (assetProxyId, tokenAddress, tokenId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Encode ERC-1155 asset data into the format described in the AssetProxy contract specification.
 | 
			
		||||
    /// @param tokenAddress The address of the ERC-1155 contract hosting the asset(s) to be traded.
 | 
			
		||||
    /// @param tokenIds The identifiers of the specific assets to be traded.
 | 
			
		||||
    /// @param tokenValues The amounts of each asset to be traded.
 | 
			
		||||
    /// @param callbackData Data to be passed to receiving contracts when a transfer is performed.
 | 
			
		||||
    /// @return AssetProxy-compliant asset data describing the set of assets.
 | 
			
		||||
    function encodeERC1155AssetData(
 | 
			
		||||
        address tokenAddress,
 | 
			
		||||
        uint256[] memory tokenIds,
 | 
			
		||||
        uint256[] memory tokenValues,
 | 
			
		||||
        bytes memory callbackData
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes memory assetData)
 | 
			
		||||
    {
 | 
			
		||||
        assetData = abi.encodeWithSelector(
 | 
			
		||||
            ERC1155_PROXY_ID,
 | 
			
		||||
            tokenAddress,
 | 
			
		||||
            tokenIds,
 | 
			
		||||
            tokenValues,
 | 
			
		||||
            callbackData
 | 
			
		||||
        );
 | 
			
		||||
        return assetData;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Decode ERC-1155 asset data from the format described in the AssetProxy contract specification.
 | 
			
		||||
    /// @param assetData AssetProxy-compliant asset data describing an ERC-1155 set of assets.
 | 
			
		||||
    /// @return The ERC-1155 AssetProxy identifier, the address of the ERC-1155
 | 
			
		||||
    /// contract hosting the assets, an array of the identifiers of the
 | 
			
		||||
    /// assets to be traded, an array of asset amounts to be traded, and
 | 
			
		||||
    /// callback data.  Each element of the arrays corresponds to the
 | 
			
		||||
    /// same-indexed element of the other array.  Return values specified as
 | 
			
		||||
    /// `memory` are returned as pointers to locations within the memory of
 | 
			
		||||
    /// the input parameter `assetData`.
 | 
			
		||||
    function decodeERC1155AssetData(bytes memory assetData)
 | 
			
		||||
        public
 | 
			
		||||
        pure
 | 
			
		||||
        returns (
 | 
			
		||||
            bytes4 assetProxyId,
 | 
			
		||||
            address tokenAddress,
 | 
			
		||||
            uint256[] memory tokenIds,
 | 
			
		||||
            uint256[] memory tokenValues,
 | 
			
		||||
            bytes memory callbackData
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        assetProxyId = assetData.readBytes4(0);
 | 
			
		||||
 | 
			
		||||
        require(
 | 
			
		||||
            assetProxyId == ERC1155_PROXY_ID,
 | 
			
		||||
            "WRONG_PROXY_ID"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        assembly {
 | 
			
		||||
            // Skip selector and length to get to the first parameter:
 | 
			
		||||
            assetData := add(assetData, 36)
 | 
			
		||||
            // Read the value of the first parameter:
 | 
			
		||||
            tokenAddress := mload(assetData)
 | 
			
		||||
            // Point to the next parameter's data:
 | 
			
		||||
            tokenIds := add(assetData, mload(add(assetData, 32)))
 | 
			
		||||
            // Point to the next parameter's data:
 | 
			
		||||
            tokenValues := add(assetData, mload(add(assetData, 64)))
 | 
			
		||||
            // Point to the next parameter's data:
 | 
			
		||||
            callbackData := add(assetData, mload(add(assetData, 96)))
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (
 | 
			
		||||
            assetProxyId,
 | 
			
		||||
            tokenAddress,
 | 
			
		||||
            tokenIds,
 | 
			
		||||
            tokenValues,
 | 
			
		||||
            callbackData
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Encode data for multiple assets, per the AssetProxy contract specification.
 | 
			
		||||
    /// @param amounts The amounts of each asset to be traded.
 | 
			
		||||
    /// @param nestedAssetData AssetProxy-compliant data describing each asset to be traded.
 | 
			
		||||
    /// @return AssetProxy-compliant data describing the set of assets.
 | 
			
		||||
    function encodeMultiAssetData(uint256[] memory amounts, bytes[] memory nestedAssetData)
 | 
			
		||||
        public
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes memory assetData)
 | 
			
		||||
    {
 | 
			
		||||
        assetData = abi.encodeWithSelector(
 | 
			
		||||
            MULTI_ASSET_PROXY_ID,
 | 
			
		||||
            amounts,
 | 
			
		||||
            nestedAssetData
 | 
			
		||||
        );
 | 
			
		||||
        return assetData;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Decode multi-asset data from the format described in the AssetProxy contract specification.
 | 
			
		||||
    /// @param assetData AssetProxy-compliant data describing a multi-asset basket.
 | 
			
		||||
    /// @return The Multi-Asset AssetProxy identifier, an array of the amounts
 | 
			
		||||
    /// of the assets to be traded, and an array of the
 | 
			
		||||
    /// AssetProxy-compliant data describing each asset to be traded.  Each
 | 
			
		||||
    /// element of the arrays corresponds to the same-indexed element of the other array.
 | 
			
		||||
    function decodeMultiAssetData(bytes memory assetData)
 | 
			
		||||
        public
 | 
			
		||||
        pure
 | 
			
		||||
        returns (
 | 
			
		||||
            bytes4 assetProxyId,
 | 
			
		||||
            uint256[] memory amounts,
 | 
			
		||||
            bytes[] memory nestedAssetData
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        assetProxyId = assetData.readBytes4(0);
 | 
			
		||||
 | 
			
		||||
        require(
 | 
			
		||||
            assetProxyId == MULTI_ASSET_PROXY_ID,
 | 
			
		||||
            "WRONG_PROXY_ID"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // solhint-disable indent
 | 
			
		||||
        (amounts, nestedAssetData) = abi.decode(
 | 
			
		||||
            assetData.slice(4, assetData.length),
 | 
			
		||||
            (uint256[], bytes[])
 | 
			
		||||
        );
 | 
			
		||||
        // solhint-enable indent
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls `asset.ownerOf(tokenId)`, but returns a null owner instead of reverting on an unowned asset.
 | 
			
		||||
    /// @param tokenAddress Address of ERC721 asset.
 | 
			
		||||
    /// @param tokenId The identifier for the specific NFT.
 | 
			
		||||
    /// @return Owner of tokenId or null address if unowned.
 | 
			
		||||
    function getERC721TokenOwner(address tokenAddress, uint256 tokenId)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (address ownerAddress)
 | 
			
		||||
    {
 | 
			
		||||
        bytes memory ownerOfCalldata = abi.encodeWithSelector(
 | 
			
		||||
            _ERC721_OWNER_OF_SELECTOR,
 | 
			
		||||
            tokenId
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        (bool success, bytes memory returnData) = tokenAddress.staticcall(ownerOfCalldata);
 | 
			
		||||
 | 
			
		||||
        ownerAddress = (success && returnData.length == 32) ? returnData.readAddress(12) : address(0);
 | 
			
		||||
        return ownerAddress;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										193
									
								
								contracts/dev-utils/contracts/src/LibTransactionDecoder.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								contracts/dev-utils/contracts/src/LibTransactionDecoder.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,193 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2019 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.5;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/LibExchangeSelectors.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/LibOrder.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract LibTransactionDecoder is
 | 
			
		||||
    LibExchangeSelectors
 | 
			
		||||
{
 | 
			
		||||
    using LibBytes for bytes;
 | 
			
		||||
 | 
			
		||||
    /// @dev Decodes the call data for an Exchange contract method call.
 | 
			
		||||
    /// @param transactionData ABI-encoded calldata for an Exchange
 | 
			
		||||
    ///     contract method call.
 | 
			
		||||
    /// @return The name of the function called, and the parameters it was
 | 
			
		||||
    ///     given.  For single-order fills and cancels, the arrays will have
 | 
			
		||||
    ///     just one element.
 | 
			
		||||
    function decodeZeroExTransactionData(bytes memory transactionData)
 | 
			
		||||
        public
 | 
			
		||||
        pure
 | 
			
		||||
        returns(
 | 
			
		||||
            string memory functionName,
 | 
			
		||||
            LibOrder.Order[] memory orders,
 | 
			
		||||
            uint256[] memory takerAssetFillAmounts,
 | 
			
		||||
            bytes[] memory signatures
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        bytes4 functionSelector = transactionData.readBytes4(0);
 | 
			
		||||
 | 
			
		||||
        if (functionSelector == BATCH_CANCEL_ORDERS_SELECTOR) {
 | 
			
		||||
            functionName = "batchCancelOrders";
 | 
			
		||||
        } else if (functionSelector == BATCH_FILL_ORDERS_SELECTOR) {
 | 
			
		||||
            functionName = "batchFillOrders";
 | 
			
		||||
        } else if (functionSelector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR) {
 | 
			
		||||
            functionName = "batchFillOrdersNoThrow";
 | 
			
		||||
        } else if (functionSelector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR) {
 | 
			
		||||
            functionName = "batchFillOrKillOrders";
 | 
			
		||||
        } else if (functionSelector == CANCEL_ORDER_SELECTOR) {
 | 
			
		||||
            functionName = "cancelOrder";
 | 
			
		||||
        } else if (functionSelector == FILL_ORDER_SELECTOR) {
 | 
			
		||||
            functionName = "fillOrder";
 | 
			
		||||
        } else if (functionSelector == FILL_ORDER_NO_THROW_SELECTOR) {
 | 
			
		||||
            functionName = "fillOrderNoThrow";
 | 
			
		||||
        } else if (functionSelector == FILL_OR_KILL_ORDER_SELECTOR) {
 | 
			
		||||
            functionName = "fillOrKillOrder";
 | 
			
		||||
        } else if (functionSelector == MARKET_BUY_ORDERS_SELECTOR) {
 | 
			
		||||
            functionName = "marketBuyOrders";
 | 
			
		||||
        } else if (functionSelector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR) {
 | 
			
		||||
            functionName = "marketBuyOrdersNoThrow";
 | 
			
		||||
        } else if (functionSelector == MARKET_SELL_ORDERS_SELECTOR) {
 | 
			
		||||
            functionName = "marketSellOrders";
 | 
			
		||||
        } else if (functionSelector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR) {
 | 
			
		||||
            functionName = "marketSellOrdersNoThrow";
 | 
			
		||||
        } else if (functionSelector == MATCH_ORDERS_SELECTOR) {
 | 
			
		||||
            functionName = "matchOrders";
 | 
			
		||||
        } else if (
 | 
			
		||||
            functionSelector == CANCEL_ORDERS_UP_TO_SELECTOR ||
 | 
			
		||||
            functionSelector == EXECUTE_TRANSACTION_SELECTOR
 | 
			
		||||
            // TODO: add new noThrow cancel functions when https://github.com/0xProject/ZEIPs/issues/35 is merged.
 | 
			
		||||
        ) {
 | 
			
		||||
            revert("UNIMPLEMENTED");
 | 
			
		||||
        } else {
 | 
			
		||||
            revert("UNKNOWN_FUNCTION_SELECTOR");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (functionSelector == BATCH_CANCEL_ORDERS_SELECTOR) {
 | 
			
		||||
            // solhint-disable-next-line indent
 | 
			
		||||
            orders = abi.decode(transactionData.slice(4, transactionData.length), (LibOrder.Order[]));
 | 
			
		||||
            takerAssetFillAmounts = new uint256[](0);
 | 
			
		||||
            signatures = new bytes[](0);
 | 
			
		||||
        } else if (
 | 
			
		||||
            functionSelector == BATCH_FILL_OR_KILL_ORDERS_SELECTOR ||
 | 
			
		||||
            functionSelector == BATCH_FILL_ORDERS_NO_THROW_SELECTOR ||
 | 
			
		||||
            functionSelector == BATCH_FILL_ORDERS_SELECTOR
 | 
			
		||||
        ) {
 | 
			
		||||
            (orders, takerAssetFillAmounts, signatures) = _makeReturnValuesForBatchFill(transactionData);
 | 
			
		||||
        } else if (functionSelector == CANCEL_ORDER_SELECTOR) {
 | 
			
		||||
            orders = new LibOrder.Order[](1);
 | 
			
		||||
            orders[0] = abi.decode(transactionData.slice(4, transactionData.length), (LibOrder.Order));
 | 
			
		||||
            takerAssetFillAmounts = new uint256[](0);
 | 
			
		||||
            signatures = new bytes[](0);
 | 
			
		||||
        } else if (
 | 
			
		||||
            functionSelector == FILL_OR_KILL_ORDER_SELECTOR ||
 | 
			
		||||
            functionSelector == FILL_ORDER_SELECTOR ||
 | 
			
		||||
            functionSelector == FILL_ORDER_NO_THROW_SELECTOR
 | 
			
		||||
        ) {
 | 
			
		||||
            (orders, takerAssetFillAmounts, signatures) = _makeReturnValuesForSingleOrderFill(transactionData);
 | 
			
		||||
        } else if (
 | 
			
		||||
            functionSelector == MARKET_BUY_ORDERS_SELECTOR ||
 | 
			
		||||
            functionSelector == MARKET_BUY_ORDERS_NO_THROW_SELECTOR ||
 | 
			
		||||
            functionSelector == MARKET_SELL_ORDERS_SELECTOR ||
 | 
			
		||||
            functionSelector == MARKET_SELL_ORDERS_NO_THROW_SELECTOR
 | 
			
		||||
        ) {
 | 
			
		||||
            (orders, takerAssetFillAmounts, signatures) = _makeReturnValuesForMarketFill(transactionData);
 | 
			
		||||
        } else if (functionSelector == MATCH_ORDERS_SELECTOR) {
 | 
			
		||||
            (
 | 
			
		||||
                LibOrder.Order memory leftOrder,
 | 
			
		||||
                LibOrder.Order memory rightOrder,
 | 
			
		||||
                bytes memory leftSignature,
 | 
			
		||||
                bytes memory rightSignature
 | 
			
		||||
            ) = abi.decode(
 | 
			
		||||
                transactionData.slice(4, transactionData.length),
 | 
			
		||||
                (LibOrder.Order, LibOrder.Order, bytes, bytes)
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            orders = new LibOrder.Order[](2);
 | 
			
		||||
            orders[0] = leftOrder;
 | 
			
		||||
            orders[1] = rightOrder;
 | 
			
		||||
 | 
			
		||||
            takerAssetFillAmounts = new uint256[](2);
 | 
			
		||||
            takerAssetFillAmounts[0] = leftOrder.takerAssetAmount;
 | 
			
		||||
            takerAssetFillAmounts[1] = rightOrder.takerAssetAmount;
 | 
			
		||||
 | 
			
		||||
            signatures = new bytes[](2);
 | 
			
		||||
            signatures[0] = leftSignature;
 | 
			
		||||
            signatures[1] = rightSignature;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _makeReturnValuesForSingleOrderFill(bytes memory transactionData)
 | 
			
		||||
        private
 | 
			
		||||
        pure
 | 
			
		||||
        returns(
 | 
			
		||||
            LibOrder.Order[] memory orders,
 | 
			
		||||
            uint256[] memory takerAssetFillAmounts,
 | 
			
		||||
            bytes[] memory signatures
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        orders = new LibOrder.Order[](1);
 | 
			
		||||
        takerAssetFillAmounts = new uint256[](1);
 | 
			
		||||
        signatures = new bytes[](1);
 | 
			
		||||
        // solhint-disable-next-line indent
 | 
			
		||||
        (orders[0], takerAssetFillAmounts[0], signatures[0]) = abi.decode(
 | 
			
		||||
            transactionData.slice(4, transactionData.length),
 | 
			
		||||
            (LibOrder.Order, uint256, bytes)
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _makeReturnValuesForBatchFill(bytes memory transactionData)
 | 
			
		||||
        private
 | 
			
		||||
        pure
 | 
			
		||||
        returns(
 | 
			
		||||
            LibOrder.Order[] memory orders,
 | 
			
		||||
            uint256[] memory takerAssetFillAmounts,
 | 
			
		||||
            bytes[] memory signatures
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        // solhint-disable-next-line indent
 | 
			
		||||
        (orders, takerAssetFillAmounts, signatures) = abi.decode(
 | 
			
		||||
            transactionData.slice(4, transactionData.length),
 | 
			
		||||
            // solhint-disable-next-line indent
 | 
			
		||||
            (LibOrder.Order[], uint256[], bytes[])
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _makeReturnValuesForMarketFill(bytes memory transactionData)
 | 
			
		||||
        private
 | 
			
		||||
        pure
 | 
			
		||||
        returns(
 | 
			
		||||
            LibOrder.Order[] memory orders,
 | 
			
		||||
            uint256[] memory takerAssetFillAmounts,
 | 
			
		||||
            bytes[] memory signatures
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        takerAssetFillAmounts = new uint256[](1);
 | 
			
		||||
        // solhint-disable-next-line indent
 | 
			
		||||
        (orders, takerAssetFillAmounts[0], signatures) = abi.decode(
 | 
			
		||||
            transactionData.slice(4, transactionData.length),
 | 
			
		||||
            // solhint-disable-next-line indent
 | 
			
		||||
            (LibOrder.Order[], uint256, bytes[])
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user