Compare commits
	
		
			95 Commits
		
	
	
		
			feat/mtx-f
			...
			protocol@4
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					4379e15a4d | ||
| 
						 | 
					b0c37606a8 | ||
| 
						 | 
					da8e43adfe | ||
| 
						 | 
					b483805a22 | ||
| 
						 | 
					ff104e7505 | ||
| 
						 | 
					8a2305c7b9 | ||
| 
						 | 
					d7bc0b79df | ||
| 
						 | 
					ad2d41fd90 | ||
| 
						 | 
					721b984bbc | ||
| 
						 | 
					72433ea5b7 | ||
| 
						 | 
					f919e8ef02 | ||
| 
						 | 
					dbcc7dd6f4 | ||
| 
						 | 
					33b7515734 | ||
| 
						 | 
					f96b944cce | ||
| 
						 | 
					0fbdc1dccd | ||
| 
						 | 
					484d9cafc4 | ||
| 
						 | 
					e73885c9a0 | ||
| 
						 | 
					948b17e2ed | ||
| 
						 | 
					2b13dcfc14 | ||
| 
						 | 
					d2bea4aa46 | ||
| 
						 | 
					dc926a05b3 | ||
| 
						 | 
					5cc53597de | ||
| 
						 | 
					57ca2c07bb | ||
| 
						 | 
					b0d2dee84d | ||
| 
						 | 
					1422ad756d | ||
| 
						 | 
					9d216f9c1c | ||
| 
						 | 
					ff74738178 | ||
| 
						 | 
					fe4fe48021 | ||
| 
						 | 
					356e74a645 | ||
| 
						 | 
					70590e3e56 | ||
| 
						 | 
					4e0b671bd8 | ||
| 
						 | 
					ea2ca700c3 | ||
| 
						 | 
					3574ea5b27 | ||
| 
						 | 
					b7bf5b5dfe | ||
| 
						 | 
					cfbb9c6f6c | ||
| 
						 | 
					7e40dd1826 | ||
| 
						 | 
					bcbfbfa16c | ||
| 
						 | 
					03fc744bbd | ||
| 
						 | 
					a23143d1eb | ||
| 
						 | 
					c0ef6fece3 | ||
| 
						 | 
					03ea4e3dba | ||
| 
						 | 
					3e939f7780 | ||
| 
						 | 
					d97dab83cd | ||
| 
						 | 
					f0a4f6aeca | ||
| 
						 | 
					f8a183812e | ||
| 
						 | 
					f6fd374590 | ||
| 
						 | 
					09763bcf5e | ||
| 
						 | 
					3ab12ed254 | ||
| 
						 | 
					25731653ef | ||
| 
						 | 
					ec82c42c1b | ||
| 
						 | 
					38665ffc86 | ||
| 
						 | 
					459fb3ee28 | ||
| 
						 | 
					dc8ff32d51 | ||
| 
						 | 
					9f30823d70 | ||
| 
						 | 
					f2f835591e | ||
| 
						 | 
					8c35931041 | ||
| 
						 | 
					a8539aa66e | ||
| 
						 | 
					4d7df00d5a | ||
| 
						 | 
					80193215e3 | ||
| 
						 | 
					c4b1f043c6 | ||
| 
						 | 
					a472125c65 | ||
| 
						 | 
					8666121bd9 | ||
| 
						 | 
					8cf1c8bbd2 | ||
| 
						 | 
					d2abe9ad97 | ||
| 
						 | 
					f8b65bd429 | ||
| 
						 | 
					3a7a5d22a2 | ||
| 
						 | 
					f87f5a40c0 | ||
| 
						 | 
					5571d1698d | ||
| 
						 | 
					6f7a7a7291 | ||
| 
						 | 
					b613de1547 | ||
| 
						 | 
					6fd269db34 | ||
| 
						 | 
					033db23929 | ||
| 
						 | 
					891d173705 | ||
| 
						 | 
					091a10676c | ||
| 
						 | 
					0ae6f3e64f | ||
| 
						 | 
					8197fee50a | ||
| 
						 | 
					ee48d4006b | ||
| 
						 | 
					d2be56c30f | ||
| 
						 | 
					c4097e4203 | ||
| 
						 | 
					8f21d167cc | ||
| 
						 | 
					b33fc27220 | ||
| 
						 | 
					dcb17768cc | ||
| 
						 | 
					82907f99a2 | ||
| 
						 | 
					2e157cc307 | ||
| 
						 | 
					3164d7882c | ||
| 
						 | 
					91587efe2e | ||
| 
						 | 
					008f00ba2f | ||
| 
						 | 
					0e38b0e54a | ||
| 
						 | 
					f6af4abd67 | ||
| 
						 | 
					6dc3084c30 | ||
| 
						 | 
					fd1f7a8a42 | ||
| 
						 | 
					3a03174a92 | ||
| 
						 | 
					f5e34bce3b | ||
| 
						 | 
					3f8dbf3fe9 | ||
| 
						 | 
					b040e55202 | 
@@ -1,339 +0,0 @@
 | 
			
		||||
version: 2.1
 | 
			
		||||
 | 
			
		||||
parameters:
 | 
			
		||||
    cache_version:
 | 
			
		||||
        type: string
 | 
			
		||||
        default: v5
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
    build:
 | 
			
		||||
        resource_class: xlarge
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
        environment:
 | 
			
		||||
            NODE_OPTIONS: '--max-old-space-size=16384'
 | 
			
		||||
        steps:
 | 
			
		||||
            - checkout
 | 
			
		||||
            - run: git submodule update --init --recursive
 | 
			
		||||
            - run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - lib-{{ .Environment.CIRCLE_SHA1 }}-feat/NerveMixinArbitrum
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - run:
 | 
			
		||||
                  name: install-yarn
 | 
			
		||||
                  command: npm install --force --global yarn@1.22.0
 | 
			
		||||
            - run:
 | 
			
		||||
                  name: yarn
 | 
			
		||||
                  command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install
 | 
			
		||||
            - setup_remote_docker
 | 
			
		||||
            - run: yarn build:ci
 | 
			
		||||
            - save_cache:
 | 
			
		||||
                  key: cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
                  paths:
 | 
			
		||||
                      - ~/project/node_modules
 | 
			
		||||
                      - ~/.cache/yarn
 | 
			
		||||
            - save_cache:
 | 
			
		||||
                  key: lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
                  paths:
 | 
			
		||||
                      - ~/project/contracts/erc20/generated-artifacts/
 | 
			
		||||
                      - ~/project/contracts/erc20/generated-wrappers/
 | 
			
		||||
                      - ~/project/contracts/erc20/lib/
 | 
			
		||||
                      - ~/project/contracts/erc20/node_modules
 | 
			
		||||
                      - ~/project/contracts/erc20/test/generated-artifacts/
 | 
			
		||||
                      - ~/project/contracts/erc20/test/generated-wrappers/
 | 
			
		||||
                      - ~/project/contracts/test-utils/lib/
 | 
			
		||||
                      - ~/project/contracts/test-utils/node_modules
 | 
			
		||||
                      - ~/project/contracts/treasury/generated-artifacts/
 | 
			
		||||
                      - ~/project/contracts/treasury/generated-wrappers/
 | 
			
		||||
                      - ~/project/contracts/treasury/lib/
 | 
			
		||||
                      - ~/project/contracts/treasury/node_modules
 | 
			
		||||
                      - ~/project/contracts/treasury/test/generated-artifacts/
 | 
			
		||||
                      - ~/project/contracts/treasury/test/generated-wrappers/
 | 
			
		||||
                      - ~/project/contracts/utils/generated-artifacts/
 | 
			
		||||
                      - ~/project/contracts/utils/generated-wrappers/
 | 
			
		||||
                      - ~/project/contracts/utils/lib/
 | 
			
		||||
                      - ~/project/contracts/utils/node_modules
 | 
			
		||||
                      - ~/project/contracts/utils/test/generated-artifacts/
 | 
			
		||||
                      - ~/project/contracts/utils/test/generated-wrappers/
 | 
			
		||||
                      - ~/project/contracts/zero-ex/generated-artifacts/
 | 
			
		||||
                      - ~/project/contracts/zero-ex/generated-wrappers/
 | 
			
		||||
                      - ~/project/contracts/zero-ex/lib/
 | 
			
		||||
                      - ~/project/contracts/zero-ex/node_modules
 | 
			
		||||
                      - ~/project/contracts/zero-ex/test/generated-artifacts/
 | 
			
		||||
                      - ~/project/contracts/zero-ex/test/generated-wrappers/
 | 
			
		||||
                      - ~/project/packages/asset-swapper/node_modules
 | 
			
		||||
                      - ~/project/packages/contract-addresses/lib/
 | 
			
		||||
                      - ~/project/packages/contract-addresses/node_modules
 | 
			
		||||
                      - ~/project/packages/contract-artifacts/lib/
 | 
			
		||||
                      - ~/project/packages/contract-artifacts/node_modules
 | 
			
		||||
                      - ~/project/packages/contract-wrappers/lib/
 | 
			
		||||
                      - ~/project/packages/contract-wrappers/node_modules
 | 
			
		||||
                      - ~/project/packages/protocol-utils/lib/
 | 
			
		||||
                      - ~/project/packages/protocol-utils/node_modules
 | 
			
		||||
            - store_artifacts:
 | 
			
		||||
                  path: ~/repo/packages/abi-gen/test-cli/output
 | 
			
		||||
            - store_artifacts:
 | 
			
		||||
                  path: ~/repo/packages/contract-wrappers/generated_docs
 | 
			
		||||
    test-exchange-ganache:
 | 
			
		||||
        resource_class: xlarge
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
        steps:
 | 
			
		||||
            - checkout
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - run: yarn wsrun -p @0x/contracts-exchange -m --serial -c test:circleci
 | 
			
		||||
    test-integrations-ganache:
 | 
			
		||||
        resource_class: xlarge
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
        steps:
 | 
			
		||||
            - checkout
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - run: yarn wsrun -p @0x/contracts-integrations -m --serial -c test:circleci
 | 
			
		||||
    test-contracts-staking-ganache:
 | 
			
		||||
        resource_class: xlarge
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
        steps:
 | 
			
		||||
            - checkout
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
                      - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - run: yarn wsrun -p @0x/contracts-staking -m --serial -c test:circleci
 | 
			
		||||
    test-contracts-extra-ganache:
 | 
			
		||||
        resource_class: xlarge
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
        steps:
 | 
			
		||||
            - checkout
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - cache-{{ checksum "yarn.lock" }}
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - run: yarn wsrun -p @0x/contracts-exchange-forwarder -p @0x/contracts-coordinator -m --serial -c test:circleci
 | 
			
		||||
    test-contracts-rest-ganache:
 | 
			
		||||
        resource_class: xlarge
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
        steps:
 | 
			
		||||
            - checkout
 | 
			
		||||
            - run: |
 | 
			
		||||
                  git diff --name-only development >> changed.txt
 | 
			
		||||
                  if ! grep -q \.sol changed.txt; then
 | 
			
		||||
                    circleci-agent step halt
 | 
			
		||||
                  fi
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - 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
 | 
			
		||||
    test-foundry:
 | 
			
		||||
        resource_class: xlarge
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: ghcr.io/foundry-rs/foundry:latest
 | 
			
		||||
        steps:
 | 
			
		||||
            - checkout
 | 
			
		||||
            - run: |
 | 
			
		||||
                  git diff --name-only development >> changed.txt
 | 
			
		||||
                  cat changed.txt
 | 
			
		||||
                  if ! grep -q \.sol changed.txt; then
 | 
			
		||||
                    circleci-agent step halt
 | 
			
		||||
                  fi
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - run: git submodule update --init --recursive
 | 
			
		||||
            - run:
 | 
			
		||||
                  command: forge test
 | 
			
		||||
                  working_directory: ~/project/contracts/zero-ex
 | 
			
		||||
    test-publish:
 | 
			
		||||
        resource_class: large
 | 
			
		||||
        environment:
 | 
			
		||||
            NODE_OPTIONS: '--max-old-space-size=6442'
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
            - image: 0xorg/verdaccio
 | 
			
		||||
        steps:
 | 
			
		||||
            - checkout
 | 
			
		||||
            - run: |
 | 
			
		||||
                  git diff --name-only development >> changed.txt
 | 
			
		||||
                  cat changed.txt
 | 
			
		||||
                  if ! grep -q packages/ changed.txt; then
 | 
			
		||||
                    circleci-agent step halt
 | 
			
		||||
                  fi
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - run:
 | 
			
		||||
                  command: yarn test:publish:circleci
 | 
			
		||||
                  no_output_timeout: 1800
 | 
			
		||||
            - store_artifacts:
 | 
			
		||||
                  path: ~/.npm/_logs
 | 
			
		||||
    test-doc-generation:
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
        steps:
 | 
			
		||||
            - checkout
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - run:
 | 
			
		||||
                  command: yarn test:generate_docs:circleci
 | 
			
		||||
                  no_output_timeout: 1200
 | 
			
		||||
    test-rest:
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
        environment:
 | 
			
		||||
            RUST_ROUTER: 'true'
 | 
			
		||||
        steps:
 | 
			
		||||
            - checkout
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - run: yarn wsrun -p @0x/contracts-test-utils -m --serial -c test:circleci
 | 
			
		||||
            - run: yarn wsrun -p @0x/contract-addresses -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
 | 
			
		||||
            - save_cache:
 | 
			
		||||
                  key: coverage-contract-wrappers-test-{{ checksum "yarn.lock" }}
 | 
			
		||||
                  paths:
 | 
			
		||||
                      - ~/repo/packages/contract-wrappers-test/coverage/lcov.info
 | 
			
		||||
            - save_cache:
 | 
			
		||||
                  key: coverage-order-utils-{{ checksum "yarn.lock" }}
 | 
			
		||||
                  paths:
 | 
			
		||||
                      - ~/repo/packages/order-utils/coverage/lcov.info
 | 
			
		||||
            - save_cache:
 | 
			
		||||
                  key: coverage-web3-wrapper-{{ checksum "yarn.lock" }}
 | 
			
		||||
                  paths:
 | 
			
		||||
                      - ~/repo/packages/web3-wrapper/coverage/lcov.info
 | 
			
		||||
    static-tests:
 | 
			
		||||
        resource_class: large
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
        steps:
 | 
			
		||||
            - checkout
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - run:
 | 
			
		||||
                  command: yarn lerna run lint
 | 
			
		||||
            - run:
 | 
			
		||||
                  command: yarn prettier:ci
 | 
			
		||||
            - run:
 | 
			
		||||
                  command: yarn deps_versions:ci
 | 
			
		||||
            - run:
 | 
			
		||||
                  command: yarn diff_md_docs:ci
 | 
			
		||||
            - run:
 | 
			
		||||
                  command: yarn test:links
 | 
			
		||||
    submit-coverage:
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
        steps:
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - coverage-contract-wrappers-test-{{ checksum "yarn.lock" }}
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - coverage-order-utils-{{ checksum "yarn.lock" }}
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - coverage-contracts-{{ checksum "yarn.lock" }}
 | 
			
		||||
            - 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-foundry:
 | 
			
		||||
                  requires:
 | 
			
		||||
                      - build
 | 
			
		||||
            - test-contracts-rest-ganache:
 | 
			
		||||
                  requires:
 | 
			
		||||
                      - build
 | 
			
		||||
            - test-rest:
 | 
			
		||||
                  requires:
 | 
			
		||||
                      - build
 | 
			
		||||
            - static-tests:
 | 
			
		||||
                  requires:
 | 
			
		||||
                      - build
 | 
			
		||||
            - test-publish:
 | 
			
		||||
                  requires:
 | 
			
		||||
                      - build
 | 
			
		||||
            - 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
 | 
			
		||||
							
								
								
									
										2
									
								
								CODEOWNERS → .github/CODEOWNERS
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								CODEOWNERS → .github/CODEOWNERS
									
									
									
									
										vendored
									
									
								
							@@ -8,7 +8,7 @@
 | 
			
		||||
 | 
			
		||||
# Dev tools & setup
 | 
			
		||||
 | 
			
		||||
.circleci/ @dekz
 | 
			
		||||
.github/ @dekz
 | 
			
		||||
packages/contract-addresses/ @dekz @dextracker @kyu-c
 | 
			
		||||
packages/contract-artifacts/ @dekz
 | 
			
		||||
packages/protocol-utils/ @dekz
 | 
			
		||||
							
								
								
									
										12
									
								
								CONTRIBUTING.md → .github/CONTRIBUTING.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								CONTRIBUTING.md → .github/CONTRIBUTING.md
									
									
									
									
										vendored
									
									
								
							@@ -89,15 +89,3 @@ A few of our coding conventions are not yet enforced by the linter/auto-formatte
 | 
			
		||||
1.  If you _must_ cast a variable to any - try to type it back as fast as possible. (e.g., `const cw = ((zeroEx as any)._contractWrappers as ContractWrappers);`). This ensures subsequent code is type-safe.
 | 
			
		||||
1.  Our enum conventions coincide with the recommended TypeScript conventions, using capitalized keys, and all-caps snake-case values. Eg `GetStats = 'GET_STATS'`
 | 
			
		||||
1.  All public, exported methods/functions/classes must have associated Javadoc-style comments.
 | 
			
		||||
 | 
			
		||||
### Fix `submit-coverage` CI failure
 | 
			
		||||
 | 
			
		||||
If you simply fork the repo and then create a PR from it, your PR will fail the `submit-coverage` check on CI. This is because the 0x CircleCI configuration sets the `COVERALLS_REPO_TOKEN` environment variable to the token for `0xProject/0x-tools`, but when running the check against your fork the token needs to match your repo's name `your-username/0x-tools`.
 | 
			
		||||
 | 
			
		||||
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.)
 | 
			
		||||
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.
 | 
			
		||||
							
								
								
									
										12
									
								
								ISSUE_TEMPLATE.md → .github/ISSUE_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								ISSUE_TEMPLATE.md → .github/ISSUE_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							@@ -2,15 +2,13 @@
 | 
			
		||||
 | 
			
		||||
<!--- Before submitting please check to see if this issue was already reported -->
 | 
			
		||||
 | 
			
		||||
<!--- Prefix your issue title with the package name it relates to (e.g., `0x.js: ` or `general:`) -->
 | 
			
		||||
 | 
			
		||||
## Expected Behavior
 | 
			
		||||
 | 
			
		||||
<!--- If you're describing a bug, tell us what should happen -->
 | 
			
		||||
 | 
			
		||||
<!--- If you're suggesting a package change/improvement, tell us how it should work -->
 | 
			
		||||
 | 
			
		||||
<!--- If you're suggesting a contract or protocol change/improvement, visit our ZEIPs repo -->
 | 
			
		||||
<!--- If you're suggesting a contract or protocol change/improvement, visit our ZEIPs repo https://github.com/0xProject/ZEIPs -->
 | 
			
		||||
 | 
			
		||||
## Current Behavior
 | 
			
		||||
 | 
			
		||||
@@ -50,8 +48,8 @@
 | 
			
		||||
| ------: | :------ |
 | 
			
		||||
 | 
			
		||||
<!-- For example:
 | 
			
		||||
|             `0x.js` | 2.0.4   |
 | 
			
		||||
| `Exchange Contract` | v2      |
 | 
			
		||||
|    `protocol-utils` | 2.0.4   |
 | 
			
		||||
| `Exchange Contract` | v3      |
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
| Network |
 | 
			
		||||
@@ -60,6 +58,6 @@
 | 
			
		||||
 | 
			
		||||
<!-- For example:
 | 
			
		||||
| mainnet |
 | 
			
		||||
| kovan |
 | 
			
		||||
| testrpc |
 | 
			
		||||
| goerli |
 | 
			
		||||
| development |
 | 
			
		||||
-->
 | 
			
		||||
							
								
								
									
										8
									
								
								.github/autolabeler.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/autolabeler.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,6 +1,2 @@
 | 
			
		||||
python: ['python-packages']
 | 
			
		||||
contracts: ['contracts']
 | 
			
		||||
@0x/contract-addresses: ['packages/contract-addresses']
 | 
			
		||||
@0x/order-utils: ['packages/order-utils']
 | 
			
		||||
@0x/contract-artifacts: ['packages/contract-artifacts']
 | 
			
		||||
@0x/contract-wrappers: ['packages/contract-wrappers']
 | 
			
		||||
documentation: ['docs']
 | 
			
		||||
liquidity integrations: ['contracts/zero-ex/contracts/src/transformers']
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
version: 2
 | 
			
		||||
updates:
 | 
			
		||||
  - package-ecosystem: github-actions
 | 
			
		||||
    directory: /
 | 
			
		||||
    schedule:
 | 
			
		||||
      interval: monthly
 | 
			
		||||
    target-branch: "development"
 | 
			
		||||
							
								
								
									
										19
									
								
								.github/stale.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								.github/stale.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,19 +0,0 @@
 | 
			
		||||
# Number of days of inactivity before an issue becomes stale
 | 
			
		||||
daysUntilStale: 30
 | 
			
		||||
# Number of days of inactivity before a stale issue is closed
 | 
			
		||||
daysUntilClose: 30
 | 
			
		||||
# Issues with these labels will never be considered stale
 | 
			
		||||
exemptLabels:
 | 
			
		||||
    - pinned
 | 
			
		||||
    - security
 | 
			
		||||
# Label to use when marking an issue as stale
 | 
			
		||||
staleLabel: stale
 | 
			
		||||
# Comment to post when marking an issue as stale. Set to `false` to disable
 | 
			
		||||
markComment: >
 | 
			
		||||
    This issue has been automatically marked as stale because it has not had
 | 
			
		||||
    recent activity. It will be closed if no further activity occurs. Thank you
 | 
			
		||||
    for your contributions.
 | 
			
		||||
# Comment to post when closing a stale issue. Set to `false` to disable
 | 
			
		||||
closeComment: >
 | 
			
		||||
    This issue has been automatically closed because no activity occured in 7 days after being marked as stale. If it's still relevant - feel free to reopen. Thank you
 | 
			
		||||
    for your contributions.
 | 
			
		||||
							
								
								
									
										160
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,160 @@
 | 
			
		||||
name: Continuous Integration
 | 
			
		||||
on:
 | 
			
		||||
    push:
 | 
			
		||||
        branches:
 | 
			
		||||
            - main
 | 
			
		||||
            - development
 | 
			
		||||
    pull_request:
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
    build:
 | 
			
		||||
        name: Build and test
 | 
			
		||||
        runs-on: ubuntu-latest
 | 
			
		||||
        env:
 | 
			
		||||
            ARBITRUM_RPC_URL: ${{ secrets.ARBITRUM_RPC_URL }}
 | 
			
		||||
            AVALANCHE_RPC_URL: ${{ secrets.AVALANCHE_RPC_URL }}
 | 
			
		||||
            BSC_RPC_URL: ${{ secrets.BSC_RPC_URL }}
 | 
			
		||||
            FANTOM_RPC_URL: ${{ secrets.FANTOM_RPC_URL }}
 | 
			
		||||
            MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }}
 | 
			
		||||
            OPTIMISM_RPC_URL: ${{ secrets.OPTIMISM_RPC_URL }}
 | 
			
		||||
            POLYGON_RPC_URL: ${{ secrets.POLYGON_RPC_URL }}
 | 
			
		||||
        steps:
 | 
			
		||||
            - uses: actions/checkout@v3
 | 
			
		||||
              with:
 | 
			
		||||
                  submodules: recursive
 | 
			
		||||
 | 
			
		||||
            - name: Setup Node
 | 
			
		||||
              uses: actions/setup-node@v3
 | 
			
		||||
              with:
 | 
			
		||||
                  node-version: '16'
 | 
			
		||||
 | 
			
		||||
            - name: Install dependencies
 | 
			
		||||
              run: yarn install --frozen-lockfile
 | 
			
		||||
 | 
			
		||||
            - name: Add foundry
 | 
			
		||||
              uses: foundry-rs/foundry-toolchain@v1
 | 
			
		||||
              with:
 | 
			
		||||
                  version: nightly
 | 
			
		||||
 | 
			
		||||
            - name: Build solution
 | 
			
		||||
              run: yarn build
 | 
			
		||||
 | 
			
		||||
            - name: Lint typescript
 | 
			
		||||
              run: yarn lint:ts
 | 
			
		||||
 | 
			
		||||
            - name: Lint solidity
 | 
			
		||||
              run: yarn lint:contracts
 | 
			
		||||
 | 
			
		||||
            - name: Run prettier
 | 
			
		||||
              run: yarn prettier:ci
 | 
			
		||||
 | 
			
		||||
            - name: Check dependent packages have consistent versions
 | 
			
		||||
              run: yarn deps_versions:ci
 | 
			
		||||
 | 
			
		||||
            - name: Check diff in docs
 | 
			
		||||
              run: yarn diff_md_docs:ci
 | 
			
		||||
 | 
			
		||||
            - name: Check for broken links in markdown files
 | 
			
		||||
              run: yarn test:links
 | 
			
		||||
 | 
			
		||||
            - name: Test doc generation
 | 
			
		||||
              run: yarn test:generate_docs:ci
 | 
			
		||||
 | 
			
		||||
            - name: Test @0x/contracts-*
 | 
			
		||||
              run: |
 | 
			
		||||
                  yarn wsrun \
 | 
			
		||||
                    -p @0x/contracts-multisig \
 | 
			
		||||
                    -p @0x/contracts-utils \
 | 
			
		||||
                    -p @0x/contracts-exchange-libs \
 | 
			
		||||
                    -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:ci
 | 
			
		||||
 | 
			
		||||
            - name: Test local @0x/contracts-*
 | 
			
		||||
              run: |
 | 
			
		||||
                  yarn wsrun \
 | 
			
		||||
                    -p @0x/contracts-test-utils \
 | 
			
		||||
                    -p @0x/contract-addresses \
 | 
			
		||||
                    -p @0x/contract-artifacts \
 | 
			
		||||
                    -p @0x/contract-wrappers-test \
 | 
			
		||||
                    -p @0x/order-utils \
 | 
			
		||||
                    -m --serial -c test:ci
 | 
			
		||||
 | 
			
		||||
            - name: Run Forge build for erc20
 | 
			
		||||
              working-directory: contracts/erc20
 | 
			
		||||
              run: |
 | 
			
		||||
                  forge --version
 | 
			
		||||
                  forge build --sizes
 | 
			
		||||
 | 
			
		||||
            - name: Run Forge tests for erc20
 | 
			
		||||
              working-directory: contracts/erc20
 | 
			
		||||
              run: |
 | 
			
		||||
                  forge test -vvv --gas-report
 | 
			
		||||
 | 
			
		||||
            - name: Run Forge coverage for erc20
 | 
			
		||||
              working-directory: contracts/erc20
 | 
			
		||||
              run: |
 | 
			
		||||
                  forge coverage --report summary --report lcov
 | 
			
		||||
 | 
			
		||||
            - name: Upload the coverage report to Coveralls
 | 
			
		||||
              uses: coverallsapp/github-action@master
 | 
			
		||||
              with:
 | 
			
		||||
                  github-token: ${{ secrets.GITHUB_TOKEN }}
 | 
			
		||||
                  base-path: ./contracts/erc20/
 | 
			
		||||
                  path-to-lcov: ./contracts/erc20/lcov.info
 | 
			
		||||
 | 
			
		||||
            - name: Run Forge build for zero-ex
 | 
			
		||||
              working-directory: contracts/zero-ex
 | 
			
		||||
              run: |
 | 
			
		||||
                  forge --version
 | 
			
		||||
                  forge build --sizes
 | 
			
		||||
 | 
			
		||||
            - name: Run Forge tests for zero-ex
 | 
			
		||||
              working-directory: contracts/zero-ex
 | 
			
		||||
              run: |
 | 
			
		||||
                  forge test -vvv --gas-report
 | 
			
		||||
 | 
			
		||||
            - name: Run Forge coverage for zero-ex
 | 
			
		||||
              working-directory: contracts/zero-ex
 | 
			
		||||
              run: |
 | 
			
		||||
                  forge coverage --report summary --report lcov
 | 
			
		||||
 | 
			
		||||
            - name: Upload the coverage report to Coveralls
 | 
			
		||||
              uses: coverallsapp/github-action@master
 | 
			
		||||
              with:
 | 
			
		||||
                  github-token: ${{ secrets.GITHUB_TOKEN }}
 | 
			
		||||
                  base-path: ./contracts/zero-ex/
 | 
			
		||||
                  path-to-lcov: ./contracts/zero-ex/lcov.info
 | 
			
		||||
 | 
			
		||||
            - name: Check coverage threshold
 | 
			
		||||
              uses: VeryGoodOpenSource/very_good_coverage@v2
 | 
			
		||||
              with:
 | 
			
		||||
                  path: ./contracts/zero-ex/lcov.info
 | 
			
		||||
                  min_coverage: 6.98
 | 
			
		||||
                  exclude: '**/tests'
 | 
			
		||||
 | 
			
		||||
            - name: Run Forge build on governance contracts
 | 
			
		||||
              working-directory: ./contracts/governance
 | 
			
		||||
              run: |
 | 
			
		||||
                  forge --version
 | 
			
		||||
                  forge build --sizes
 | 
			
		||||
 | 
			
		||||
            - name: Run Forge tests on governance contracts
 | 
			
		||||
              working-directory: ./contracts/governance
 | 
			
		||||
              run: |
 | 
			
		||||
                  forge test -vvv --gas-report
 | 
			
		||||
 | 
			
		||||
            - name: Run Forge coverage on governance contracts
 | 
			
		||||
              working-directory: ./contracts/governance
 | 
			
		||||
              run: |
 | 
			
		||||
                  forge coverage --report lcov
 | 
			
		||||
 | 
			
		||||
            - name: Upload the coverage report to Coveralls
 | 
			
		||||
              uses: coverallsapp/github-action@master
 | 
			
		||||
              with:
 | 
			
		||||
                  github-token: ${{ secrets.GITHUB_TOKEN }}
 | 
			
		||||
                  base-path: ./contracts/governance/
 | 
			
		||||
                  path-to-lcov: ./contracts/governance/lcov.info
 | 
			
		||||
							
								
								
									
										4
									
								
								.github/workflows/publish.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/publish.yml
									
									
									
									
										vendored
									
									
								
							@@ -22,6 +22,10 @@ jobs:
 | 
			
		||||
                  | jq .state)
 | 
			
		||||
                  [[ "${REF_STATUS}" == '"${{ github.event.inputs.ci_status }}"' ]] || \
 | 
			
		||||
                  (echo "::error ::${{ github.ref }} does not have a successful CI status" && false)
 | 
			
		||||
            - name: Add foundry
 | 
			
		||||
              uses: foundry-rs/foundry-toolchain@v1
 | 
			
		||||
              with:
 | 
			
		||||
                  version: nightly
 | 
			
		||||
            - uses: actions/checkout@v2
 | 
			
		||||
              with:
 | 
			
		||||
                ref: ${{ github.ref }}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										40
									
								
								.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
name: "Close stale issues and PRs"
 | 
			
		||||
on:
 | 
			
		||||
  schedule:
 | 
			
		||||
    - cron: "0 8 * * 1-5" # This is in UTC.
 | 
			
		||||
  # Do a dry-run (debug-only: true) whenever this workflow itself is changed.
 | 
			
		||||
  pull_request:
 | 
			
		||||
    paths:
 | 
			
		||||
      - .github/workflows/stale.yml
 | 
			
		||||
    types:
 | 
			
		||||
      - opened
 | 
			
		||||
      - synchronize
 | 
			
		||||
 | 
			
		||||
permissions:
 | 
			
		||||
  issues: write
 | 
			
		||||
  pull-requests: write
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  stale:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/stale@v7
 | 
			
		||||
        with:
 | 
			
		||||
          ascending: true # Spend API operations budget on older, more-likely-to-get-closed issues first
 | 
			
		||||
          close-issue-message: "" # Leave no comment when closing
 | 
			
		||||
          close-pr-message: "" # Leave no comment when closing
 | 
			
		||||
          days-before-issue-stale: 30
 | 
			
		||||
          days-before-pr-stale: 30
 | 
			
		||||
          days-before-close: 14
 | 
			
		||||
          debug-only: ${{ github.event_name == 'pull_request' }} # Dry-run when true.
 | 
			
		||||
          exempt-issue-labels: bug,enhancement,feature,question
 | 
			
		||||
          # No actual changes get made in debug-only mode, so we can raise the operations ceiling.
 | 
			
		||||
          operations-per-run: ${{ github.event_name == 'pull_request' && 100 || 30}}
 | 
			
		||||
          stale-issue-label: stale
 | 
			
		||||
          stale-issue-message: "This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions."
 | 
			
		||||
          stale-pr-label: stale
 | 
			
		||||
          stale-pr-message: "This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions."
 | 
			
		||||
          # Time immemorial when in debug-only mode (ie. on pull requests).
 | 
			
		||||
          # `STALEBOT_START_DATE` otherwise.
 | 
			
		||||
          # You can use this as a killswitch by setting `STALEBOT_START_DATE` in the far future.
 | 
			
		||||
          start-date: ${{ github.event_name == 'pull_request' && '1970-01-01T00:00:00Z' || secrets.STALEBOT_START_DATE }} # ISO 8601 or RFC 2822
 | 
			
		||||
							
								
								
									
										126
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										126
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -15,9 +15,6 @@ pids
 | 
			
		||||
*.db
 | 
			
		||||
*.sqlite
 | 
			
		||||
 | 
			
		||||
# Directory for instrumented libs generated by jscoverage/JSCover
 | 
			
		||||
lib-cov
 | 
			
		||||
 | 
			
		||||
# Coverage directory used by tools like istanbul
 | 
			
		||||
coverage
 | 
			
		||||
 | 
			
		||||
@@ -66,7 +63,16 @@ typings/
 | 
			
		||||
.env
 | 
			
		||||
 | 
			
		||||
# built library using in commonjs module syntax
 | 
			
		||||
lib/
 | 
			
		||||
contracts/erc20/lib/
 | 
			
		||||
contracts/test-utils/lib/
 | 
			
		||||
contracts/treasury/lib/
 | 
			
		||||
contracts/utils/lib/
 | 
			
		||||
contracts/zero-ex/lib/
 | 
			
		||||
packages/contract-addresses/lib/
 | 
			
		||||
packages/contract-artifacts/lib/
 | 
			
		||||
packages/contract-wrappers/lib/
 | 
			
		||||
packages/protocol-utils/lib/
 | 
			
		||||
 | 
			
		||||
# UMD bundles that export the global variable
 | 
			
		||||
_bundles
 | 
			
		||||
 | 
			
		||||
@@ -80,112 +86,38 @@ TODO.md
 | 
			
		||||
.idea
 | 
			
		||||
 | 
			
		||||
# 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/
 | 
			
		||||
generated-artifacts/
 | 
			
		||||
 | 
			
		||||
# generated contract wrappers
 | 
			
		||||
contracts/broker/generated-wrappers/
 | 
			
		||||
contracts/broker/test/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/
 | 
			
		||||
generated-wrappers/
 | 
			
		||||
 | 
			
		||||
# forge std-lib
 | 
			
		||||
contracts/zero-ex/contracts/deps/forge-std
 | 
			
		||||
 | 
			
		||||
# foundry artifacts
 | 
			
		||||
contracts/zero-ex/foundry-artifacts/
 | 
			
		||||
foundry-artifacts/
 | 
			
		||||
 | 
			
		||||
# foundry cache 
 | 
			
		||||
contracts/zero-ex/foundry-cache/
 | 
			
		||||
# foundry cache
 | 
			
		||||
cache/
 | 
			
		||||
foundry-cache/
 | 
			
		||||
 | 
			
		||||
#foundry output artifacts
 | 
			
		||||
out/
 | 
			
		||||
 | 
			
		||||
# typechain wrappers
 | 
			
		||||
contracts/zero-ex/typechain-wrappers/
 | 
			
		||||
 | 
			
		||||
# foundry packages
 | 
			
		||||
contracts/governance/cache
 | 
			
		||||
contracts/governance/out
 | 
			
		||||
 | 
			
		||||
# Doc README copy
 | 
			
		||||
packages/*/docs/README.md
 | 
			
		||||
 | 
			
		||||
.DS_Store
 | 
			
		||||
*~
 | 
			
		||||
\#*\#
 | 
			
		||||
.\#*
 | 
			
		||||
 | 
			
		||||
# the snapshot that gets built for migrations sure does have a ton of files
 | 
			
		||||
packages/migrations/0x_ganache_snapshot*
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,17 @@
 | 
			
		||||
[submodule "contracts/zero-ex/contracts/deps/forge-std"]
 | 
			
		||||
	path = contracts/zero-ex/contracts/deps/forge-std
 | 
			
		||||
	url = https://github.com/foundry-rs/forge-std
 | 
			
		||||
[submodule "contracts/erc20/lib/forge-std"]
 | 
			
		||||
	path = contracts/erc20/lib/forge-std
 | 
			
		||||
    url = https://github.com/foundry-rs/forge-std
 | 
			
		||||
[submodule "contracts/governance/lib/forge-std"]
 | 
			
		||||
	path = contracts/governance/lib/forge-std
 | 
			
		||||
	url = https://github.com/foundry-rs/forge-std
 | 
			
		||||
[submodule "contracts/governance/lib/openzeppelin-contracts"]
 | 
			
		||||
	path = contracts/governance/lib/openzeppelin-contracts
 | 
			
		||||
	url = https://github.com/openzeppelin/openzeppelin-contracts
 | 
			
		||||
[submodule "contracts/governance/lib/openzeppelin-contracts-upgradeable"]
 | 
			
		||||
	path = contracts/governance/lib/openzeppelin-contracts-upgradeable
 | 
			
		||||
	url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable
 | 
			
		||||
[submodule "lib/openzeppelin-contracts-upgradeable"]
 | 
			
		||||
	branch = v4.8.2
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								.husky/pre-commit
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										4
									
								
								.husky/pre-commit
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
. "$(dirname -- "$0")/_/husky.sh"
 | 
			
		||||
 | 
			
		||||
npx lint-staged --no-stash
 | 
			
		||||
@@ -1,88 +1,10 @@
 | 
			
		||||
lib
 | 
			
		||||
deps
 | 
			
		||||
.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/foundry-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/
 | 
			
		||||
/packages/contract-wrappers/src/generated-wrappers/
 | 
			
		||||
generated-artifacts/
 | 
			
		||||
generated-wrappers/
 | 
			
		||||
foundry-artifacts/
 | 
			
		||||
out/
 | 
			
		||||
cache/
 | 
			
		||||
package.json
 | 
			
		||||
packages/*/docs
 | 
			
		||||
docs/
 | 
			
		||||
packages
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
        "avoid-tx-origin": "warn",
 | 
			
		||||
        "code-complexity": "off",
 | 
			
		||||
        "const-name-snakecase": "error",
 | 
			
		||||
        "function-max-lines": "off",
 | 
			
		||||
        "function-max-lines": ["error", 350],
 | 
			
		||||
        "max-line-length": ["error", 120],
 | 
			
		||||
        "no-inline-assembly": "off",
 | 
			
		||||
        "quotes": ["error", "double"],
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +1,9 @@
 | 
			
		||||
contracts/erc20/contracts/src/ZRXToken.sol
 | 
			
		||||
contracts/erc20/src/ZRXToken.sol
 | 
			
		||||
node_modules/
 | 
			
		||||
lib
 | 
			
		||||
deps
 | 
			
		||||
generated-artifacts/
 | 
			
		||||
generated-wrappers/
 | 
			
		||||
foundry-artifacts/
 | 
			
		||||
out/
 | 
			
		||||
cache/
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,7 @@ This repository is a monorepo including the 0x protocol smart contracts and nume
 | 
			
		||||
 | 
			
		||||
[website-url]: https://0x.org
 | 
			
		||||
 | 
			
		||||
[](https://circleci.com/gh/0xProject/protocool)
 | 
			
		||||
[](https://coveralls.io/github/0xProject/0x-monorepo?branch=development)
 | 
			
		||||
[](https://coveralls.io/github/0xProject/protocol?branch=development)
 | 
			
		||||
[](https://discordapp.com/invite/d3FTX3M)
 | 
			
		||||
[](https://opensource.org/licenses/Apache-2.0)
 | 
			
		||||
 | 
			
		||||
@@ -54,7 +53,7 @@ You can include those by prepending the `@0x/typescript-typings` package to your
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
 | 
			
		||||
#### Read our [contribution guidelines](./CONTRIBUTING.md).
 | 
			
		||||
#### Read our [contribution guidelines](.github/CONTRIBUTING.md).
 | 
			
		||||
 | 
			
		||||
### Install dependencies
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,25 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  "env": {
 | 
			
		||||
      "es2021": true,
 | 
			
		||||
      "node": true
 | 
			
		||||
  },
 | 
			
		||||
  "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"],
 | 
			
		||||
  "overrides": [],
 | 
			
		||||
  "parser": "@typescript-eslint/parser",
 | 
			
		||||
  "parserOptions": {
 | 
			
		||||
      "project": "./tsconfig.json",
 | 
			
		||||
      "ecmaVersion": "latest",
 | 
			
		||||
      "sourceType": "module"
 | 
			
		||||
  },
 | 
			
		||||
  "plugins": ["@typescript-eslint"],
 | 
			
		||||
  "ignorePatterns": [
 | 
			
		||||
      "lib/**/*",
 | 
			
		||||
      "contracts/**/*",
 | 
			
		||||
      "generated-wrappers/**/*",
 | 
			
		||||
      "generated-artifacts/**/*",
 | 
			
		||||
      "test/generated-wrappers/**/*",
 | 
			
		||||
      "test/generated-artifacts/**/*"
 | 
			
		||||
 | 
			
		||||
  ],
 | 
			
		||||
  "rules": {}
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,102 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1681969282,
 | 
			
		||||
        "version": "4.0.6",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "4.0.5",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1681756154
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1681697326,
 | 
			
		||||
        "version": "4.0.4",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1681157139,
 | 
			
		||||
        "version": "4.0.3",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1678410794,
 | 
			
		||||
        "version": "4.0.2",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1677693479,
 | 
			
		||||
        "version": "4.0.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "4.0.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Migrated package to foundry"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1675210931,
 | 
			
		||||
        "version": "3.3.57",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1675105183,
 | 
			
		||||
        "version": "3.3.56",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1674517560,
 | 
			
		||||
        "version": "3.3.55",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1670879498,
 | 
			
		||||
        "version": "3.3.54",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1669235113,
 | 
			
		||||
        "version": "3.3.53",
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,50 @@ Edit the package's CHANGELOG.json file only.
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v4.0.6 - _April 20, 2023_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.0.5 - _April 17, 2023_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.0.4 - _April 17, 2023_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.0.3 - _April 10, 2023_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.0.2 - _March 10, 2023_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.0.1 - _March 1, 2023_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v4.0.0 - _Invalid date_
 | 
			
		||||
 | 
			
		||||
    * Migrated package to foundry
 | 
			
		||||
 | 
			
		||||
## v3.3.57 - _February 1, 2023_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.3.56 - _January 30, 2023_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.3.55 - _January 23, 2023_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.3.54 - _December 12, 2022_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.3.53 - _November 23, 2022_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ We strongly recommend that the community help us make improvements and determine
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
Please read our [contribution guidelines](../../.github/CONTRIBUTING.md) before getting started.
 | 
			
		||||
 | 
			
		||||
### Install Dependencies
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,28 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
    "artifactsDir": "./test/generated-artifacts",
 | 
			
		||||
    "contractsDir": "./contracts",
 | 
			
		||||
    "useDockerisedSolc": false,
 | 
			
		||||
    "isOfflineMode": false,
 | 
			
		||||
    "shouldSaveStandardInput": true,
 | 
			
		||||
    "compilerSettings": {
 | 
			
		||||
        "evmVersion": "istanbul",
 | 
			
		||||
        "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",
 | 
			
		||||
                    "devdoc"
 | 
			
		||||
                ]
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,93 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.9;
 | 
			
		||||
 | 
			
		||||
import "./interfaces/IERC20Token.sol";
 | 
			
		||||
 | 
			
		||||
contract ERC20Token is IERC20Token {
 | 
			
		||||
    mapping(address => uint256) internal balances;
 | 
			
		||||
    mapping(address => mapping(address => uint256)) internal allowed;
 | 
			
		||||
 | 
			
		||||
    uint256 internal _totalSupply;
 | 
			
		||||
 | 
			
		||||
    /// @dev send `value` token to `to` from `msg.sender`
 | 
			
		||||
    /// @param _to The address of the recipient
 | 
			
		||||
    /// @param _value The amount of token to be transferred
 | 
			
		||||
    /// @return True if transfer was successful
 | 
			
		||||
    function transfer(address _to, uint256 _value) external returns (bool) {
 | 
			
		||||
        require(balances[msg.sender] >= _value, "ERC20_INSUFFICIENT_BALANCE");
 | 
			
		||||
        require(balances[_to] + _value >= balances[_to], "UINT256_OVERFLOW");
 | 
			
		||||
 | 
			
		||||
        balances[msg.sender] -= _value;
 | 
			
		||||
        balances[_to] += _value;
 | 
			
		||||
 | 
			
		||||
        emit Transfer(msg.sender, _to, _value);
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev send `value` token to `to` from `from` on the condition it is approved by `from`
 | 
			
		||||
    /// @param _from The address of the sender
 | 
			
		||||
    /// @param _to The address of the recipient
 | 
			
		||||
    /// @param _value The amount of token to be transferred
 | 
			
		||||
    /// @return True if transfer was successful
 | 
			
		||||
    function transferFrom(address _from, address _to, uint256 _value) external returns (bool) {
 | 
			
		||||
        require(balances[_from] >= _value, "ERC20_INSUFFICIENT_BALANCE");
 | 
			
		||||
        require(allowed[_from][msg.sender] >= _value, "ERC20_INSUFFICIENT_ALLOWANCE");
 | 
			
		||||
        require(balances[_to] + _value >= balances[_to], "UINT256_OVERFLOW");
 | 
			
		||||
 | 
			
		||||
        balances[_to] += _value;
 | 
			
		||||
        balances[_from] -= _value;
 | 
			
		||||
        allowed[_from][msg.sender] -= _value;
 | 
			
		||||
 | 
			
		||||
        emit Transfer(_from, _to, _value);
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `msg.sender` approves `_spender` to spend `_value` tokens
 | 
			
		||||
    /// @param _spender The address of the account able to transfer the tokens
 | 
			
		||||
    /// @param _value The amount of wei to be approved for transfer
 | 
			
		||||
    /// @return Always true if the call has enough gas to complete execution
 | 
			
		||||
    function approve(address _spender, uint256 _value) external returns (bool) {
 | 
			
		||||
        allowed[msg.sender][_spender] = _value;
 | 
			
		||||
        emit Approval(msg.sender, _spender, _value);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Query total supply of token
 | 
			
		||||
    /// @return Total supply of token
 | 
			
		||||
    function totalSupply() external view returns (uint256) {
 | 
			
		||||
        return _totalSupply;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Query the balance of owner
 | 
			
		||||
    /// @param _owner The address from which the balance will be retrieved
 | 
			
		||||
    /// @return Balance of owner
 | 
			
		||||
    function balanceOf(address _owner) external view returns (uint256) {
 | 
			
		||||
        return balances[_owner];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @param _owner The address of the account owning tokens
 | 
			
		||||
    /// @param _spender The address of the account able to transfer the tokens
 | 
			
		||||
    /// @return Amount of remaining tokens allowed to spent
 | 
			
		||||
    function allowance(address _owner, address _spender) external view returns (uint256) {
 | 
			
		||||
        return allowed[_owner][_spender];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,136 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.9;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
 | 
			
		||||
import "../src/interfaces/IERC20Token.sol";
 | 
			
		||||
 | 
			
		||||
library LibERC20Token {
 | 
			
		||||
    bytes private constant DECIMALS_CALL_DATA = hex"313ce567";
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls `IERC20Token(token).approve()`.
 | 
			
		||||
    ///      Reverts if `false` is returned or if the return
 | 
			
		||||
    ///      data length is nonzero and not 32 bytes.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @param spender The address that receives an allowance.
 | 
			
		||||
    /// @param allowance The allowance to set.
 | 
			
		||||
    function approve(address token, address spender, uint256 allowance) internal {
 | 
			
		||||
        bytes memory callData = abi.encodeWithSelector(IERC20Token(0).approve.selector, spender, allowance);
 | 
			
		||||
        _callWithOptionalBooleanResult(token, callData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls `IERC20Token(token).approve()` and sets the allowance to the
 | 
			
		||||
    ///      maximum if the current approval is not already >= an amount.
 | 
			
		||||
    ///      Reverts if `false` is returned or if the return
 | 
			
		||||
    ///      data length is nonzero and not 32 bytes.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @param spender The address that receives an allowance.
 | 
			
		||||
    /// @param amount The minimum allowance needed.
 | 
			
		||||
    function approveIfBelow(address token, address spender, uint256 amount) internal {
 | 
			
		||||
        if (IERC20Token(token).allowance(address(this), spender) < amount) {
 | 
			
		||||
            approve(token, spender, uint256(-1));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls `IERC20Token(token).transfer()`.
 | 
			
		||||
    ///      Reverts if `false` is returned or if the return
 | 
			
		||||
    ///      data length is nonzero and not 32 bytes.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @param to The address that receives the tokens
 | 
			
		||||
    /// @param amount Number of tokens to transfer.
 | 
			
		||||
    function transfer(address token, address to, uint256 amount) internal {
 | 
			
		||||
        bytes memory callData = abi.encodeWithSelector(IERC20Token(0).transfer.selector, to, amount);
 | 
			
		||||
        _callWithOptionalBooleanResult(token, callData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls `IERC20Token(token).transferFrom()`.
 | 
			
		||||
    ///      Reverts if `false` is returned or if the return
 | 
			
		||||
    ///      data length is nonzero and not 32 bytes.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @param from The owner of the tokens.
 | 
			
		||||
    /// @param to The address that receives the tokens
 | 
			
		||||
    /// @param amount Number of tokens to transfer.
 | 
			
		||||
    function transferFrom(address token, address from, address to, uint256 amount) internal {
 | 
			
		||||
        bytes memory callData = abi.encodeWithSelector(IERC20Token(0).transferFrom.selector, from, to, amount);
 | 
			
		||||
        _callWithOptionalBooleanResult(token, callData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Retrieves the number of decimals for a token.
 | 
			
		||||
    ///      Returns `18` if the call reverts.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @return tokenDecimals The number of decimals places for the token.
 | 
			
		||||
    function decimals(address token) internal view returns (uint8 tokenDecimals) {
 | 
			
		||||
        tokenDecimals = 18;
 | 
			
		||||
        (bool didSucceed, bytes memory resultData) = token.staticcall(DECIMALS_CALL_DATA);
 | 
			
		||||
        if (didSucceed && resultData.length == 32) {
 | 
			
		||||
            tokenDecimals = uint8(LibBytes.readUint256(resultData, 0));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Retrieves the allowance for a token, owner, and spender.
 | 
			
		||||
    ///      Returns `0` if the call reverts.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @param owner The owner of the tokens.
 | 
			
		||||
    /// @param spender The address the spender.
 | 
			
		||||
    /// @return allowance The allowance for a token, owner, and spender.
 | 
			
		||||
    function allowance(address token, address owner, address spender) internal view returns (uint256 allowance_) {
 | 
			
		||||
        (bool didSucceed, bytes memory resultData) = token.staticcall(
 | 
			
		||||
            abi.encodeWithSelector(IERC20Token(0).allowance.selector, owner, spender)
 | 
			
		||||
        );
 | 
			
		||||
        if (didSucceed && resultData.length == 32) {
 | 
			
		||||
            allowance_ = LibBytes.readUint256(resultData, 0);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Retrieves the balance for a token owner.
 | 
			
		||||
    ///      Returns `0` if the call reverts.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @param owner The owner of the tokens.
 | 
			
		||||
    /// @return balance The token balance of an owner.
 | 
			
		||||
    function balanceOf(address token, address owner) internal view returns (uint256 balance) {
 | 
			
		||||
        (bool didSucceed, bytes memory resultData) = token.staticcall(
 | 
			
		||||
            abi.encodeWithSelector(IERC20Token(0).balanceOf.selector, owner)
 | 
			
		||||
        );
 | 
			
		||||
        if (didSucceed && resultData.length == 32) {
 | 
			
		||||
            balance = LibBytes.readUint256(resultData, 0);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Executes a call on address `target` with calldata `callData`
 | 
			
		||||
    ///      and asserts that either nothing was returned or a single boolean
 | 
			
		||||
    ///      was returned equal to `true`.
 | 
			
		||||
    /// @param target The call target.
 | 
			
		||||
    /// @param callData The abi-encoded call data.
 | 
			
		||||
    function _callWithOptionalBooleanResult(address target, bytes memory callData) private {
 | 
			
		||||
        (bool didSucceed, bytes memory resultData) = target.call(callData);
 | 
			
		||||
        if (didSucceed) {
 | 
			
		||||
            if (resultData.length == 0) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            if (resultData.length == 32) {
 | 
			
		||||
                uint256 result = LibBytes.readUint256(resultData, 0);
 | 
			
		||||
                if (result == 1) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        LibRichErrors.rrevert(resultData);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,46 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.9;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
 | 
			
		||||
import "./UnlimitedAllowanceERC20Token.sol";
 | 
			
		||||
 | 
			
		||||
contract MintableERC20Token is UnlimitedAllowanceERC20Token {
 | 
			
		||||
    using LibSafeMath for uint256;
 | 
			
		||||
 | 
			
		||||
    /// @dev Mints new tokens
 | 
			
		||||
    /// @param _to Address of the beneficiary that will own the minted token
 | 
			
		||||
    /// @param _value Amount of tokens to mint
 | 
			
		||||
    function _mint(address _to, uint256 _value) internal {
 | 
			
		||||
        balances[_to] = _value.safeAdd(balances[_to]);
 | 
			
		||||
        _totalSupply = _totalSupply.safeAdd(_value);
 | 
			
		||||
 | 
			
		||||
        emit Transfer(address(0), _to, _value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Mints new tokens
 | 
			
		||||
    /// @param _owner Owner of tokens that will be burned
 | 
			
		||||
    /// @param _value Amount of tokens to burn
 | 
			
		||||
    function _burn(address _owner, uint256 _value) internal {
 | 
			
		||||
        balances[_owner] = balances[_owner].safeSub(_value);
 | 
			
		||||
        _totalSupply = _totalSupply.safeSub(_value);
 | 
			
		||||
 | 
			
		||||
        emit Transfer(_owner, address(0), _value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,48 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.9;
 | 
			
		||||
 | 
			
		||||
import "./ERC20Token.sol";
 | 
			
		||||
 | 
			
		||||
contract UnlimitedAllowanceERC20Token is ERC20Token {
 | 
			
		||||
    uint256 internal constant MAX_UINT = 2 ** 256 - 1;
 | 
			
		||||
 | 
			
		||||
    /// @dev ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance.
 | 
			
		||||
    // See https://github.com/ethereum/EIPs/issues/717
 | 
			
		||||
    /// @param _from Address to transfer from.
 | 
			
		||||
    /// @param _to Address to transfer to.
 | 
			
		||||
    /// @param _value Amount to transfer.
 | 
			
		||||
    /// @return Success of transfer.
 | 
			
		||||
    function transferFrom(address _from, address _to, uint256 _value) external returns (bool) {
 | 
			
		||||
        uint256 allowance = allowed[_from][msg.sender];
 | 
			
		||||
        require(balances[_from] >= _value, "ERC20_INSUFFICIENT_BALANCE");
 | 
			
		||||
        require(allowance >= _value, "ERC20_INSUFFICIENT_ALLOWANCE");
 | 
			
		||||
        require(balances[_to] + _value >= balances[_to], "UINT256_OVERFLOW");
 | 
			
		||||
 | 
			
		||||
        balances[_to] += _value;
 | 
			
		||||
        balances[_from] -= _value;
 | 
			
		||||
        if (allowance < MAX_UINT) {
 | 
			
		||||
            allowed[_from][msg.sender] -= _value;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        emit Transfer(_from, _to, _value);
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,57 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.9;
 | 
			
		||||
 | 
			
		||||
contract IERC20Token {
 | 
			
		||||
    event Transfer(address indexed _from, address indexed _to, uint256 _value);
 | 
			
		||||
 | 
			
		||||
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
 | 
			
		||||
 | 
			
		||||
    /// @dev send `value` token to `to` from `msg.sender`
 | 
			
		||||
    /// @param _to The address of the recipient
 | 
			
		||||
    /// @param _value The amount of token to be transferred
 | 
			
		||||
    /// @return True if transfer was successful
 | 
			
		||||
    function transfer(address _to, uint256 _value) external returns (bool);
 | 
			
		||||
 | 
			
		||||
    /// @dev send `value` token to `to` from `from` on the condition it is approved by `from`
 | 
			
		||||
    /// @param _from The address of the sender
 | 
			
		||||
    /// @param _to The address of the recipient
 | 
			
		||||
    /// @param _value The amount of token to be transferred
 | 
			
		||||
    /// @return True if transfer was successful
 | 
			
		||||
    function transferFrom(address _from, address _to, uint256 _value) external returns (bool);
 | 
			
		||||
 | 
			
		||||
    /// @dev `msg.sender` approves `_spender` to spend `_value` tokens
 | 
			
		||||
    /// @param _spender The address of the account able to transfer the tokens
 | 
			
		||||
    /// @param _value The amount of wei to be approved for transfer
 | 
			
		||||
    /// @return Always true if the call has enough gas to complete execution
 | 
			
		||||
    function approve(address _spender, uint256 _value) external returns (bool);
 | 
			
		||||
 | 
			
		||||
    /// @dev Query total supply of token
 | 
			
		||||
    /// @return Total supply of token
 | 
			
		||||
    function totalSupply() external view returns (uint256);
 | 
			
		||||
 | 
			
		||||
    /// @param _owner The address from which the balance will be retrieved
 | 
			
		||||
    /// @return Balance of owner
 | 
			
		||||
    function balanceOf(address _owner) external view returns (uint256);
 | 
			
		||||
 | 
			
		||||
    /// @param _owner The address of the account owning tokens
 | 
			
		||||
    /// @param _spender The address of the account able to transfer the tokens
 | 
			
		||||
    /// @return Amount of remaining tokens allowed to spent
 | 
			
		||||
    function allowance(address _owner, address _spender) external view returns (uint256);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,61 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/Ownable.sol";
 | 
			
		||||
import "../src/MintableERC20Token.sol";
 | 
			
		||||
 | 
			
		||||
contract DummyERC20Token is Ownable, MintableERC20Token {
 | 
			
		||||
    using LibSafeMath for uint256;
 | 
			
		||||
 | 
			
		||||
    string public name;
 | 
			
		||||
    string public symbol;
 | 
			
		||||
    uint256 public decimals;
 | 
			
		||||
    uint256 public constant MAX_MINT_AMOUNT = 10000000000000000000000;
 | 
			
		||||
 | 
			
		||||
    constructor(string memory _name, string memory _symbol, uint256 _decimals, uint256 _totalSupply) public {
 | 
			
		||||
        name = _name;
 | 
			
		||||
        symbol = _symbol;
 | 
			
		||||
        decimals = _decimals;
 | 
			
		||||
        _totalSupply = _totalSupply;
 | 
			
		||||
        balances[msg.sender] = _totalSupply;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sets the balance of target address
 | 
			
		||||
    /// @param _target Address or which balance will be updated
 | 
			
		||||
    /// @param _value New balance of target address
 | 
			
		||||
    function setBalance(address _target, uint256 _value) external onlyOwner {
 | 
			
		||||
        uint256 currBalance = balances[_target];
 | 
			
		||||
        if (_value < currBalance) {
 | 
			
		||||
            _totalSupply = _totalSupply.safeSub(currBalance.safeSub(_value));
 | 
			
		||||
        } else {
 | 
			
		||||
            _totalSupply = _totalSupply.safeAdd(_value.safeSub(currBalance));
 | 
			
		||||
        }
 | 
			
		||||
        balances[_target] = _value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Mints new tokens for sender
 | 
			
		||||
    /// @param _value Amount of tokens to mint
 | 
			
		||||
    function mint(uint256 _value) external {
 | 
			
		||||
        require(_value <= MAX_MINT_AMOUNT, "VALUE_TOO_LARGE");
 | 
			
		||||
 | 
			
		||||
        _mint(msg.sender, _value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,46 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
 | 
			
		||||
import "./DummyERC20Token.sol";
 | 
			
		||||
 | 
			
		||||
contract DummyMultipleReturnERC20Token is DummyERC20Token {
 | 
			
		||||
    constructor(
 | 
			
		||||
        string memory _name,
 | 
			
		||||
        string memory _symbol,
 | 
			
		||||
        uint256 _decimals,
 | 
			
		||||
        uint256 _totalSupply
 | 
			
		||||
    ) public DummyERC20Token(_name, _symbol, _decimals, _totalSupply) {}
 | 
			
		||||
 | 
			
		||||
    /// @dev send `value` token to `to` from `from` on the condition it is approved by `from`
 | 
			
		||||
    /// @param _from The address of the sender
 | 
			
		||||
    /// @param _to The address of the recipient
 | 
			
		||||
    /// @param _value The amount of token to be transferred
 | 
			
		||||
    function transferFrom(address _from, address _to, uint256 _value) external returns (bool) {
 | 
			
		||||
        emit Transfer(_from, _to, _value);
 | 
			
		||||
 | 
			
		||||
        // HACK: This contract will not compile if we remove `returns (bool)`, so we manually return 64 bytes
 | 
			
		||||
        // (equiavalent to true, true)
 | 
			
		||||
        assembly {
 | 
			
		||||
            mstore(0, 1)
 | 
			
		||||
            mstore(32, 1)
 | 
			
		||||
            return(0, 64)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,69 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
 | 
			
		||||
import "./DummyERC20Token.sol";
 | 
			
		||||
 | 
			
		||||
contract DummyNoReturnERC20Token is DummyERC20Token {
 | 
			
		||||
    constructor(
 | 
			
		||||
        string memory _name,
 | 
			
		||||
        string memory _symbol,
 | 
			
		||||
        uint256 _decimals,
 | 
			
		||||
        uint256 _totalSupply
 | 
			
		||||
    ) public DummyERC20Token(_name, _symbol, _decimals, _totalSupply) {}
 | 
			
		||||
 | 
			
		||||
    /// @dev send `value` token to `to` from `msg.sender`
 | 
			
		||||
    /// @param _to The address of the recipient
 | 
			
		||||
    /// @param _value The amount of token to be transferred
 | 
			
		||||
    function transfer(address _to, uint256 _value) external returns (bool) {
 | 
			
		||||
        require(balances[msg.sender] >= _value, "ERC20_INSUFFICIENT_BALANCE");
 | 
			
		||||
        require(balances[_to] + _value >= balances[_to], "UINT256_OVERFLOW");
 | 
			
		||||
 | 
			
		||||
        balances[msg.sender] -= _value;
 | 
			
		||||
        balances[_to] += _value;
 | 
			
		||||
 | 
			
		||||
        emit Transfer(msg.sender, _to, _value);
 | 
			
		||||
 | 
			
		||||
        // HACK: This contract will not compile if we remove `returns (bool)`, so we manually return no data
 | 
			
		||||
        assembly {
 | 
			
		||||
            return(0, 0)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev send `value` token to `to` from `from` on the condition it is approved by `from`
 | 
			
		||||
    /// @param _from The address of the sender
 | 
			
		||||
    /// @param _to The address of the recipient
 | 
			
		||||
    /// @param _value The amount of token to be transferred
 | 
			
		||||
    function transferFrom(address _from, address _to, uint256 _value) external returns (bool) {
 | 
			
		||||
        require(balances[_from] >= _value, "ERC20_INSUFFICIENT_BALANCE");
 | 
			
		||||
        require(allowed[_from][msg.sender] >= _value, "ERC20_INSUFFICIENT_ALLOWANCE");
 | 
			
		||||
        require(balances[_to] + _value >= balances[_to], "UINT256_OVERFLOW");
 | 
			
		||||
 | 
			
		||||
        balances[_to] += _value;
 | 
			
		||||
        balances[_from] -= _value;
 | 
			
		||||
        allowed[_from][msg.sender] -= _value;
 | 
			
		||||
 | 
			
		||||
        emit Transfer(_from, _to, _value);
 | 
			
		||||
 | 
			
		||||
        // HACK: This contract will not compile if we remove `returns (bool)`, so we manually return no data
 | 
			
		||||
        assembly {
 | 
			
		||||
            return(0, 0)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,73 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.9;
 | 
			
		||||
 | 
			
		||||
import "../src/LibERC20Token.sol";
 | 
			
		||||
import "./TestLibERC20TokenTarget.sol";
 | 
			
		||||
 | 
			
		||||
contract TestLibERC20Token {
 | 
			
		||||
    TestLibERC20TokenTarget public target;
 | 
			
		||||
 | 
			
		||||
    constructor() public {
 | 
			
		||||
        target = new TestLibERC20TokenTarget();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testApprove(
 | 
			
		||||
        bool shouldRevert,
 | 
			
		||||
        bytes calldata revertData,
 | 
			
		||||
        bytes calldata returnData,
 | 
			
		||||
        address spender,
 | 
			
		||||
        uint256 allowance
 | 
			
		||||
    ) external {
 | 
			
		||||
        target.setBehavior(shouldRevert, revertData, returnData);
 | 
			
		||||
        LibERC20Token.approve(address(target), spender, allowance);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testTransfer(
 | 
			
		||||
        bool shouldRevert,
 | 
			
		||||
        bytes calldata revertData,
 | 
			
		||||
        bytes calldata returnData,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    ) external {
 | 
			
		||||
        target.setBehavior(shouldRevert, revertData, returnData);
 | 
			
		||||
        LibERC20Token.transfer(address(target), to, amount);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testTransferFrom(
 | 
			
		||||
        bool shouldRevert,
 | 
			
		||||
        bytes calldata revertData,
 | 
			
		||||
        bytes calldata returnData,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    ) external {
 | 
			
		||||
        target.setBehavior(shouldRevert, revertData, returnData);
 | 
			
		||||
        LibERC20Token.transferFrom(address(target), from, to, amount);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testDecimals(
 | 
			
		||||
        bool shouldRevert,
 | 
			
		||||
        bytes calldata revertData,
 | 
			
		||||
        bytes calldata returnData
 | 
			
		||||
    ) external returns (uint8) {
 | 
			
		||||
        target.setBehavior(shouldRevert, revertData, returnData);
 | 
			
		||||
        return LibERC20Token.decimals(address(target));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,69 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.9;
 | 
			
		||||
 | 
			
		||||
contract TestLibERC20TokenTarget {
 | 
			
		||||
    event ApproveCalled(address spender, uint256 allowance);
 | 
			
		||||
 | 
			
		||||
    event TransferCalled(address to, uint256 amount);
 | 
			
		||||
 | 
			
		||||
    event TransferFromCalled(address from, address to, uint256 amount);
 | 
			
		||||
 | 
			
		||||
    bool private _shouldRevert;
 | 
			
		||||
    bytes private _revertData;
 | 
			
		||||
    bytes private _returnData;
 | 
			
		||||
 | 
			
		||||
    function setBehavior(bool shouldRevert, bytes calldata revertData, bytes calldata returnData) external {
 | 
			
		||||
        _shouldRevert = shouldRevert;
 | 
			
		||||
        _revertData = revertData;
 | 
			
		||||
        _returnData = returnData;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function approve(address spender, uint256 allowance) external returns (bool) {
 | 
			
		||||
        emit ApproveCalled(spender, allowance);
 | 
			
		||||
        _execute();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function transfer(address to, uint256 amount) external returns (bool) {
 | 
			
		||||
        emit TransferCalled(to, amount);
 | 
			
		||||
        _execute();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function transferFrom(address from, address to, uint256 amount) external returns (bool) {
 | 
			
		||||
        emit TransferFromCalled(from, to, amount);
 | 
			
		||||
        _execute();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function decimals() external view returns (uint8) {
 | 
			
		||||
        _execute();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _execute() private view {
 | 
			
		||||
        if (_shouldRevert) {
 | 
			
		||||
            bytes memory revertData = _revertData;
 | 
			
		||||
            assembly {
 | 
			
		||||
                revert(add(revertData, 0x20), mload(revertData))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        bytes memory returnData = _returnData;
 | 
			
		||||
        assembly {
 | 
			
		||||
            return(add(returnData, 0x20), mload(returnData))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,38 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
 | 
			
		||||
import "./DummyERC20Token.sol";
 | 
			
		||||
 | 
			
		||||
contract UntransferrableDummyERC20Token is DummyERC20Token {
 | 
			
		||||
    constructor(
 | 
			
		||||
        string memory _name,
 | 
			
		||||
        string memory _symbol,
 | 
			
		||||
        uint256 _decimals,
 | 
			
		||||
        uint256 _totalSupply
 | 
			
		||||
    ) public DummyERC20Token(_name, _symbol, _decimals, _totalSupply) {}
 | 
			
		||||
 | 
			
		||||
    /// @dev send `value` token to `to` from `from` on the condition it is approved by `from`
 | 
			
		||||
    /// @param _from The address of the sender
 | 
			
		||||
    /// @param _to The address of the recipient
 | 
			
		||||
    /// @param _value The amount of token to be transferred
 | 
			
		||||
    function transferFrom(address _from, address _to, uint256 _value) external returns (bool) {
 | 
			
		||||
        require(false, "TRANSFER_DISABLED");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								contracts/erc20/foundry.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								contracts/erc20/foundry.toml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
[profile.default]
 | 
			
		||||
src = 'src'
 | 
			
		||||
out = 'out'
 | 
			
		||||
libs = [
 | 
			
		||||
    'lib',
 | 
			
		||||
    'node_modules',
 | 
			
		||||
]
 | 
			
		||||
remappings = [
 | 
			
		||||
    '@0x/contracts-utils/=../utils/'
 | 
			
		||||
]
 | 
			
		||||
allow_paths = [
 | 
			
		||||
    '../utils/'
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
fs_permissions = [{ access = "read", path = "./out/ZRXToken.sol" }]
 | 
			
		||||
 | 
			
		||||
optimizer_runs = 1_000_000
 | 
			
		||||
# See more config options https://github.com/foundry-rs/foundry/tree/master/config
 | 
			
		||||
							
								
								
									
										1
									
								
								contracts/erc20/lib/forge-std
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								contracts/erc20/lib/forge-std
									
									
									
									
									
										Submodule
									
								
							 Submodule contracts/erc20/lib/forge-std added at fc560fa34f
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contracts-erc20",
 | 
			
		||||
    "version": "3.3.53",
 | 
			
		||||
    "version": "4.0.6",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
@@ -10,36 +10,10 @@
 | 
			
		||||
        "test": "test"
 | 
			
		||||
    },
 | 
			
		||||
    "scripts": {
 | 
			
		||||
        "build": "yarn pre_build && tsc -b",
 | 
			
		||||
        "build:ci": "yarn build",
 | 
			
		||||
        "pre_build": "run-s compile contracts:gen generate_contract_wrappers contracts:copy",
 | 
			
		||||
        "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 test/generated-artifacts test/generated-wrappers generated-artifacts generated-wrappers",
 | 
			
		||||
        "generate_contract_wrappers": "abi-gen --debug --abis  ${npm_package_config_abis} --output test/generated-wrappers --backend ethers",
 | 
			
		||||
        "lint": "eslint src test",
 | 
			
		||||
        "fix": "eslint --fix src test",
 | 
			
		||||
        "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 generate",
 | 
			
		||||
        "contracts:copy": "contracts-gen copy",
 | 
			
		||||
        "test:ci": "forge test",
 | 
			
		||||
        "docs:md": "ts-doc-gen --sourceDir='$PROJECT_FILES' --output=$MD_FILE_DIR --fileExtension=mdx --tsconfig=./typedoc-tsconfig.json",
 | 
			
		||||
        "docs:json": "typedoc --excludePrivate --excludeExternals --excludeProtected --ignoreCompilerErrors --target ES5 --tsconfig typedoc-tsconfig.json --json $JSON_FILE_PATH $PROJECT_FILES"
 | 
			
		||||
    },
 | 
			
		||||
    "config": {
 | 
			
		||||
        "publicInterfaceContracts": "DummyERC20Token,ERC20Token,WETH9,ZRXToken,DummyNoReturnERC20Token,DummyMultipleReturnERC20Token",
 | 
			
		||||
        "abis": "./test/generated-artifacts/@(DummyERC20Token|DummyMultipleReturnERC20Token|DummyNoReturnERC20Token|ERC20Token|IERC20Token|IERC20TokenV06|IEtherToken|IEtherTokenV06|LibERC20Token|LibERC20TokenV06|MintableERC20Token|TestLibERC20Token|TestLibERC20TokenTarget|UnlimitedAllowanceERC20Token|UntransferrableDummyERC20Token|WETH9|ZRXToken).json",
 | 
			
		||||
        "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually."
 | 
			
		||||
    },
 | 
			
		||||
    "repository": {
 | 
			
		||||
        "type": "git",
 | 
			
		||||
        "url": "https://github.com/0xProject/protocol.git"
 | 
			
		||||
@@ -48,42 +22,11 @@
 | 
			
		||||
    "bugs": {
 | 
			
		||||
        "url": "https://github.com/0xProject/protocol/issues"
 | 
			
		||||
    },
 | 
			
		||||
    "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens",
 | 
			
		||||
    "homepage": "https://github.com/0xProject/protocol",
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "@0x/abi-gen": "^5.8.1",
 | 
			
		||||
        "@0x/contracts-gen": "^2.0.48",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.4.43",
 | 
			
		||||
        "@0x/contracts-utils": "^4.8.34",
 | 
			
		||||
        "@0x/dev-utils": "^5.0.0",
 | 
			
		||||
        "@0x/sol-compiler": "^4.8.2",
 | 
			
		||||
        "@0x/contracts-utils": "^4.8.44",
 | 
			
		||||
        "@0x/ts-doc-gen": "^0.0.28",
 | 
			
		||||
        "@0x/types": "^3.3.6",
 | 
			
		||||
        "@0x/typescript-typings": "^5.3.1",
 | 
			
		||||
        "@0x/utils": "^7.0.0",
 | 
			
		||||
        "@0x/web3-wrapper": "^8.0.0",
 | 
			
		||||
        "@types/lodash": "4.14.104",
 | 
			
		||||
        "@types/mocha": "^5.2.7",
 | 
			
		||||
        "@types/node": "12.12.54",
 | 
			
		||||
        "@typescript-eslint/eslint-plugin": "^5.38.0",
 | 
			
		||||
        "@typescript-eslint/parser": "^5.38.0",
 | 
			
		||||
        "chai": "^4.0.1",
 | 
			
		||||
        "chai-as-promised": "^7.1.0",
 | 
			
		||||
        "chai-bignumber": "^3.0.0",
 | 
			
		||||
        "dirty-chai": "^2.0.1",
 | 
			
		||||
        "eslint": "^8.23.1",
 | 
			
		||||
        "eslint-config-prettier": "^8.5.0",
 | 
			
		||||
        "ethereum-types": "^3.7.1",
 | 
			
		||||
        "lodash": "^4.17.11",
 | 
			
		||||
        "make-promises-safe": "^1.1.0",
 | 
			
		||||
        "mocha": "^6.2.0",
 | 
			
		||||
        "npm-run-all": "^4.1.2",
 | 
			
		||||
        "shx": "^0.2.2",
 | 
			
		||||
        "typedoc": "~0.16.11",
 | 
			
		||||
        "typescript": "4.6.3"
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@0x/base-contract": "^7.0.0",
 | 
			
		||||
        "ethers": "~4.0.4"
 | 
			
		||||
        "typedoc": "~0.16.11"
 | 
			
		||||
    },
 | 
			
		||||
    "publishConfig": {
 | 
			
		||||
        "access": "public"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 ZeroEx Intl.
 | 
			
		||||
  Copyright 2023 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
@@ -17,9 +17,9 @@
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6.5;
 | 
			
		||||
pragma solidity >=0.6.5 <0.9;
 | 
			
		||||
 | 
			
		||||
interface IERC20TokenV06 {
 | 
			
		||||
interface IERC20Token {
 | 
			
		||||
    event Transfer(address indexed from, address indexed to, uint256 value);
 | 
			
		||||
 | 
			
		||||
    event Approval(address indexed owner, address indexed spender, uint256 value);
 | 
			
		||||
@@ -19,9 +19,9 @@
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.6.5;
 | 
			
		||||
 | 
			
		||||
import "./IERC20TokenV06.sol";
 | 
			
		||||
import "./IERC20Token.sol";
 | 
			
		||||
 | 
			
		||||
interface IEtherTokenV06 is IERC20TokenV06 {
 | 
			
		||||
interface IEtherToken is IERC20Token {
 | 
			
		||||
    /// @dev Wrap ether.
 | 
			
		||||
    function deposit() external payable;
 | 
			
		||||
 | 
			
		||||
@@ -1,21 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 * Warning: This file is auto-generated by contracts-gen. Don't edit manually.
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
import { ContractArtifact } from 'ethereum-types';
 | 
			
		||||
 | 
			
		||||
import * as DummyERC20Token from '../generated-artifacts/DummyERC20Token.json';
 | 
			
		||||
import * as DummyMultipleReturnERC20Token from '../generated-artifacts/DummyMultipleReturnERC20Token.json';
 | 
			
		||||
import * as DummyNoReturnERC20Token from '../generated-artifacts/DummyNoReturnERC20Token.json';
 | 
			
		||||
import * as ERC20Token from '../generated-artifacts/ERC20Token.json';
 | 
			
		||||
import * as WETH9 from '../generated-artifacts/WETH9.json';
 | 
			
		||||
import * as ZRXToken from '../generated-artifacts/ZRXToken.json';
 | 
			
		||||
export const artifacts = {
 | 
			
		||||
    DummyERC20Token: DummyERC20Token as ContractArtifact,
 | 
			
		||||
    ERC20Token: ERC20Token as ContractArtifact,
 | 
			
		||||
    WETH9: WETH9 as ContractArtifact,
 | 
			
		||||
    ZRXToken: ZRXToken as any as ContractArtifact,
 | 
			
		||||
    DummyNoReturnERC20Token: DummyNoReturnERC20Token as ContractArtifact,
 | 
			
		||||
    DummyMultipleReturnERC20Token: DummyMultipleReturnERC20Token as ContractArtifact,
 | 
			
		||||
};
 | 
			
		||||
@@ -1,47 +0,0 @@
 | 
			
		||||
export {
 | 
			
		||||
    DummyERC20TokenContract,
 | 
			
		||||
    DummyMultipleReturnERC20TokenContract,
 | 
			
		||||
    DummyNoReturnERC20TokenContract,
 | 
			
		||||
    WETH9Contract,
 | 
			
		||||
    WETH9Events,
 | 
			
		||||
    WETH9DepositEventArgs,
 | 
			
		||||
    WETH9TransferEventArgs,
 | 
			
		||||
    WETH9WithdrawalEventArgs,
 | 
			
		||||
    ZRXTokenContract,
 | 
			
		||||
    DummyERC20TokenTransferEventArgs,
 | 
			
		||||
    ERC20TokenEventArgs,
 | 
			
		||||
    ERC20TokenEvents,
 | 
			
		||||
    ERC20TokenTransferEventArgs,
 | 
			
		||||
    ERC20TokenApprovalEventArgs,
 | 
			
		||||
    ERC20TokenContract,
 | 
			
		||||
} from './wrappers';
 | 
			
		||||
export { artifacts } from './artifacts';
 | 
			
		||||
export {
 | 
			
		||||
    ContractArtifact,
 | 
			
		||||
    ContractChains,
 | 
			
		||||
    CompilerOpts,
 | 
			
		||||
    StandardContractOutput,
 | 
			
		||||
    CompilerSettings,
 | 
			
		||||
    ContractChainData,
 | 
			
		||||
    ContractAbi,
 | 
			
		||||
    DevdocOutput,
 | 
			
		||||
    EvmOutput,
 | 
			
		||||
    CompilerSettingsMetadata,
 | 
			
		||||
    OptimizerSettings,
 | 
			
		||||
    OutputField,
 | 
			
		||||
    ParamDescription,
 | 
			
		||||
    EvmBytecodeOutput,
 | 
			
		||||
    EvmBytecodeOutputLinkReferences,
 | 
			
		||||
    AbiDefinition,
 | 
			
		||||
    FunctionAbi,
 | 
			
		||||
    EventAbi,
 | 
			
		||||
    RevertErrorAbi,
 | 
			
		||||
    EventParameter,
 | 
			
		||||
    DataItem,
 | 
			
		||||
    MethodAbi,
 | 
			
		||||
    ConstructorAbi,
 | 
			
		||||
    FallbackAbi,
 | 
			
		||||
    ConstructorStateMutability,
 | 
			
		||||
    TupleDataItem,
 | 
			
		||||
    StateMutability,
 | 
			
		||||
} from 'ethereum-types';
 | 
			
		||||
@@ -21,50 +21,50 @@ pragma solidity ^0.6.5;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol";
 | 
			
		||||
import "./IERC20TokenV06.sol";
 | 
			
		||||
import "../IERC20Token.sol";
 | 
			
		||||
 | 
			
		||||
library LibERC20TokenV06 {
 | 
			
		||||
    bytes private constant DECIMALS_CALL_DATA = hex"313ce567";
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls `IERC20TokenV06(token).approve()`.
 | 
			
		||||
    /// @dev Calls `IERC20Token(token).approve()`.
 | 
			
		||||
    ///      Reverts if the return data is invalid or the call reverts.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @param spender The address that receives an allowance.
 | 
			
		||||
    /// @param allowance The allowance to set.
 | 
			
		||||
    function compatApprove(IERC20TokenV06 token, address spender, uint256 allowance) internal {
 | 
			
		||||
    function compatApprove(IERC20Token token, address spender, uint256 allowance) internal {
 | 
			
		||||
        bytes memory callData = abi.encodeWithSelector(token.approve.selector, spender, allowance);
 | 
			
		||||
        _callWithOptionalBooleanResult(address(token), callData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls `IERC20TokenV06(token).approve()` and sets the allowance to the
 | 
			
		||||
    /// @dev Calls `IERC20Token(token).approve()` and sets the allowance to the
 | 
			
		||||
    ///      maximum if the current approval is not already >= an amount.
 | 
			
		||||
    ///      Reverts if the return data is invalid or the call reverts.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @param spender The address that receives an allowance.
 | 
			
		||||
    /// @param amount The minimum allowance needed.
 | 
			
		||||
    function approveIfBelow(IERC20TokenV06 token, address spender, uint256 amount) internal {
 | 
			
		||||
    function approveIfBelow(IERC20Token token, address spender, uint256 amount) internal {
 | 
			
		||||
        if (token.allowance(address(this), spender) < amount) {
 | 
			
		||||
            compatApprove(token, spender, uint256(-1));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls `IERC20TokenV06(token).transfer()`.
 | 
			
		||||
    /// @dev Calls `IERC20Token(token).transfer()`.
 | 
			
		||||
    ///      Reverts if the return data is invalid or the call reverts.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @param to The address that receives the tokens
 | 
			
		||||
    /// @param amount Number of tokens to transfer.
 | 
			
		||||
    function compatTransfer(IERC20TokenV06 token, address to, uint256 amount) internal {
 | 
			
		||||
    function compatTransfer(IERC20Token token, address to, uint256 amount) internal {
 | 
			
		||||
        bytes memory callData = abi.encodeWithSelector(token.transfer.selector, to, amount);
 | 
			
		||||
        _callWithOptionalBooleanResult(address(token), callData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls `IERC20TokenV06(token).transferFrom()`.
 | 
			
		||||
    /// @dev Calls `IERC20Token(token).transferFrom()`.
 | 
			
		||||
    ///      Reverts if the return data is invalid or the call reverts.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @param from The owner of the tokens.
 | 
			
		||||
    /// @param to The address that receives the tokens
 | 
			
		||||
    /// @param amount Number of tokens to transfer.
 | 
			
		||||
    function compatTransferFrom(IERC20TokenV06 token, address from, address to, uint256 amount) internal {
 | 
			
		||||
    function compatTransferFrom(IERC20Token token, address from, address to, uint256 amount) internal {
 | 
			
		||||
        bytes memory callData = abi.encodeWithSelector(token.transferFrom.selector, from, to, amount);
 | 
			
		||||
        _callWithOptionalBooleanResult(address(token), callData);
 | 
			
		||||
    }
 | 
			
		||||
@@ -73,7 +73,7 @@ library LibERC20TokenV06 {
 | 
			
		||||
    ///      Returns `18` if the call reverts.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @return tokenDecimals The number of decimals places for the token.
 | 
			
		||||
    function compatDecimals(IERC20TokenV06 token) internal view returns (uint8 tokenDecimals) {
 | 
			
		||||
    function compatDecimals(IERC20Token token) internal view returns (uint8 tokenDecimals) {
 | 
			
		||||
        tokenDecimals = 18;
 | 
			
		||||
        (bool didSucceed, bytes memory resultData) = address(token).staticcall(DECIMALS_CALL_DATA);
 | 
			
		||||
        if (didSucceed && resultData.length >= 32) {
 | 
			
		||||
@@ -88,7 +88,7 @@ library LibERC20TokenV06 {
 | 
			
		||||
    /// @param spender The address the spender.
 | 
			
		||||
    /// @return allowance_ The allowance for a token, owner, and spender.
 | 
			
		||||
    function compatAllowance(
 | 
			
		||||
        IERC20TokenV06 token,
 | 
			
		||||
        IERC20Token token,
 | 
			
		||||
        address owner,
 | 
			
		||||
        address spender
 | 
			
		||||
    ) internal view returns (uint256 allowance_) {
 | 
			
		||||
@@ -105,7 +105,7 @@ library LibERC20TokenV06 {
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @param owner The owner of the tokens.
 | 
			
		||||
    /// @return balance The token balance of an owner.
 | 
			
		||||
    function compatBalanceOf(IERC20TokenV06 token, address owner) internal view returns (uint256 balance) {
 | 
			
		||||
    function compatBalanceOf(IERC20Token token, address owner) internal view returns (uint256 balance) {
 | 
			
		||||
        (bool didSucceed, bytes memory resultData) = address(token).staticcall(
 | 
			
		||||
            abi.encodeWithSelector(token.balanceOf.selector, owner)
 | 
			
		||||
        );
 | 
			
		||||
							
								
								
									
										755
									
								
								contracts/erc20/src/v06/WETH9V06.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										755
									
								
								contracts/erc20/src/v06/WETH9V06.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,755 @@
 | 
			
		||||
// Copyright (C) 2015, 2016, 2017 Dapphub
 | 
			
		||||
 | 
			
		||||
// This program is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
// This program is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
// solhint-disable
 | 
			
		||||
pragma solidity ^0.6.0;
 | 
			
		||||
 | 
			
		||||
contract WETH9V06 {
 | 
			
		||||
    string public name = "Wrapped Ether";
 | 
			
		||||
    string public symbol = "WETH";
 | 
			
		||||
    uint8 public decimals = 18;
 | 
			
		||||
 | 
			
		||||
    event Approval(address indexed _owner, address indexed _spender, uint _value);
 | 
			
		||||
    event Transfer(address indexed _from, address indexed _to, uint _value);
 | 
			
		||||
    event Deposit(address indexed _owner, uint _value);
 | 
			
		||||
    event Withdrawal(address indexed _owner, uint _value);
 | 
			
		||||
 | 
			
		||||
    mapping(address => uint) public balanceOf;
 | 
			
		||||
    mapping(address => mapping(address => uint)) public allowance;
 | 
			
		||||
 | 
			
		||||
    receive() external payable {
 | 
			
		||||
        deposit();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function deposit() public payable {
 | 
			
		||||
        balanceOf[msg.sender] += msg.value;
 | 
			
		||||
        emit Deposit(msg.sender, msg.value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function withdraw(uint wad) public {
 | 
			
		||||
        require(balanceOf[msg.sender] >= wad);
 | 
			
		||||
        balanceOf[msg.sender] -= wad;
 | 
			
		||||
        msg.sender.transfer(wad);
 | 
			
		||||
        emit Withdrawal(msg.sender, wad);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function totalSupply() public view returns (uint) {
 | 
			
		||||
        return address(this).balance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function approve(address guy, uint wad) public returns (bool) {
 | 
			
		||||
        allowance[msg.sender][guy] = wad;
 | 
			
		||||
        emit Approval(msg.sender, guy, wad);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function transfer(address dst, uint wad) public returns (bool) {
 | 
			
		||||
        return transferFrom(msg.sender, dst, wad);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function transferFrom(address src, address dst, uint wad) public returns (bool) {
 | 
			
		||||
        require(balanceOf[src] >= wad);
 | 
			
		||||
 | 
			
		||||
        if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) {
 | 
			
		||||
            require(allowance[src][msg.sender] >= wad);
 | 
			
		||||
            allowance[src][msg.sender] -= wad;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        balanceOf[src] -= wad;
 | 
			
		||||
        balanceOf[dst] += wad;
 | 
			
		||||
 | 
			
		||||
        emit Transfer(src, dst, wad);
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
                    GNU GENERAL PUBLIC LICENSE
 | 
			
		||||
                       Version 3, 29 June 2007
 | 
			
		||||
 | 
			
		||||
 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 | 
			
		||||
 Everyone is permitted to copy and distribute verbatim copies
 | 
			
		||||
 of this license document, but changing it is not allowed.
 | 
			
		||||
 | 
			
		||||
                            Preamble
 | 
			
		||||
 | 
			
		||||
  The GNU General Public License is a free, copyleft license for
 | 
			
		||||
software and other kinds of works.
 | 
			
		||||
 | 
			
		||||
  The licenses for most software and other practical works are designed
 | 
			
		||||
to take away your freedom to share and change the works.  By contrast,
 | 
			
		||||
the GNU General Public License is intended to guarantee your freedom to
 | 
			
		||||
share and change all versions of a program--to make sure it remains free
 | 
			
		||||
software for all its users.  We, the Free Software Foundation, use the
 | 
			
		||||
GNU General Public License for most of our software; it applies also to
 | 
			
		||||
any other work released this way by its authors.  You can apply it to
 | 
			
		||||
your programs, too.
 | 
			
		||||
 | 
			
		||||
  When we speak of free software, we are referring to freedom, not
 | 
			
		||||
price.  Our General Public Licenses are designed to make sure that you
 | 
			
		||||
have the freedom to distribute copies of free software (and charge for
 | 
			
		||||
them if you wish), that you receive source code or can get it if you
 | 
			
		||||
want it, that you can change the software or use pieces of it in new
 | 
			
		||||
free programs, and that you know you can do these things.
 | 
			
		||||
 | 
			
		||||
  To protect your rights, we need to prevent others from denying you
 | 
			
		||||
these rights or asking you to surrender the rights.  Therefore, you have
 | 
			
		||||
certain responsibilities if you distribute copies of the software, or if
 | 
			
		||||
you modify it: responsibilities to respect the freedom of others.
 | 
			
		||||
 | 
			
		||||
  For example, if you distribute copies of such a program, whether
 | 
			
		||||
gratis or for a fee, you must pass on to the recipients the same
 | 
			
		||||
freedoms that you received.  You must make sure that they, too, receive
 | 
			
		||||
or can get the source code.  And you must show them these terms so they
 | 
			
		||||
know their rights.
 | 
			
		||||
 | 
			
		||||
  Developers that use the GNU GPL protect your rights with two steps:
 | 
			
		||||
(1) assert copyright on the software, and (2) offer you this License
 | 
			
		||||
giving you legal permission to copy, distribute and/or modify it.
 | 
			
		||||
 | 
			
		||||
  For the developers' and authors' protection, the GPL clearly explains
 | 
			
		||||
that there is no warranty for this free software.  For both users' and
 | 
			
		||||
authors' sake, the GPL requires that modified versions be marked as
 | 
			
		||||
changed, so that their problems will not be attributed erroneously to
 | 
			
		||||
authors of previous versions.
 | 
			
		||||
 | 
			
		||||
  Some devices are designed to deny users access to install or run
 | 
			
		||||
modified versions of the software inside them, although the manufacturer
 | 
			
		||||
can do so.  This is fundamentally incompatible with the aim of
 | 
			
		||||
protecting users' freedom to change the software.  The systematic
 | 
			
		||||
pattern of such abuse occurs in the area of products for individuals to
 | 
			
		||||
use, which is precisely where it is most unacceptable.  Therefore, we
 | 
			
		||||
have designed this version of the GPL to prohibit the practice for those
 | 
			
		||||
products.  If such problems arise substantially in other domains, we
 | 
			
		||||
stand ready to extend this provision to those domains in future versions
 | 
			
		||||
of the GPL, as needed to protect the freedom of users.
 | 
			
		||||
 | 
			
		||||
  Finally, every program is threatened constantly by software patents.
 | 
			
		||||
States should not allow patents to restrict development and use of
 | 
			
		||||
software on general-purpose computers, but in those that do, we wish to
 | 
			
		||||
avoid the special danger that patents applied to a free program could
 | 
			
		||||
make it effectively proprietary.  To prevent this, the GPL assures that
 | 
			
		||||
patents cannot be used to render the program non-free.
 | 
			
		||||
 | 
			
		||||
  The precise terms and conditions for copying, distribution and
 | 
			
		||||
modification follow.
 | 
			
		||||
 | 
			
		||||
                       TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
  0. Definitions.
 | 
			
		||||
 | 
			
		||||
  "This License" refers to version 3 of the GNU General Public License.
 | 
			
		||||
 | 
			
		||||
  "Copyright" also means copyright-like laws that apply to other kinds of
 | 
			
		||||
works, such as semiconductor masks.
 | 
			
		||||
 | 
			
		||||
  "The Program" refers to any copyrightable work licensed under this
 | 
			
		||||
License.  Each licensee is addressed as "you".  "Licensees" and
 | 
			
		||||
"recipients" may be individuals or organizations.
 | 
			
		||||
 | 
			
		||||
  To "modify" a work means to copy from or adapt all or part of the work
 | 
			
		||||
in a fashion requiring copyright permission, other than the making of an
 | 
			
		||||
exact copy.  The resulting work is called a "modified version" of the
 | 
			
		||||
earlier work or a work "based on" the earlier work.
 | 
			
		||||
 | 
			
		||||
  A "covered work" means either the unmodified Program or a work based
 | 
			
		||||
on the Program.
 | 
			
		||||
 | 
			
		||||
  To "propagate" a work means to do anything with it that, without
 | 
			
		||||
permission, would make you directly or secondarily liable for
 | 
			
		||||
infringement under applicable copyright law, except executing it on a
 | 
			
		||||
computer or modifying a private copy.  Propagation includes copying,
 | 
			
		||||
distribution (with or without modification), making available to the
 | 
			
		||||
public, and in some countries other activities as well.
 | 
			
		||||
 | 
			
		||||
  To "convey" a work means any kind of propagation that enables other
 | 
			
		||||
parties to make or receive copies.  Mere interaction with a user through
 | 
			
		||||
a computer network, with no transfer of a copy, is not conveying.
 | 
			
		||||
 | 
			
		||||
  An interactive user interface displays "Appropriate Legal Notices"
 | 
			
		||||
to the extent that it includes a convenient and prominently visible
 | 
			
		||||
feature that (1) displays an appropriate copyright notice, and (2)
 | 
			
		||||
tells the user that there is no warranty for the work (except to the
 | 
			
		||||
extent that warranties are provided), that licensees may convey the
 | 
			
		||||
work under this License, and how to view a copy of this License.  If
 | 
			
		||||
the interface presents a list of user commands or options, such as a
 | 
			
		||||
menu, a prominent item in the list meets this criterion.
 | 
			
		||||
 | 
			
		||||
  1. Source Code.
 | 
			
		||||
 | 
			
		||||
  The "source code" for a work means the preferred form of the work
 | 
			
		||||
for making modifications to it.  "Object code" means any non-source
 | 
			
		||||
form of a work.
 | 
			
		||||
 | 
			
		||||
  A "Standard Interface" means an interface that either is an official
 | 
			
		||||
standard defined by a recognized standards body, or, in the case of
 | 
			
		||||
interfaces specified for a particular programming language, one that
 | 
			
		||||
is widely used among developers working in that language.
 | 
			
		||||
 | 
			
		||||
  The "System Libraries" of an executable work include anything, other
 | 
			
		||||
than the work as a whole, that (a) is included in the normal form of
 | 
			
		||||
packaging a Major Component, but which is not part of that Major
 | 
			
		||||
Component, and (b) serves only to enable use of the work with that
 | 
			
		||||
Major Component, or to implement a Standard Interface for which an
 | 
			
		||||
implementation is available to the public in source code form.  A
 | 
			
		||||
"Major Component", in this context, means a major essential component
 | 
			
		||||
(kernel, window system, and so on) of the specific operating system
 | 
			
		||||
(if any) on which the executable work runs, or a compiler used to
 | 
			
		||||
produce the work, or an object code interpreter used to run it.
 | 
			
		||||
 | 
			
		||||
  The "Corresponding Source" for a work in object code form means all
 | 
			
		||||
the source code needed to generate, install, and (for an executable
 | 
			
		||||
work) run the object code and to modify the work, including scripts to
 | 
			
		||||
control those activities.  However, it does not include the work's
 | 
			
		||||
System Libraries, or general-purpose tools or generally available free
 | 
			
		||||
programs which are used unmodified in performing those activities but
 | 
			
		||||
which are not part of the work.  For example, Corresponding Source
 | 
			
		||||
includes interface definition files associated with source files for
 | 
			
		||||
the work, and the source code for shared libraries and dynamically
 | 
			
		||||
linked subprograms that the work is specifically designed to require,
 | 
			
		||||
such as by intimate data communication or control flow between those
 | 
			
		||||
subprograms and other parts of the work.
 | 
			
		||||
 | 
			
		||||
  The Corresponding Source need not include anything that users
 | 
			
		||||
can regenerate automatically from other parts of the Corresponding
 | 
			
		||||
Source.
 | 
			
		||||
 | 
			
		||||
  The Corresponding Source for a work in source code form is that
 | 
			
		||||
same work.
 | 
			
		||||
 | 
			
		||||
  2. Basic Permissions.
 | 
			
		||||
 | 
			
		||||
  All rights granted under this License are granted for the term of
 | 
			
		||||
copyright on the Program, and are irrevocable provided the stated
 | 
			
		||||
conditions are met.  This License explicitly affirms your unlimited
 | 
			
		||||
permission to run the unmodified Program.  The output from running a
 | 
			
		||||
covered work is covered by this License only if the output, given its
 | 
			
		||||
content, constitutes a covered work.  This License acknowledges your
 | 
			
		||||
rights of fair use or other equivalent, as provided by copyright law.
 | 
			
		||||
 | 
			
		||||
  You may make, run and propagate covered works that you do not
 | 
			
		||||
convey, without conditions so long as your license otherwise remains
 | 
			
		||||
in force.  You may convey covered works to others for the sole purpose
 | 
			
		||||
of having them make modifications exclusively for you, or provide you
 | 
			
		||||
with facilities for running those works, provided that you comply with
 | 
			
		||||
the terms of this License in conveying all material for which you do
 | 
			
		||||
not control copyright.  Those thus making or running the covered works
 | 
			
		||||
for you must do so exclusively on your behalf, under your direction
 | 
			
		||||
and control, on terms that prohibit them from making any copies of
 | 
			
		||||
your copyrighted material outside their relationship with you.
 | 
			
		||||
 | 
			
		||||
  Conveying under any other circumstances is permitted solely under
 | 
			
		||||
the conditions stated below.  Sublicensing is not allowed; section 10
 | 
			
		||||
makes it unnecessary.
 | 
			
		||||
 | 
			
		||||
  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
 | 
			
		||||
 | 
			
		||||
  No covered work shall be deemed part of an effective technological
 | 
			
		||||
measure under any applicable law fulfilling obligations under article
 | 
			
		||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
 | 
			
		||||
similar laws prohibiting or restricting circumvention of such
 | 
			
		||||
measures.
 | 
			
		||||
 | 
			
		||||
  When you convey a covered work, you waive any legal power to forbid
 | 
			
		||||
circumvention of technological measures to the extent such circumvention
 | 
			
		||||
is effected by exercising rights under this License with respect to
 | 
			
		||||
the covered work, and you disclaim any intention to limit operation or
 | 
			
		||||
modification of the work as a means of enforcing, against the work's
 | 
			
		||||
users, your or third parties' legal rights to forbid circumvention of
 | 
			
		||||
technological measures.
 | 
			
		||||
 | 
			
		||||
  4. Conveying Verbatim Copies.
 | 
			
		||||
 | 
			
		||||
  You may convey verbatim copies of the Program's source code as you
 | 
			
		||||
receive it, in any medium, provided that you conspicuously and
 | 
			
		||||
appropriately publish on each copy an appropriate copyright notice;
 | 
			
		||||
keep intact all notices stating that this License and any
 | 
			
		||||
non-permissive terms added in accord with section 7 apply to the code;
 | 
			
		||||
keep intact all notices of the absence of any warranty; and give all
 | 
			
		||||
recipients a copy of this License along with the Program.
 | 
			
		||||
 | 
			
		||||
  You may charge any price or no price for each copy that you convey,
 | 
			
		||||
and you may offer support or warranty protection for a fee.
 | 
			
		||||
 | 
			
		||||
  5. Conveying Modified Source Versions.
 | 
			
		||||
 | 
			
		||||
  You may convey a work based on the Program, or the modifications to
 | 
			
		||||
produce it from the Program, in the form of source code under the
 | 
			
		||||
terms of section 4, provided that you also meet all of these conditions:
 | 
			
		||||
 | 
			
		||||
    a) The work must carry prominent notices stating that you modified
 | 
			
		||||
    it, and giving a relevant date.
 | 
			
		||||
 | 
			
		||||
    b) The work must carry prominent notices stating that it is
 | 
			
		||||
    released under this License and any conditions added under section
 | 
			
		||||
    7.  This requirement modifies the requirement in section 4 to
 | 
			
		||||
    "keep intact all notices".
 | 
			
		||||
 | 
			
		||||
    c) You must license the entire work, as a whole, under this
 | 
			
		||||
    License to anyone who comes into possession of a copy.  This
 | 
			
		||||
    License will therefore apply, along with any applicable section 7
 | 
			
		||||
    additional terms, to the whole of the work, and all its parts,
 | 
			
		||||
    regardless of how they are packaged.  This License gives no
 | 
			
		||||
    permission to license the work in any other way, but it does not
 | 
			
		||||
    invalidate such permission if you have separately received it.
 | 
			
		||||
 | 
			
		||||
    d) If the work has interactive user interfaces, each must display
 | 
			
		||||
    Appropriate Legal Notices; however, if the Program has interactive
 | 
			
		||||
    interfaces that do not display Appropriate Legal Notices, your
 | 
			
		||||
    work need not make them do so.
 | 
			
		||||
 | 
			
		||||
  A compilation of a covered work with other separate and independent
 | 
			
		||||
works, which are not by their nature extensions of the covered work,
 | 
			
		||||
and which are not combined with it such as to form a larger program,
 | 
			
		||||
in or on a volume of a storage or distribution medium, is called an
 | 
			
		||||
"aggregate" if the compilation and its resulting copyright are not
 | 
			
		||||
used to limit the access or legal rights of the compilation's users
 | 
			
		||||
beyond what the individual works permit.  Inclusion of a covered work
 | 
			
		||||
in an aggregate does not cause this License to apply to the other
 | 
			
		||||
parts of the aggregate.
 | 
			
		||||
 | 
			
		||||
  6. Conveying Non-Source Forms.
 | 
			
		||||
 | 
			
		||||
  You may convey a covered work in object code form under the terms
 | 
			
		||||
of sections 4 and 5, provided that you also convey the
 | 
			
		||||
machine-readable Corresponding Source under the terms of this License,
 | 
			
		||||
in one of these ways:
 | 
			
		||||
 | 
			
		||||
    a) Convey the object code in, or embodied in, a physical product
 | 
			
		||||
    (including a physical distribution medium), accompanied by the
 | 
			
		||||
    Corresponding Source fixed on a durable physical medium
 | 
			
		||||
    customarily used for software interchange.
 | 
			
		||||
 | 
			
		||||
    b) Convey the object code in, or embodied in, a physical product
 | 
			
		||||
    (including a physical distribution medium), accompanied by a
 | 
			
		||||
    written offer, valid for at least three years and valid for as
 | 
			
		||||
    long as you offer spare parts or customer support for that product
 | 
			
		||||
    model, to give anyone who possesses the object code either (1) a
 | 
			
		||||
    copy of the Corresponding Source for all the software in the
 | 
			
		||||
    product that is covered by this License, on a durable physical
 | 
			
		||||
    medium customarily used for software interchange, for a price no
 | 
			
		||||
    more than your reasonable cost of physically performing this
 | 
			
		||||
    conveying of source, or (2) access to copy the
 | 
			
		||||
    Corresponding Source from a network server at no charge.
 | 
			
		||||
 | 
			
		||||
    c) Convey individual copies of the object code with a copy of the
 | 
			
		||||
    written offer to provide the Corresponding Source.  This
 | 
			
		||||
    alternative is allowed only occasionally and noncommercially, and
 | 
			
		||||
    only if you received the object code with such an offer, in accord
 | 
			
		||||
    with subsection 6b.
 | 
			
		||||
 | 
			
		||||
    d) Convey the object code by offering access from a designated
 | 
			
		||||
    place (gratis or for a charge), and offer equivalent access to the
 | 
			
		||||
    Corresponding Source in the same way through the same place at no
 | 
			
		||||
    further charge.  You need not require recipients to copy the
 | 
			
		||||
    Corresponding Source along with the object code.  If the place to
 | 
			
		||||
    copy the object code is a network server, the Corresponding Source
 | 
			
		||||
    may be on a different server (operated by you or a third party)
 | 
			
		||||
    that supports equivalent copying facilities, provided you maintain
 | 
			
		||||
    clear directions next to the object code saying where to find the
 | 
			
		||||
    Corresponding Source.  Regardless of what server hosts the
 | 
			
		||||
    Corresponding Source, you remain obligated to ensure that it is
 | 
			
		||||
    available for as long as needed to satisfy these requirements.
 | 
			
		||||
 | 
			
		||||
    e) Convey the object code using peer-to-peer transmission, provided
 | 
			
		||||
    you inform other peers where the object code and Corresponding
 | 
			
		||||
    Source of the work are being offered to the general public at no
 | 
			
		||||
    charge under subsection 6d.
 | 
			
		||||
 | 
			
		||||
  A separable portion of the object code, whose source code is excluded
 | 
			
		||||
from the Corresponding Source as a System Library, need not be
 | 
			
		||||
included in conveying the object code work.
 | 
			
		||||
 | 
			
		||||
  A "User Product" is either (1) a "consumer product", which means any
 | 
			
		||||
tangible personal property which is normally used for personal, family,
 | 
			
		||||
or household purposes, or (2) anything designed or sold for incorporation
 | 
			
		||||
into a dwelling.  In determining whether a product is a consumer product,
 | 
			
		||||
doubtful cases shall be resolved in favor of coverage.  For a particular
 | 
			
		||||
product received by a particular user, "normally used" refers to a
 | 
			
		||||
typical or common use of that class of product, regardless of the status
 | 
			
		||||
of the particular user or of the way in which the particular user
 | 
			
		||||
actually uses, or expects or is expected to use, the product.  A product
 | 
			
		||||
is a consumer product regardless of whether the product has substantial
 | 
			
		||||
commercial, industrial or non-consumer uses, unless such uses represent
 | 
			
		||||
the only significant mode of use of the product.
 | 
			
		||||
 | 
			
		||||
  "Installation Information" for a User Product means any methods,
 | 
			
		||||
procedures, authorization keys, or other information required to install
 | 
			
		||||
and execute modified versions of a covered work in that User Product from
 | 
			
		||||
a modified version of its Corresponding Source.  The information must
 | 
			
		||||
suffice to ensure that the continued functioning of the modified object
 | 
			
		||||
code is in no case prevented or interfered with solely because
 | 
			
		||||
modification has been made.
 | 
			
		||||
 | 
			
		||||
  If you convey an object code work under this section in, or with, or
 | 
			
		||||
specifically for use in, a User Product, and the conveying occurs as
 | 
			
		||||
part of a transaction in which the right of possession and use of the
 | 
			
		||||
User Product is transferred to the recipient in perpetuity or for a
 | 
			
		||||
fixed term (regardless of how the transaction is characterized), the
 | 
			
		||||
Corresponding Source conveyed under this section must be accompanied
 | 
			
		||||
by the Installation Information.  But this requirement does not apply
 | 
			
		||||
if neither you nor any third party retains the ability to install
 | 
			
		||||
modified object code on the User Product (for example, the work has
 | 
			
		||||
been installed in ROM).
 | 
			
		||||
 | 
			
		||||
  The requirement to provide Installation Information does not include a
 | 
			
		||||
requirement to continue to provide support service, warranty, or updates
 | 
			
		||||
for a work that has been modified or installed by the recipient, or for
 | 
			
		||||
the User Product in which it has been modified or installed.  Access to a
 | 
			
		||||
network may be denied when the modification itself materially and
 | 
			
		||||
adversely affects the operation of the network or violates the rules and
 | 
			
		||||
protocols for communication across the network.
 | 
			
		||||
 | 
			
		||||
  Corresponding Source conveyed, and Installation Information provided,
 | 
			
		||||
in accord with this section must be in a format that is publicly
 | 
			
		||||
documented (and with an implementation available to the public in
 | 
			
		||||
source code form), and must require no special password or key for
 | 
			
		||||
unpacking, reading or copying.
 | 
			
		||||
 | 
			
		||||
  7. Additional Terms.
 | 
			
		||||
 | 
			
		||||
  "Additional permissions" are terms that supplement the terms of this
 | 
			
		||||
License by making exceptions from one or more of its conditions.
 | 
			
		||||
Additional permissions that are applicable to the entire Program shall
 | 
			
		||||
be treated as though they were included in this License, to the extent
 | 
			
		||||
that they are valid under applicable law.  If additional permissions
 | 
			
		||||
apply only to part of the Program, that part may be used separately
 | 
			
		||||
under those permissions, but the entire Program remains governed by
 | 
			
		||||
this License without regard to the additional permissions.
 | 
			
		||||
 | 
			
		||||
  When you convey a copy of a covered work, you may at your option
 | 
			
		||||
remove any additional permissions from that copy, or from any part of
 | 
			
		||||
it.  (Additional permissions may be written to require their own
 | 
			
		||||
removal in certain cases when you modify the work.)  You may place
 | 
			
		||||
additional permissions on material, added by you to a covered work,
 | 
			
		||||
for which you have or can give appropriate copyright permission.
 | 
			
		||||
 | 
			
		||||
  Notwithstanding any other provision of this License, for material you
 | 
			
		||||
add to a covered work, you may (if authorized by the copyright holders of
 | 
			
		||||
that material) supplement the terms of this License with terms:
 | 
			
		||||
 | 
			
		||||
    a) Disclaiming warranty or limiting liability differently from the
 | 
			
		||||
    terms of sections 15 and 16 of this License; or
 | 
			
		||||
 | 
			
		||||
    b) Requiring preservation of specified reasonable legal notices or
 | 
			
		||||
    author attributions in that material or in the Appropriate Legal
 | 
			
		||||
    Notices displayed by works containing it; or
 | 
			
		||||
 | 
			
		||||
    c) Prohibiting misrepresentation of the origin of that material, or
 | 
			
		||||
    requiring that modified versions of such material be marked in
 | 
			
		||||
    reasonable ways as different from the original version; or
 | 
			
		||||
 | 
			
		||||
    d) Limiting the use for publicity purposes of names of licensors or
 | 
			
		||||
    authors of the material; or
 | 
			
		||||
 | 
			
		||||
    e) Declining to grant rights under trademark law for use of some
 | 
			
		||||
    trade names, trademarks, or service marks; or
 | 
			
		||||
 | 
			
		||||
    f) Requiring indemnification of licensors and authors of that
 | 
			
		||||
    material by anyone who conveys the material (or modified versions of
 | 
			
		||||
    it) with contractual assumptions of liability to the recipient, for
 | 
			
		||||
    any liability that these contractual assumptions directly impose on
 | 
			
		||||
    those licensors and authors.
 | 
			
		||||
 | 
			
		||||
  All other non-permissive additional terms are considered "further
 | 
			
		||||
restrictions" within the meaning of section 10.  If the Program as you
 | 
			
		||||
received it, or any part of it, contains a notice stating that it is
 | 
			
		||||
governed by this License along with a term that is a further
 | 
			
		||||
restriction, you may remove that term.  If a license document contains
 | 
			
		||||
a further restriction but permits relicensing or conveying under this
 | 
			
		||||
License, you may add to a covered work material governed by the terms
 | 
			
		||||
of that license document, provided that the further restriction does
 | 
			
		||||
not survive such relicensing or conveying.
 | 
			
		||||
 | 
			
		||||
  If you add terms to a covered work in accord with this section, you
 | 
			
		||||
must place, in the relevant source files, a statement of the
 | 
			
		||||
additional terms that apply to those files, or a notice indicating
 | 
			
		||||
where to find the applicable terms.
 | 
			
		||||
 | 
			
		||||
  Additional terms, permissive or non-permissive, may be stated in the
 | 
			
		||||
form of a separately written license, or stated as exceptions;
 | 
			
		||||
the above requirements apply either way.
 | 
			
		||||
 | 
			
		||||
  8. Termination.
 | 
			
		||||
 | 
			
		||||
  You may not propagate or modify a covered work except as expressly
 | 
			
		||||
provided under this License.  Any attempt otherwise to propagate or
 | 
			
		||||
modify it is void, and will automatically terminate your rights under
 | 
			
		||||
this License (including any patent licenses granted under the third
 | 
			
		||||
paragraph of section 11).
 | 
			
		||||
 | 
			
		||||
  However, if you cease all violation of this License, then your
 | 
			
		||||
license from a particular copyright holder is reinstated (a)
 | 
			
		||||
provisionally, unless and until the copyright holder explicitly and
 | 
			
		||||
finally terminates your license, and (b) permanently, if the copyright
 | 
			
		||||
holder fails to notify you of the violation by some reasonable means
 | 
			
		||||
prior to 60 days after the cessation.
 | 
			
		||||
 | 
			
		||||
  Moreover, your license from a particular copyright holder is
 | 
			
		||||
reinstated permanently if the copyright holder notifies you of the
 | 
			
		||||
violation by some reasonable means, this is the first time you have
 | 
			
		||||
received notice of violation of this License (for any work) from that
 | 
			
		||||
copyright holder, and you cure the violation prior to 30 days after
 | 
			
		||||
your receipt of the notice.
 | 
			
		||||
 | 
			
		||||
  Termination of your rights under this section does not terminate the
 | 
			
		||||
licenses of parties who have received copies or rights from you under
 | 
			
		||||
this License.  If your rights have been terminated and not permanently
 | 
			
		||||
reinstated, you do not qualify to receive new licenses for the same
 | 
			
		||||
material under section 10.
 | 
			
		||||
 | 
			
		||||
  9. Acceptance Not Required for Having Copies.
 | 
			
		||||
 | 
			
		||||
  You are not required to accept this License in order to receive or
 | 
			
		||||
run a copy of the Program.  Ancillary propagation of a covered work
 | 
			
		||||
occurring solely as a consequence of using peer-to-peer transmission
 | 
			
		||||
to receive a copy likewise does not require acceptance.  However,
 | 
			
		||||
nothing other than this License grants you permission to propagate or
 | 
			
		||||
modify any covered work.  These actions infringe copyright if you do
 | 
			
		||||
not accept this License.  Therefore, by modifying or propagating a
 | 
			
		||||
covered work, you indicate your acceptance of this License to do so.
 | 
			
		||||
 | 
			
		||||
  10. Automatic Licensing of Downstream Recipients.
 | 
			
		||||
 | 
			
		||||
  Each time you convey a covered work, the recipient automatically
 | 
			
		||||
receives a license from the original licensors, to run, modify and
 | 
			
		||||
propagate that work, subject to this License.  You are not responsible
 | 
			
		||||
for enforcing compliance by third parties with this License.
 | 
			
		||||
 | 
			
		||||
  An "entity transaction" is a transaction transferring control of an
 | 
			
		||||
organization, or substantially all assets of one, or subdividing an
 | 
			
		||||
organization, or merging organizations.  If propagation of a covered
 | 
			
		||||
work results from an entity transaction, each party to that
 | 
			
		||||
transaction who receives a copy of the work also receives whatever
 | 
			
		||||
licenses to the work the party's predecessor in interest had or could
 | 
			
		||||
give under the previous paragraph, plus a right to possession of the
 | 
			
		||||
Corresponding Source of the work from the predecessor in interest, if
 | 
			
		||||
the predecessor has it or can get it with reasonable efforts.
 | 
			
		||||
 | 
			
		||||
  You may not impose any further restrictions on the exercise of the
 | 
			
		||||
rights granted or affirmed under this License.  For example, you may
 | 
			
		||||
not impose a license fee, royalty, or other charge for exercise of
 | 
			
		||||
rights granted under this License, and you may not initiate litigation
 | 
			
		||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
 | 
			
		||||
any patent claim is infringed by making, using, selling, offering for
 | 
			
		||||
sale, or importing the Program or any portion of it.
 | 
			
		||||
 | 
			
		||||
  11. Patents.
 | 
			
		||||
 | 
			
		||||
  A "contributor" is a copyright holder who authorizes use under this
 | 
			
		||||
License of the Program or a work on which the Program is based.  The
 | 
			
		||||
work thus licensed is called the contributor's "contributor version".
 | 
			
		||||
 | 
			
		||||
  A contributor's "essential patent claims" are all patent claims
 | 
			
		||||
owned or controlled by the contributor, whether already acquired or
 | 
			
		||||
hereafter acquired, that would be infringed by some manner, permitted
 | 
			
		||||
by this License, of making, using, or selling its contributor version,
 | 
			
		||||
but do not include claims that would be infringed only as a
 | 
			
		||||
consequence of further modification of the contributor version.  For
 | 
			
		||||
purposes of this definition, "control" includes the right to grant
 | 
			
		||||
patent sublicenses in a manner consistent with the requirements of
 | 
			
		||||
this License.
 | 
			
		||||
 | 
			
		||||
  Each contributor grants you a non-exclusive, worldwide, royalty-free
 | 
			
		||||
patent license under the contributor's essential patent claims, to
 | 
			
		||||
make, use, sell, offer for sale, import and otherwise run, modify and
 | 
			
		||||
propagate the contents of its contributor version.
 | 
			
		||||
 | 
			
		||||
  In the following three paragraphs, a "patent license" is any express
 | 
			
		||||
agreement or commitment, however denominated, not to enforce a patent
 | 
			
		||||
(such as an express permission to practice a patent or covenant not to
 | 
			
		||||
sue for patent infringement).  To "grant" such a patent license to a
 | 
			
		||||
party means to make such an agreement or commitment not to enforce a
 | 
			
		||||
patent against the party.
 | 
			
		||||
 | 
			
		||||
  If you convey a covered work, knowingly relying on a patent license,
 | 
			
		||||
and the Corresponding Source of the work is not available for anyone
 | 
			
		||||
to copy, free of charge and under the terms of this License, through a
 | 
			
		||||
publicly available network server or other readily accessible means,
 | 
			
		||||
then you must either (1) cause the Corresponding Source to be so
 | 
			
		||||
available, or (2) arrange to deprive yourself of the benefit of the
 | 
			
		||||
patent license for this particular work, or (3) arrange, in a manner
 | 
			
		||||
consistent with the requirements of this License, to extend the patent
 | 
			
		||||
license to downstream recipients.  "Knowingly relying" means you have
 | 
			
		||||
actual knowledge that, but for the patent license, your conveying the
 | 
			
		||||
covered work in a country, or your recipient's use of the covered work
 | 
			
		||||
in a country, would infringe one or more identifiable patents in that
 | 
			
		||||
country that you have reason to believe are valid.
 | 
			
		||||
 | 
			
		||||
  If, pursuant to or in connection with a single transaction or
 | 
			
		||||
arrangement, you convey, or propagate by procuring conveyance of, a
 | 
			
		||||
covered work, and grant a patent license to some of the parties
 | 
			
		||||
receiving the covered work authorizing them to use, propagate, modify
 | 
			
		||||
or convey a specific copy of the covered work, then the patent license
 | 
			
		||||
you grant is automatically extended to all recipients of the covered
 | 
			
		||||
work and works based on it.
 | 
			
		||||
 | 
			
		||||
  A patent license is "discriminatory" if it does not include within
 | 
			
		||||
the scope of its coverage, prohibits the exercise of, or is
 | 
			
		||||
conditioned on the non-exercise of one or more of the rights that are
 | 
			
		||||
specifically granted under this License.  You may not convey a covered
 | 
			
		||||
work if you are a party to an arrangement with a third party that is
 | 
			
		||||
in the business of distributing software, under which you make payment
 | 
			
		||||
to the third party based on the extent of your activity of conveying
 | 
			
		||||
the work, and under which the third party grants, to any of the
 | 
			
		||||
parties who would receive the covered work from you, a discriminatory
 | 
			
		||||
patent license (a) in connection with copies of the covered work
 | 
			
		||||
conveyed by you (or copies made from those copies), or (b) primarily
 | 
			
		||||
for and in connection with specific products or compilations that
 | 
			
		||||
contain the covered work, unless you entered into that arrangement,
 | 
			
		||||
or that patent license was granted, prior to 28 March 2007.
 | 
			
		||||
 | 
			
		||||
  Nothing in this License shall be construed as excluding or limiting
 | 
			
		||||
any implied license or other defenses to infringement that may
 | 
			
		||||
otherwise be available to you under applicable patent law.
 | 
			
		||||
 | 
			
		||||
  12. No Surrender of Others' Freedom.
 | 
			
		||||
 | 
			
		||||
  If conditions are imposed on you (whether by court order, agreement or
 | 
			
		||||
otherwise) that contradict the conditions of this License, they do not
 | 
			
		||||
excuse you from the conditions of this License.  If you cannot convey a
 | 
			
		||||
covered work so as to satisfy simultaneously your obligations under this
 | 
			
		||||
License and any other pertinent obligations, then as a consequence you may
 | 
			
		||||
not convey it at all.  For example, if you agree to terms that obligate you
 | 
			
		||||
to collect a royalty for further conveying from those to whom you convey
 | 
			
		||||
the Program, the only way you could satisfy both those terms and this
 | 
			
		||||
License would be to refrain entirely from conveying the Program.
 | 
			
		||||
 | 
			
		||||
  13. Use with the GNU Affero General Public License.
 | 
			
		||||
 | 
			
		||||
  Notwithstanding any other provision of this License, you have
 | 
			
		||||
permission to link or combine any covered work with a work licensed
 | 
			
		||||
under version 3 of the GNU Affero General Public License into a single
 | 
			
		||||
combined work, and to convey the resulting work.  The terms of this
 | 
			
		||||
License will continue to apply to the part which is the covered work,
 | 
			
		||||
but the special requirements of the GNU Affero General Public License,
 | 
			
		||||
section 13, concerning interaction through a network will apply to the
 | 
			
		||||
combination as such.
 | 
			
		||||
 | 
			
		||||
  14. Revised Versions of this License.
 | 
			
		||||
 | 
			
		||||
  The Free Software Foundation may publish revised and/or new versions of
 | 
			
		||||
the GNU General Public License from time to time.  Such new versions will
 | 
			
		||||
be similar in spirit to the present version, but may differ in detail to
 | 
			
		||||
address new problems or concerns.
 | 
			
		||||
 | 
			
		||||
  Each version is given a distinguishing version number.  If the
 | 
			
		||||
Program specifies that a certain numbered version of the GNU General
 | 
			
		||||
Public License "or any later version" applies to it, you have the
 | 
			
		||||
option of following the terms and conditions either of that numbered
 | 
			
		||||
version or of any later version published by the Free Software
 | 
			
		||||
Foundation.  If the Program does not specify a version number of the
 | 
			
		||||
GNU General Public License, you may choose any version ever published
 | 
			
		||||
by the Free Software Foundation.
 | 
			
		||||
 | 
			
		||||
  If the Program specifies that a proxy can decide which future
 | 
			
		||||
versions of the GNU General Public License can be used, that proxy's
 | 
			
		||||
public statement of acceptance of a version permanently authorizes you
 | 
			
		||||
to choose that version for the Program.
 | 
			
		||||
 | 
			
		||||
  Later license versions may give you additional or different
 | 
			
		||||
permissions.  However, no additional obligations are imposed on any
 | 
			
		||||
author or copyright holder as a result of your choosing to follow a
 | 
			
		||||
later version.
 | 
			
		||||
 | 
			
		||||
  15. Disclaimer of Warranty.
 | 
			
		||||
 | 
			
		||||
  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
 | 
			
		||||
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
 | 
			
		||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
 | 
			
		||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
 | 
			
		||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 | 
			
		||||
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
 | 
			
		||||
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
 | 
			
		||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
 | 
			
		||||
 | 
			
		||||
  16. Limitation of Liability.
 | 
			
		||||
 | 
			
		||||
  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
 | 
			
		||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
 | 
			
		||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
 | 
			
		||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
 | 
			
		||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
 | 
			
		||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
 | 
			
		||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
 | 
			
		||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
 | 
			
		||||
SUCH DAMAGES.
 | 
			
		||||
 | 
			
		||||
  17. Interpretation of Sections 15 and 16.
 | 
			
		||||
 | 
			
		||||
  If the disclaimer of warranty and limitation of liability provided
 | 
			
		||||
above cannot be given local legal effect according to their terms,
 | 
			
		||||
reviewing courts shall apply local law that most closely approximates
 | 
			
		||||
an absolute waiver of all civil liability in connection with the
 | 
			
		||||
Program, unless a warranty or assumption of liability accompanies a
 | 
			
		||||
copy of the Program in return for a fee.
 | 
			
		||||
 | 
			
		||||
                     END OF TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
            How to Apply These Terms to Your New Programs
 | 
			
		||||
 | 
			
		||||
  If you develop a new program, and you want it to be of the greatest
 | 
			
		||||
possible use to the public, the best way to achieve this is to make it
 | 
			
		||||
free software which everyone can redistribute and change under these terms.
 | 
			
		||||
 | 
			
		||||
  To do so, attach the following notices to the program.  It is safest
 | 
			
		||||
to attach them to the start of each source file to most effectively
 | 
			
		||||
state the exclusion of warranty; and each file should have at least
 | 
			
		||||
the "copyright" line and a pointer to where the full notice is found.
 | 
			
		||||
 | 
			
		||||
    <one line to give the program's name and a brief idea of what it does.>
 | 
			
		||||
    Copyright (C) <year>  <name of author>
 | 
			
		||||
 | 
			
		||||
    This program is free software: you can redistribute it and/or modify
 | 
			
		||||
    it under the terms of the GNU General Public License as published by
 | 
			
		||||
    the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
    (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
    This program is distributed in the hope that it will be useful,
 | 
			
		||||
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
    GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
    You should have received a copy of the GNU General Public License
 | 
			
		||||
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
Also add information on how to contact you by electronic and paper mail.
 | 
			
		||||
 | 
			
		||||
  If the program does terminal interaction, make it output a short
 | 
			
		||||
notice like this when it starts in an interactive mode:
 | 
			
		||||
 | 
			
		||||
    <program>  Copyright (C) <year>  <name of author>
 | 
			
		||||
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
 | 
			
		||||
    This is free software, and you are welcome to redistribute it
 | 
			
		||||
    under certain conditions; type `show c' for details.
 | 
			
		||||
 | 
			
		||||
The hypothetical commands `show w' and `show c' should show the appropriate
 | 
			
		||||
parts of the General Public License.  Of course, your program's commands
 | 
			
		||||
might be different; for a GUI interface, you would use an "about box".
 | 
			
		||||
 | 
			
		||||
  You should also get your employer (if you work as a programmer) or school,
 | 
			
		||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
 | 
			
		||||
For more information on this, and how to apply and follow the GNU GPL, see
 | 
			
		||||
<http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
  The GNU General Public License does not permit incorporating your program
 | 
			
		||||
into proprietary programs.  If your program is a subroutine library, you
 | 
			
		||||
may consider it more useful to permit linking proprietary applications with
 | 
			
		||||
the library.  If this is what you want to do, use the GNU Lesser General
 | 
			
		||||
Public License instead of this License.  But first, please read
 | 
			
		||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
							
								
								
									
										146
									
								
								contracts/erc20/src/v08/LibERC20TokenV08.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								contracts/erc20/src/v08/LibERC20TokenV08.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,146 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2020 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.8.0;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/v08/errors/LibRichErrorsV08.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/v08/LibBytesV08.sol";
 | 
			
		||||
import "../IERC20Token.sol";
 | 
			
		||||
 | 
			
		||||
library LibERC20TokenV08 {
 | 
			
		||||
    bytes private constant DECIMALS_CALL_DATA = hex"313ce567";
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls `IERC20Token(token).approve()`.
 | 
			
		||||
    ///      Reverts if the return data is invalid or the call reverts.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @param spender The address that receives an allowance.
 | 
			
		||||
    /// @param allowance The allowance to set.
 | 
			
		||||
    function compatApprove(IERC20Token token, address spender, uint256 allowance) internal {
 | 
			
		||||
        bytes memory callData = abi.encodeCall(token.approve, (spender, allowance));
 | 
			
		||||
        _callWithOptionalBooleanResult(address(token), callData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls `IERC20Token(token).approve()` and sets the allowance to the
 | 
			
		||||
    ///      maximum if the current approval is not already >= an amount.
 | 
			
		||||
    ///      Reverts if the return data is invalid or the call reverts.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @param spender The address that receives an allowance.
 | 
			
		||||
    /// @param amount The minimum allowance needed.
 | 
			
		||||
    function approveIfBelow(IERC20Token token, address spender, uint256 amount) internal {
 | 
			
		||||
        if (token.allowance(address(this), spender) < amount) {
 | 
			
		||||
            compatApprove(token, spender, type(uint256).max);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls `IERC20Token(token).transfer()`.
 | 
			
		||||
    ///      Reverts if the return data is invalid or the call reverts.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @param to The address that receives the tokens
 | 
			
		||||
    /// @param amount Number of tokens to transfer.
 | 
			
		||||
    function compatTransfer(IERC20Token token, address to, uint256 amount) internal {
 | 
			
		||||
        bytes memory callData = abi.encodeCall(token.transfer, (to, amount));
 | 
			
		||||
        _callWithOptionalBooleanResult(address(token), callData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls `IERC20Token(token).transferFrom()`.
 | 
			
		||||
    ///      Reverts if the return data is invalid or the call reverts.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @param from The owner of the tokens.
 | 
			
		||||
    /// @param to The address that receives the tokens
 | 
			
		||||
    /// @param amount Number of tokens to transfer.
 | 
			
		||||
    function compatTransferFrom(IERC20Token token, address from, address to, uint256 amount) internal {
 | 
			
		||||
        bytes memory callData = abi.encodeCall(token.transferFrom, (from, to, amount));
 | 
			
		||||
        _callWithOptionalBooleanResult(address(token), callData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Retrieves the number of decimals for a token.
 | 
			
		||||
    ///      Returns `18` if the call reverts.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @return tokenDecimals The number of decimals places for the token.
 | 
			
		||||
    function compatDecimals(IERC20Token token) internal view returns (uint8 tokenDecimals) {
 | 
			
		||||
        tokenDecimals = 18;
 | 
			
		||||
        (bool didSucceed, bytes memory resultData) = address(token).staticcall(DECIMALS_CALL_DATA);
 | 
			
		||||
        if (didSucceed && resultData.length >= 32) {
 | 
			
		||||
            tokenDecimals = abi.decode(resultData, (uint8));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Retrieves the allowance for a token, owner, and spender.
 | 
			
		||||
    ///      Returns `0` if the call reverts.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @param owner The owner of the tokens.
 | 
			
		||||
    /// @param spender The address the spender.
 | 
			
		||||
    /// @return allowance_ The allowance for a token, owner, and spender.
 | 
			
		||||
    function compatAllowance(
 | 
			
		||||
        IERC20Token token,
 | 
			
		||||
        address owner,
 | 
			
		||||
        address spender
 | 
			
		||||
    ) internal view returns (uint256 allowance_) {
 | 
			
		||||
        (bool didSucceed, bytes memory resultData) = address(token).staticcall(
 | 
			
		||||
            abi.encodeCall(token.allowance, (owner, spender))
 | 
			
		||||
        );
 | 
			
		||||
        if (didSucceed && resultData.length >= 32) {
 | 
			
		||||
            allowance_ = abi.decode(resultData, (uint256));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Retrieves the balance for a token owner.
 | 
			
		||||
    ///      Returns `0` if the call reverts.
 | 
			
		||||
    /// @param token The address of the token contract.
 | 
			
		||||
    /// @param owner The owner of the tokens.
 | 
			
		||||
    /// @return balance The token balance of an owner.
 | 
			
		||||
    function compatBalanceOf(IERC20Token token, address owner) internal view returns (uint256 balance) {
 | 
			
		||||
        (bool didSucceed, bytes memory resultData) = address(token).staticcall(
 | 
			
		||||
            abi.encodeCall(token.balanceOf, (owner))
 | 
			
		||||
        );
 | 
			
		||||
        if (didSucceed && resultData.length >= 32) {
 | 
			
		||||
            balance = abi.decode(resultData, (uint256));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Executes a call on address `target` with calldata `callData`
 | 
			
		||||
    ///      and asserts that either nothing was returned or a single boolean
 | 
			
		||||
    ///      was returned equal to `true`.
 | 
			
		||||
    /// @param target The call target.
 | 
			
		||||
    /// @param callData The abi-encoded call data.
 | 
			
		||||
    function _callWithOptionalBooleanResult(address target, bytes memory callData) private {
 | 
			
		||||
        (bool didSucceed, bytes memory resultData) = target.call(callData);
 | 
			
		||||
        // Revert if the call reverted.
 | 
			
		||||
        if (!didSucceed) {
 | 
			
		||||
            LibRichErrorsV08.rrevert(resultData);
 | 
			
		||||
        }
 | 
			
		||||
        // If we get back 0 returndata, this may be a non-standard ERC-20 that
 | 
			
		||||
        // does not return a boolean. Check that it at least contains code.
 | 
			
		||||
        if (resultData.length == 0) {
 | 
			
		||||
            require(target.code.length > 0, "invalid token address, contains no code");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        // If we get back at least 32 bytes, we know the target address
 | 
			
		||||
        // contains code, and we assume it is a token that returned a boolean
 | 
			
		||||
        // success value, which must be true.
 | 
			
		||||
        if (resultData.length >= 32) {
 | 
			
		||||
            if (!abi.decode(resultData, (bool))) {
 | 
			
		||||
                LibRichErrorsV08.rrevert(resultData);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // If 0 < returndatasize < 32, the target is a contract, but not a
 | 
			
		||||
        // valid token.
 | 
			
		||||
        LibRichErrorsV08.rrevert(resultData);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,11 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 * Warning: This file is auto-generated by contracts-gen. Don't edit manually.
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
export * from '../generated-wrappers/dummy_erc20_token';
 | 
			
		||||
export * from '../generated-wrappers/dummy_multiple_return_erc20_token';
 | 
			
		||||
export * from '../generated-wrappers/dummy_no_return_erc20_token';
 | 
			
		||||
export * from '../generated-wrappers/erc20_token';
 | 
			
		||||
export * from '../generated-wrappers/weth9';
 | 
			
		||||
export * from '../generated-wrappers/zrx_token';
 | 
			
		||||
							
								
								
									
										76
									
								
								contracts/erc20/test/WETH9V06Test.t.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								contracts/erc20/test/WETH9V06Test.t.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,76 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
  Copyright 2023 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.6.5;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "forge-std/Test.sol";
 | 
			
		||||
import "../src/v06/WETH9V06.sol";
 | 
			
		||||
 | 
			
		||||
contract WETH9V06Test is Test {
 | 
			
		||||
    address payable internal owner = payable(vm.addr(1));
 | 
			
		||||
    address payable internal user = payable(vm.addr(2));
 | 
			
		||||
    WETH9V06 internal etherToken;
 | 
			
		||||
 | 
			
		||||
    function setUp() public {
 | 
			
		||||
        vm.deal(owner, 1e20);
 | 
			
		||||
        vm.deal(user, 1e20);
 | 
			
		||||
 | 
			
		||||
        etherToken = new WETH9V06();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldRevertIfCallerAttemptsToDepositMoreThanTheirBalance() public {
 | 
			
		||||
        vm.prank(user);
 | 
			
		||||
        vm.expectRevert();
 | 
			
		||||
        etherToken.deposit{value: 1e20 + 1}();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldConvertDepositedETHToWrappedETH() public {
 | 
			
		||||
        vm.prank(user);
 | 
			
		||||
        etherToken.deposit{value: 1e20}();
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        assertEq(etherToken.balanceOf(user), 1e20);
 | 
			
		||||
        assertEq(address(etherToken).balance, 1e20);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldRevertIfCallerAttemptsToWithdrawMoreThanTheirBalance() public {
 | 
			
		||||
        vm.prank(user);
 | 
			
		||||
        etherToken.deposit{value: 1e20}();
 | 
			
		||||
 | 
			
		||||
        vm.expectRevert();
 | 
			
		||||
        etherToken.withdraw(1e20 + 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldConvertWithdrawWrappedETHToETH() public {
 | 
			
		||||
        vm.prank(user);
 | 
			
		||||
        etherToken.deposit{value: 1e20}();
 | 
			
		||||
        vm.prank(user);
 | 
			
		||||
        etherToken.withdraw(100);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        assertEq(etherToken.balanceOf(user), 1e20 - 100);
 | 
			
		||||
        assertEq(address(etherToken).balance, 1e20 - 100);
 | 
			
		||||
        assertEq(user.balance, 100);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldConvertSentETHToWrappedETH() public {
 | 
			
		||||
        vm.prank(user);
 | 
			
		||||
        address(etherToken).call{value: 1e20}(new bytes(0));
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        assertEq(etherToken.balanceOf(user), 1e20);
 | 
			
		||||
        assertEq(address(etherToken).balance, 1e20);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										117
									
								
								contracts/erc20/test/ZRXTokenTest.t.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								contracts/erc20/test/ZRXTokenTest.t.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,117 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
  Copyright 2023 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.8.17;
 | 
			
		||||
 | 
			
		||||
import "forge-std/Test.sol";
 | 
			
		||||
import "../src/IERC20Token.sol";
 | 
			
		||||
 | 
			
		||||
contract ZRXTokenTest is Test {
 | 
			
		||||
    address payable internal owner = payable(vm.addr(1));
 | 
			
		||||
    address payable internal user = payable(vm.addr(2));
 | 
			
		||||
    address payable internal anotherUser = payable(vm.addr(3));
 | 
			
		||||
    uint256 internal totalSupply = 1_000_000_000 * 1e18;
 | 
			
		||||
    IERC20Token zrxToken;
 | 
			
		||||
 | 
			
		||||
    function setUp() public {
 | 
			
		||||
        vm.deal(owner, 1e20);
 | 
			
		||||
        vm.deal(user, 1e20);
 | 
			
		||||
 | 
			
		||||
        vm.prank(owner);
 | 
			
		||||
        bytes memory _bytecode = vm.getCode("./out/ZRXToken.sol/ZRXToken.json");
 | 
			
		||||
        address _address;
 | 
			
		||||
        assembly {
 | 
			
		||||
            _address := create(0, add(_bytecode, 0x20), mload(_bytecode))
 | 
			
		||||
        }
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
        zrxToken = IERC20Token(address(_address));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldHave18Decimals() public {
 | 
			
		||||
        assertEq(zrxToken.decimals(), 18);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldHaveTotalSupplyOf1Billion() public {
 | 
			
		||||
        assertEq(zrxToken.totalSupply(), totalSupply);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldInitializeOwnerBalanceToTotalSupply() public {
 | 
			
		||||
        assertEq(zrxToken.balanceOf(owner), totalSupply);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldTransferBalanceCorrectly() public {
 | 
			
		||||
        vm.prank(owner);
 | 
			
		||||
        zrxToken.transfer(user, 100);
 | 
			
		||||
 | 
			
		||||
        assertEq(zrxToken.balanceOf(user), 100);
 | 
			
		||||
        assertEq(zrxToken.balanceOf(owner), totalSupply - 100);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldReturnTrueOnAZeroValueTransfer() public {
 | 
			
		||||
        vm.prank(owner);
 | 
			
		||||
        bool success = zrxToken.transfer(user, 0);
 | 
			
		||||
        assertTrue(success);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldReturnTrueOnAZeroValueTransferByUserWithZeroBalance() public {
 | 
			
		||||
        vm.prank(anotherUser);
 | 
			
		||||
        bool success = zrxToken.transfer(user, 0);
 | 
			
		||||
        assertTrue(success);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldReturnFalseIfSenderHasInsufficientBalance() public {
 | 
			
		||||
        vm.prank(owner);
 | 
			
		||||
        zrxToken.approve(user, totalSupply + 1);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        bool success = zrxToken.transferFrom(owner, user, totalSupply + 1);
 | 
			
		||||
        assertEq(success, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldReturnFalseIfRecipientHasInsufficientAllowance() public {
 | 
			
		||||
        vm.prank(owner);
 | 
			
		||||
        zrxToken.approve(user, totalSupply - 1);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        bool success = zrxToken.transferFrom(owner, user, totalSupply);
 | 
			
		||||
        assertEq(success, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldReturnTrueOnAZeroValueApprovedTransfer() public {
 | 
			
		||||
        vm.prank(user);
 | 
			
		||||
        bool success = zrxToken.transferFrom(owner, user, 0);
 | 
			
		||||
        assertEq(success, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldNotModifySenderAllowanceIfSetToUINT256Max() public {
 | 
			
		||||
        vm.prank(owner);
 | 
			
		||||
        zrxToken.approve(user, type(uint256).max);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        zrxToken.transferFrom(owner, user, 100);
 | 
			
		||||
        assertEq(zrxToken.allowance(owner, user), type(uint256).max);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldTransferCorrectlyWhenSufficientAllowance() public {
 | 
			
		||||
        vm.prank(owner);
 | 
			
		||||
        zrxToken.approve(user, 1000 * 1e18);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        vm.prank(user);
 | 
			
		||||
        zrxToken.transferFrom(owner, user, 100 * 1e18);
 | 
			
		||||
        assertEq(zrxToken.allowance(owner, user), 900 * 1e18);
 | 
			
		||||
        assertEq(zrxToken.balanceOf(user), 100 * 1e18);
 | 
			
		||||
        assertEq(zrxToken.balanceOf(owner), totalSupply - 100 * 1e18);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,43 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 * Warning: This file is auto-generated by contracts-gen. Don't edit manually.
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
import { ContractArtifact } from 'ethereum-types';
 | 
			
		||||
 | 
			
		||||
import * as DummyERC20Token from '../test/generated-artifacts/DummyERC20Token.json';
 | 
			
		||||
import * as DummyMultipleReturnERC20Token from '../test/generated-artifacts/DummyMultipleReturnERC20Token.json';
 | 
			
		||||
import * as DummyNoReturnERC20Token from '../test/generated-artifacts/DummyNoReturnERC20Token.json';
 | 
			
		||||
import * as ERC20Token from '../test/generated-artifacts/ERC20Token.json';
 | 
			
		||||
import * as IERC20Token from '../test/generated-artifacts/IERC20Token.json';
 | 
			
		||||
import * as IERC20TokenV06 from '../test/generated-artifacts/IERC20TokenV06.json';
 | 
			
		||||
import * as IEtherToken from '../test/generated-artifacts/IEtherToken.json';
 | 
			
		||||
import * as IEtherTokenV06 from '../test/generated-artifacts/IEtherTokenV06.json';
 | 
			
		||||
import * as LibERC20Token from '../test/generated-artifacts/LibERC20Token.json';
 | 
			
		||||
import * as LibERC20TokenV06 from '../test/generated-artifacts/LibERC20TokenV06.json';
 | 
			
		||||
import * as MintableERC20Token from '../test/generated-artifacts/MintableERC20Token.json';
 | 
			
		||||
import * as TestLibERC20Token from '../test/generated-artifacts/TestLibERC20Token.json';
 | 
			
		||||
import * as TestLibERC20TokenTarget from '../test/generated-artifacts/TestLibERC20TokenTarget.json';
 | 
			
		||||
import * as UnlimitedAllowanceERC20Token from '../test/generated-artifacts/UnlimitedAllowanceERC20Token.json';
 | 
			
		||||
import * as UntransferrableDummyERC20Token from '../test/generated-artifacts/UntransferrableDummyERC20Token.json';
 | 
			
		||||
import * as WETH9 from '../test/generated-artifacts/WETH9.json';
 | 
			
		||||
import * as ZRXToken from '../test/generated-artifacts/ZRXToken.json';
 | 
			
		||||
export const artifacts = {
 | 
			
		||||
    ERC20Token: ERC20Token as ContractArtifact,
 | 
			
		||||
    LibERC20Token: LibERC20Token as ContractArtifact,
 | 
			
		||||
    MintableERC20Token: MintableERC20Token as ContractArtifact,
 | 
			
		||||
    UnlimitedAllowanceERC20Token: UnlimitedAllowanceERC20Token as ContractArtifact,
 | 
			
		||||
    WETH9: WETH9 as ContractArtifact,
 | 
			
		||||
    ZRXToken: ZRXToken as any as ContractArtifact,
 | 
			
		||||
    IERC20Token: IERC20Token as ContractArtifact,
 | 
			
		||||
    IEtherToken: IEtherToken as ContractArtifact,
 | 
			
		||||
    IERC20TokenV06: IERC20TokenV06 as ContractArtifact,
 | 
			
		||||
    IEtherTokenV06: IEtherTokenV06 as ContractArtifact,
 | 
			
		||||
    LibERC20TokenV06: LibERC20TokenV06 as ContractArtifact,
 | 
			
		||||
    DummyERC20Token: DummyERC20Token as ContractArtifact,
 | 
			
		||||
    DummyMultipleReturnERC20Token: DummyMultipleReturnERC20Token as ContractArtifact,
 | 
			
		||||
    DummyNoReturnERC20Token: DummyNoReturnERC20Token as ContractArtifact,
 | 
			
		||||
    TestLibERC20Token: TestLibERC20Token as ContractArtifact,
 | 
			
		||||
    TestLibERC20TokenTarget: TestLibERC20TokenTarget as ContractArtifact,
 | 
			
		||||
    UntransferrableDummyERC20Token: UntransferrableDummyERC20Token as ContractArtifact,
 | 
			
		||||
};
 | 
			
		||||
@@ -1,19 +0,0 @@
 | 
			
		||||
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();
 | 
			
		||||
});
 | 
			
		||||
@@ -1,335 +0,0 @@
 | 
			
		||||
import {
 | 
			
		||||
    blockchainTests,
 | 
			
		||||
    constants,
 | 
			
		||||
    expect,
 | 
			
		||||
    getRandomInteger,
 | 
			
		||||
    randomAddress,
 | 
			
		||||
    verifyEventsFromLogs,
 | 
			
		||||
} from '@0x/contracts-test-utils';
 | 
			
		||||
import { hexUtils, RawRevertError, StringRevertError } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
import { TestLibERC20TokenContract, TestLibERC20TokenTargetEvents } from './wrappers';
 | 
			
		||||
 | 
			
		||||
import { artifacts } from './artifacts';
 | 
			
		||||
 | 
			
		||||
blockchainTests('LibERC20Token', env => {
 | 
			
		||||
    let testContract: TestLibERC20TokenContract;
 | 
			
		||||
    const REVERT_STRING = 'WHOOPSIE';
 | 
			
		||||
    const ENCODED_REVERT = new StringRevertError(REVERT_STRING).encode();
 | 
			
		||||
    const ENCODED_TRUE = hexUtils.leftPad(1);
 | 
			
		||||
    const ENCODED_FALSE = hexUtils.leftPad(0);
 | 
			
		||||
    const ENCODED_TWO = hexUtils.leftPad(2);
 | 
			
		||||
    const ENCODED_SHORT_TRUE = hexUtils.leftPad(2, 31);
 | 
			
		||||
    const ENCODED_LONG_TRUE = hexUtils.leftPad(2, 33);
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        testContract = await TestLibERC20TokenContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.TestLibERC20Token,
 | 
			
		||||
            env.provider,
 | 
			
		||||
            env.txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('approve()', () => {
 | 
			
		||||
        it('calls the target with the correct arguments', async () => {
 | 
			
		||||
            const spender = randomAddress();
 | 
			
		||||
            const allowance = getRandomInteger(0, 100e18);
 | 
			
		||||
            const { logs } = await testContract
 | 
			
		||||
                .testApprove(false, ENCODED_REVERT, ENCODED_TRUE, spender, allowance)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            expect(logs).to.be.length(1);
 | 
			
		||||
            verifyEventsFromLogs(logs, [{ spender, allowance }], TestLibERC20TokenTargetEvents.ApproveCalled);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('succeeds if the target returns true', async () => {
 | 
			
		||||
            const spender = randomAddress();
 | 
			
		||||
            const allowance = getRandomInteger(0, 100e18);
 | 
			
		||||
            await testContract
 | 
			
		||||
                .testApprove(false, ENCODED_REVERT, ENCODED_TRUE, spender, allowance)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('succeeds if the target returns nothing', async () => {
 | 
			
		||||
            const spender = randomAddress();
 | 
			
		||||
            const allowance = getRandomInteger(0, 100e18);
 | 
			
		||||
            await testContract
 | 
			
		||||
                .testApprove(false, ENCODED_REVERT, constants.NULL_BYTES, spender, allowance)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if the target returns false', async () => {
 | 
			
		||||
            const spender = randomAddress();
 | 
			
		||||
            const allowance = getRandomInteger(0, 100e18);
 | 
			
		||||
            const tx = testContract
 | 
			
		||||
                .testApprove(false, ENCODED_REVERT, ENCODED_FALSE, spender, allowance)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            const expectedError = new RawRevertError(ENCODED_FALSE);
 | 
			
		||||
            return expect(tx).to.revertWith(expectedError);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if the target returns nonzero and not true', async () => {
 | 
			
		||||
            const spender = randomAddress();
 | 
			
		||||
            const allowance = getRandomInteger(0, 100e18);
 | 
			
		||||
            const tx = testContract
 | 
			
		||||
                .testApprove(false, ENCODED_REVERT, ENCODED_TWO, spender, allowance)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            const expectedError = new RawRevertError(ENCODED_TWO);
 | 
			
		||||
            return expect(tx).to.revertWith(expectedError);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if the target returns less than 32 bytes', async () => {
 | 
			
		||||
            const spender = randomAddress();
 | 
			
		||||
            const allowance = getRandomInteger(0, 100e18);
 | 
			
		||||
            const tx = testContract
 | 
			
		||||
                .testApprove(false, ENCODED_REVERT, ENCODED_SHORT_TRUE, spender, allowance)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            const expectedError = new RawRevertError(ENCODED_SHORT_TRUE);
 | 
			
		||||
            return expect(tx).to.revertWith(expectedError);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if the target returns greater than 32 bytes', async () => {
 | 
			
		||||
            const spender = randomAddress();
 | 
			
		||||
            const allowance = getRandomInteger(0, 100e18);
 | 
			
		||||
            const tx = testContract
 | 
			
		||||
                .testApprove(false, ENCODED_REVERT, ENCODED_LONG_TRUE, spender, allowance)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            const expectedError = new RawRevertError(ENCODED_LONG_TRUE);
 | 
			
		||||
            return expect(tx).to.revertWith(expectedError);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if the target reverts', async () => {
 | 
			
		||||
            const spender = randomAddress();
 | 
			
		||||
            const allowance = getRandomInteger(0, 100e18);
 | 
			
		||||
            const tx = testContract
 | 
			
		||||
                .testApprove(true, ENCODED_REVERT, ENCODED_TRUE, spender, allowance)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            return expect(tx).to.revertWith(REVERT_STRING);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if the target reverts with no data', async () => {
 | 
			
		||||
            const spender = randomAddress();
 | 
			
		||||
            const allowance = getRandomInteger(0, 100e18);
 | 
			
		||||
            const tx = testContract
 | 
			
		||||
                .testApprove(true, constants.NULL_BYTES, ENCODED_TRUE, spender, allowance)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            return expect(tx).to.be.rejectedWith('revert');
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('transfer()', () => {
 | 
			
		||||
        it('calls the target with the correct arguments', async () => {
 | 
			
		||||
            const to = randomAddress();
 | 
			
		||||
            const amount = getRandomInteger(0, 100e18);
 | 
			
		||||
            const { logs } = await testContract
 | 
			
		||||
                .testTransfer(false, ENCODED_REVERT, ENCODED_TRUE, to, amount)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            expect(logs).to.be.length(1);
 | 
			
		||||
            verifyEventsFromLogs(logs, [{ to, amount }], TestLibERC20TokenTargetEvents.TransferCalled);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('succeeds if the target returns true', async () => {
 | 
			
		||||
            const to = randomAddress();
 | 
			
		||||
            const amount = getRandomInteger(0, 100e18);
 | 
			
		||||
            await testContract
 | 
			
		||||
                .testTransfer(false, ENCODED_REVERT, ENCODED_TRUE, to, amount)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('succeeds if the target returns nothing', async () => {
 | 
			
		||||
            const to = randomAddress();
 | 
			
		||||
            const amount = getRandomInteger(0, 100e18);
 | 
			
		||||
            await testContract
 | 
			
		||||
                .testTransfer(false, ENCODED_REVERT, constants.NULL_BYTES, to, amount)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if the target returns false', async () => {
 | 
			
		||||
            const to = randomAddress();
 | 
			
		||||
            const amount = getRandomInteger(0, 100e18);
 | 
			
		||||
            const tx = testContract
 | 
			
		||||
                .testTransfer(false, ENCODED_REVERT, ENCODED_FALSE, to, amount)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            const expectedError = new RawRevertError(ENCODED_FALSE);
 | 
			
		||||
            return expect(tx).to.revertWith(expectedError);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if the target returns nonzero and not true', async () => {
 | 
			
		||||
            const to = randomAddress();
 | 
			
		||||
            const amount = getRandomInteger(0, 100e18);
 | 
			
		||||
            const tx = testContract
 | 
			
		||||
                .testTransfer(false, ENCODED_REVERT, ENCODED_TWO, to, amount)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            const expectedError = new RawRevertError(ENCODED_TWO);
 | 
			
		||||
            return expect(tx).to.revertWith(expectedError);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if the target returns less than 32 bytes', async () => {
 | 
			
		||||
            const to = randomAddress();
 | 
			
		||||
            const amount = getRandomInteger(0, 100e18);
 | 
			
		||||
            const tx = testContract
 | 
			
		||||
                .testTransfer(false, ENCODED_REVERT, ENCODED_SHORT_TRUE, to, amount)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            const expectedError = new RawRevertError(ENCODED_SHORT_TRUE);
 | 
			
		||||
            return expect(tx).to.revertWith(expectedError);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if the target returns greater than 32 bytes', async () => {
 | 
			
		||||
            const to = randomAddress();
 | 
			
		||||
            const amount = getRandomInteger(0, 100e18);
 | 
			
		||||
            const tx = testContract
 | 
			
		||||
                .testTransfer(false, ENCODED_REVERT, ENCODED_LONG_TRUE, to, amount)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            const expectedError = new RawRevertError(ENCODED_LONG_TRUE);
 | 
			
		||||
            return expect(tx).to.revertWith(expectedError);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if the target reverts', async () => {
 | 
			
		||||
            const to = randomAddress();
 | 
			
		||||
            const amount = getRandomInteger(0, 100e18);
 | 
			
		||||
            const tx = testContract
 | 
			
		||||
                .testTransfer(true, ENCODED_REVERT, ENCODED_TRUE, to, amount)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            return expect(tx).to.revertWith(REVERT_STRING);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if the target reverts with no data', async () => {
 | 
			
		||||
            const to = randomAddress();
 | 
			
		||||
            const amount = getRandomInteger(0, 100e18);
 | 
			
		||||
            const tx = testContract
 | 
			
		||||
                .testTransfer(true, constants.NULL_BYTES, ENCODED_TRUE, to, amount)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            return expect(tx).to.be.rejectedWith('revert');
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('transferFrom()', () => {
 | 
			
		||||
        it('calls the target with the correct arguments', async () => {
 | 
			
		||||
            const owner = randomAddress();
 | 
			
		||||
            const to = randomAddress();
 | 
			
		||||
            const amount = getRandomInteger(0, 100e18);
 | 
			
		||||
            const { logs } = await testContract
 | 
			
		||||
                .testTransferFrom(false, ENCODED_REVERT, ENCODED_TRUE, owner, to, amount)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            expect(logs).to.be.length(1);
 | 
			
		||||
            verifyEventsFromLogs(logs, [{ from: owner, to, amount }], TestLibERC20TokenTargetEvents.TransferFromCalled);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('succeeds if the target returns true', async () => {
 | 
			
		||||
            const owner = randomAddress();
 | 
			
		||||
            const to = randomAddress();
 | 
			
		||||
            const amount = getRandomInteger(0, 100e18);
 | 
			
		||||
            await testContract
 | 
			
		||||
                .testTransferFrom(false, ENCODED_REVERT, ENCODED_TRUE, owner, to, amount)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('succeeds if the target returns nothing', async () => {
 | 
			
		||||
            const owner = randomAddress();
 | 
			
		||||
            const to = randomAddress();
 | 
			
		||||
            const amount = getRandomInteger(0, 100e18);
 | 
			
		||||
            await testContract
 | 
			
		||||
                .testTransferFrom(false, ENCODED_REVERT, constants.NULL_BYTES, owner, to, amount)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if the target returns false', async () => {
 | 
			
		||||
            const owner = randomAddress();
 | 
			
		||||
            const to = randomAddress();
 | 
			
		||||
            const amount = getRandomInteger(0, 100e18);
 | 
			
		||||
            const tx = testContract
 | 
			
		||||
                .testTransferFrom(false, ENCODED_REVERT, ENCODED_FALSE, owner, to, amount)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            const expectedError = new RawRevertError(ENCODED_FALSE);
 | 
			
		||||
            return expect(tx).to.revertWith(expectedError);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if the target returns nonzero and not true', async () => {
 | 
			
		||||
            const owner = randomAddress();
 | 
			
		||||
            const to = randomAddress();
 | 
			
		||||
            const amount = getRandomInteger(0, 100e18);
 | 
			
		||||
            const tx = testContract
 | 
			
		||||
                .testTransferFrom(false, ENCODED_REVERT, ENCODED_TWO, owner, to, amount)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            const expectedError = new RawRevertError(ENCODED_TWO);
 | 
			
		||||
            return expect(tx).to.revertWith(expectedError);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if the target returns less than 32 bytes', async () => {
 | 
			
		||||
            const owner = randomAddress();
 | 
			
		||||
            const to = randomAddress();
 | 
			
		||||
            const amount = getRandomInteger(0, 100e18);
 | 
			
		||||
            const tx = testContract
 | 
			
		||||
                .testTransferFrom(false, ENCODED_REVERT, ENCODED_SHORT_TRUE, owner, to, amount)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            const expectedError = new RawRevertError(ENCODED_SHORT_TRUE);
 | 
			
		||||
            return expect(tx).to.revertWith(expectedError);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if the target returns greater than 32 bytes', async () => {
 | 
			
		||||
            const owner = randomAddress();
 | 
			
		||||
            const to = randomAddress();
 | 
			
		||||
            const amount = getRandomInteger(0, 100e18);
 | 
			
		||||
            const tx = testContract
 | 
			
		||||
                .testTransferFrom(false, ENCODED_REVERT, ENCODED_LONG_TRUE, owner, to, amount)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            const expectedError = new RawRevertError(ENCODED_LONG_TRUE);
 | 
			
		||||
            return expect(tx).to.revertWith(expectedError);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if the target reverts', async () => {
 | 
			
		||||
            const owner = randomAddress();
 | 
			
		||||
            const to = randomAddress();
 | 
			
		||||
            const amount = getRandomInteger(0, 100e18);
 | 
			
		||||
            const tx = testContract
 | 
			
		||||
                .testTransferFrom(true, ENCODED_REVERT, ENCODED_TRUE, owner, to, amount)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            return expect(tx).to.revertWith(REVERT_STRING);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if the target reverts with no data', async () => {
 | 
			
		||||
            const owner = randomAddress();
 | 
			
		||||
            const to = randomAddress();
 | 
			
		||||
            const amount = getRandomInteger(0, 100e18);
 | 
			
		||||
            const tx = testContract
 | 
			
		||||
                .testTransferFrom(true, constants.NULL_BYTES, ENCODED_TRUE, owner, to, amount)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            return expect(tx).to.be.rejectedWith('revert');
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('decimals()', () => {
 | 
			
		||||
        const DEFAULT_DECIMALS = 18;
 | 
			
		||||
        const ENCODED_ZERO = hexUtils.leftPad(0);
 | 
			
		||||
        const ENCODED_SHORT_ZERO = hexUtils.leftPad(0, 31);
 | 
			
		||||
        const ENCODED_LONG_ZERO = hexUtils.leftPad(0, 33);
 | 
			
		||||
        const randomDecimals = () => Math.floor(Math.random() * 256) + 1;
 | 
			
		||||
 | 
			
		||||
        it('returns the number of decimals defined by the token', async () => {
 | 
			
		||||
            const decimals = randomDecimals();
 | 
			
		||||
            const encodedDecimals = hexUtils.leftPad(decimals);
 | 
			
		||||
            const result = await testContract.testDecimals(false, ENCODED_REVERT, encodedDecimals).callAsync();
 | 
			
		||||
            return expect(result).to.bignumber.eq(decimals);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('returns 0 if the token returns 0', async () => {
 | 
			
		||||
            const result = await testContract.testDecimals(false, ENCODED_REVERT, ENCODED_ZERO).callAsync();
 | 
			
		||||
            return expect(result).to.bignumber.eq(0);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('returns 18 if the token returns less than 32 bytes', async () => {
 | 
			
		||||
            const result = await testContract.testDecimals(false, ENCODED_REVERT, ENCODED_SHORT_ZERO).callAsync();
 | 
			
		||||
            return expect(result).to.bignumber.eq(DEFAULT_DECIMALS);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('returns 18 if the token returns greater than 32 bytes', async () => {
 | 
			
		||||
            const result = await testContract.testDecimals(false, ENCODED_REVERT, ENCODED_LONG_ZERO).callAsync();
 | 
			
		||||
            return expect(result).to.bignumber.eq(DEFAULT_DECIMALS);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('returns 18 if the token reverts', async () => {
 | 
			
		||||
            const result = await testContract.testDecimals(true, ENCODED_REVERT, ENCODED_ZERO).callAsync();
 | 
			
		||||
            return expect(result).to.bignumber.eq(DEFAULT_DECIMALS);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
@@ -1,187 +0,0 @@
 | 
			
		||||
import { chaiSetup, constants, 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 { DummyERC20TokenContract } from './wrappers';
 | 
			
		||||
 | 
			
		||||
import { artifacts } from './artifacts';
 | 
			
		||||
 | 
			
		||||
chaiSetup.configure();
 | 
			
		||||
const expect = chai.expect;
 | 
			
		||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
 | 
			
		||||
 | 
			
		||||
describe('UnlimitedAllowanceToken', () => {
 | 
			
		||||
    let owner: string;
 | 
			
		||||
    let spender: string;
 | 
			
		||||
    const MAX_MINT_VALUE = new BigNumber(10000000000000000000000);
 | 
			
		||||
    let token: DummyERC20TokenContract;
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        await blockchainLifecycle.startAsync();
 | 
			
		||||
    });
 | 
			
		||||
    after(async () => {
 | 
			
		||||
        await blockchainLifecycle.revertAsync();
 | 
			
		||||
    });
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        const accounts = await web3Wrapper.getAvailableAddressesAsync();
 | 
			
		||||
        owner = accounts[0];
 | 
			
		||||
        spender = accounts[1];
 | 
			
		||||
        token = await DummyERC20TokenContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.DummyERC20Token,
 | 
			
		||||
            provider,
 | 
			
		||||
            txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
            constants.DUMMY_TOKEN_NAME,
 | 
			
		||||
            constants.DUMMY_TOKEN_SYMBOL,
 | 
			
		||||
            constants.DUMMY_TOKEN_DECIMALS,
 | 
			
		||||
            constants.DUMMY_TOKEN_TOTAL_SUPPLY,
 | 
			
		||||
        );
 | 
			
		||||
        await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
            await token.mint(MAX_MINT_VALUE).sendTransactionAsync({ from: owner }),
 | 
			
		||||
            constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
        );
 | 
			
		||||
    });
 | 
			
		||||
    beforeEach(async () => {
 | 
			
		||||
        await blockchainLifecycle.startAsync();
 | 
			
		||||
    });
 | 
			
		||||
    afterEach(async () => {
 | 
			
		||||
        await blockchainLifecycle.revertAsync();
 | 
			
		||||
    });
 | 
			
		||||
    describe('transfer', () => {
 | 
			
		||||
        it('should revert if owner has insufficient balance', async () => {
 | 
			
		||||
            const ownerBalance = await token.balanceOf(owner).callAsync();
 | 
			
		||||
            const amountToTransfer = ownerBalance.plus(1);
 | 
			
		||||
            return expect(token.transfer(spender, amountToTransfer).callAsync({ from: owner })).to.revertWith(
 | 
			
		||||
                RevertReason.Erc20InsufficientBalance,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should transfer balance from sender to receiver', async () => {
 | 
			
		||||
            const receiver = spender;
 | 
			
		||||
            const initOwnerBalance = await token.balanceOf(owner).callAsync();
 | 
			
		||||
            const amountToTransfer = new BigNumber(1);
 | 
			
		||||
            await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                await token.transfer(receiver, amountToTransfer).sendTransactionAsync({ from: owner }),
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            const finalOwnerBalance = await token.balanceOf(owner).callAsync();
 | 
			
		||||
            const finalReceiverBalance = await token.balanceOf(receiver).callAsync();
 | 
			
		||||
 | 
			
		||||
            const expectedFinalOwnerBalance = initOwnerBalance.minus(amountToTransfer);
 | 
			
		||||
            const expectedFinalReceiverBalance = amountToTransfer;
 | 
			
		||||
            expect(finalOwnerBalance).to.be.bignumber.equal(expectedFinalOwnerBalance);
 | 
			
		||||
            expect(finalReceiverBalance).to.be.bignumber.equal(expectedFinalReceiverBalance);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should return true on a 0 value transfer', async () => {
 | 
			
		||||
            const didReturnTrue = await token.transfer(spender, new BigNumber(0)).callAsync({
 | 
			
		||||
                from: owner,
 | 
			
		||||
            });
 | 
			
		||||
            expect(didReturnTrue).to.be.true();
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('transferFrom', () => {
 | 
			
		||||
        it('should revert if owner has insufficient balance', async () => {
 | 
			
		||||
            const ownerBalance = await token.balanceOf(owner).callAsync();
 | 
			
		||||
            const amountToTransfer = ownerBalance.plus(1);
 | 
			
		||||
            await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                await token.approve(spender, amountToTransfer).sendTransactionAsync({ from: owner }),
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            return expect(
 | 
			
		||||
                token.transferFrom(owner, spender, amountToTransfer).callAsync({
 | 
			
		||||
                    from: spender,
 | 
			
		||||
                }),
 | 
			
		||||
            ).to.revertWith(RevertReason.Erc20InsufficientBalance);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should revert if spender has insufficient allowance', async () => {
 | 
			
		||||
            const ownerBalance = await token.balanceOf(owner).callAsync();
 | 
			
		||||
            const amountToTransfer = ownerBalance;
 | 
			
		||||
 | 
			
		||||
            const spenderAllowance = await token.allowance(owner, spender).callAsync();
 | 
			
		||||
            const isSpenderAllowanceInsufficient = spenderAllowance.comparedTo(amountToTransfer) < 0;
 | 
			
		||||
            expect(isSpenderAllowanceInsufficient).to.be.true();
 | 
			
		||||
 | 
			
		||||
            return expect(
 | 
			
		||||
                token.transferFrom(owner, spender, amountToTransfer).callAsync({
 | 
			
		||||
                    from: spender,
 | 
			
		||||
                }),
 | 
			
		||||
            ).to.revertWith(RevertReason.Erc20InsufficientAllowance);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should return true on a 0 value transfer', async () => {
 | 
			
		||||
            const amountToTransfer = new BigNumber(0);
 | 
			
		||||
            const didReturnTrue = await token.transferFrom(owner, spender, amountToTransfer).callAsync({
 | 
			
		||||
                from: spender,
 | 
			
		||||
            });
 | 
			
		||||
            expect(didReturnTrue).to.be.true();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should not modify spender allowance if spender allowance is 2^256 - 1', async () => {
 | 
			
		||||
            const initOwnerBalance = await token.balanceOf(owner).callAsync();
 | 
			
		||||
            const amountToTransfer = initOwnerBalance;
 | 
			
		||||
            const initSpenderAllowance = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
 | 
			
		||||
            await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                await token.approve(spender, initSpenderAllowance).sendTransactionAsync({ from: owner }),
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                await token.transferFrom(owner, spender, amountToTransfer).sendTransactionAsync({
 | 
			
		||||
                    from: spender,
 | 
			
		||||
                    gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
 | 
			
		||||
                }),
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            const newSpenderAllowance = await token.allowance(owner, spender).callAsync();
 | 
			
		||||
            expect(initSpenderAllowance).to.be.bignumber.equal(newSpenderAllowance);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should transfer the correct balances if spender has sufficient allowance', async () => {
 | 
			
		||||
            const initOwnerBalance = await token.balanceOf(owner).callAsync();
 | 
			
		||||
            const amountToTransfer = initOwnerBalance;
 | 
			
		||||
            const initSpenderAllowance = initOwnerBalance;
 | 
			
		||||
            await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                await token.approve(spender, initSpenderAllowance).sendTransactionAsync({ from: owner }),
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                await token.transferFrom(owner, spender, amountToTransfer).sendTransactionAsync({
 | 
			
		||||
                    from: spender,
 | 
			
		||||
                    gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
 | 
			
		||||
                }),
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            const newOwnerBalance = await token.balanceOf(owner).callAsync();
 | 
			
		||||
            const newSpenderBalance = await token.balanceOf(spender).callAsync();
 | 
			
		||||
 | 
			
		||||
            expect(newOwnerBalance).to.be.bignumber.equal(0);
 | 
			
		||||
            expect(newSpenderBalance).to.be.bignumber.equal(initOwnerBalance);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should modify allowance if spender has sufficient allowance less than 2^256 - 1', async () => {
 | 
			
		||||
            const initOwnerBalance = await token.balanceOf(owner).callAsync();
 | 
			
		||||
            const amountToTransfer = initOwnerBalance;
 | 
			
		||||
            const initSpenderAllowance = initOwnerBalance;
 | 
			
		||||
            await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                await token.approve(spender, initSpenderAllowance).sendTransactionAsync({ from: owner }),
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                await token.transferFrom(owner, spender, amountToTransfer).sendTransactionAsync({
 | 
			
		||||
                    from: spender,
 | 
			
		||||
                    gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
 | 
			
		||||
                }),
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            const newSpenderAllowance = await token.allowance(owner, spender).callAsync();
 | 
			
		||||
            expect(newSpenderAllowance).to.be.bignumber.equal(0);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
@@ -1,149 +0,0 @@
 | 
			
		||||
import {
 | 
			
		||||
    chaiSetup,
 | 
			
		||||
    constants,
 | 
			
		||||
    expectInsufficientFundsAsync,
 | 
			
		||||
    expectTransactionFailedWithoutReasonAsync,
 | 
			
		||||
    provider,
 | 
			
		||||
    txDefaults,
 | 
			
		||||
    web3Wrapper,
 | 
			
		||||
} from '@0x/contracts-test-utils';
 | 
			
		||||
import { BlockchainLifecycle } from '@0x/dev-utils';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
import { Web3Wrapper } from '@0x/web3-wrapper';
 | 
			
		||||
import * as chai from 'chai';
 | 
			
		||||
 | 
			
		||||
import { WETH9Contract } from './wrappers';
 | 
			
		||||
 | 
			
		||||
import { artifacts } from './artifacts';
 | 
			
		||||
 | 
			
		||||
chaiSetup.configure();
 | 
			
		||||
const expect = chai.expect;
 | 
			
		||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
 | 
			
		||||
 | 
			
		||||
describe('EtherToken', () => {
 | 
			
		||||
    let account: string;
 | 
			
		||||
    const gasPrice = new BigNumber(constants.DEFAULT_GAS_PRICE);
 | 
			
		||||
    let etherToken: WETH9Contract;
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        await blockchainLifecycle.startAsync();
 | 
			
		||||
    });
 | 
			
		||||
    after(async () => {
 | 
			
		||||
        await blockchainLifecycle.revertAsync();
 | 
			
		||||
    });
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        const accounts = await web3Wrapper.getAvailableAddressesAsync();
 | 
			
		||||
        account = accounts[0];
 | 
			
		||||
 | 
			
		||||
        etherToken = await WETH9Contract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.WETH9,
 | 
			
		||||
            provider,
 | 
			
		||||
            {
 | 
			
		||||
                ...txDefaults,
 | 
			
		||||
                gasPrice,
 | 
			
		||||
            },
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
    });
 | 
			
		||||
    beforeEach(async () => {
 | 
			
		||||
        await blockchainLifecycle.startAsync();
 | 
			
		||||
    });
 | 
			
		||||
    afterEach(async () => {
 | 
			
		||||
        await blockchainLifecycle.revertAsync();
 | 
			
		||||
    });
 | 
			
		||||
    describe('deposit', () => {
 | 
			
		||||
        it('should revert if caller attempts to deposit more Ether than caller balance', async () => {
 | 
			
		||||
            const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
 | 
			
		||||
            const ethToDeposit = initEthBalance.plus(1);
 | 
			
		||||
 | 
			
		||||
            return expectInsufficientFundsAsync(etherToken.deposit().sendTransactionAsync({ value: ethToDeposit }));
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should convert deposited Ether to wrapped Ether tokens', async () => {
 | 
			
		||||
            const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
 | 
			
		||||
            const initEthTokenBalance = await etherToken.balanceOf(account).callAsync();
 | 
			
		||||
 | 
			
		||||
            const ethToDeposit = new BigNumber(Web3Wrapper.toWei(new BigNumber(1)));
 | 
			
		||||
 | 
			
		||||
            const txHash = await etherToken.deposit().sendTransactionAsync({ value: ethToDeposit });
 | 
			
		||||
            const receipt = await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                txHash,
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            const ethSpentOnGas = gasPrice.times(receipt.gasUsed);
 | 
			
		||||
            const finalEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
 | 
			
		||||
            const finalEthTokenBalance = await etherToken.balanceOf(account).callAsync();
 | 
			
		||||
 | 
			
		||||
            expect(finalEthBalance).to.be.bignumber.equal(initEthBalance.minus(ethToDeposit.plus(ethSpentOnGas)));
 | 
			
		||||
            expect(finalEthTokenBalance).to.be.bignumber.equal(initEthTokenBalance.plus(ethToDeposit));
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('withdraw', () => {
 | 
			
		||||
        it('should revert if caller attempts to withdraw greater than caller balance', async () => {
 | 
			
		||||
            const initEthTokenBalance = await etherToken.balanceOf(account).callAsync();
 | 
			
		||||
            const ethTokensToWithdraw = initEthTokenBalance.plus(1);
 | 
			
		||||
 | 
			
		||||
            return expectTransactionFailedWithoutReasonAsync(
 | 
			
		||||
                etherToken.withdraw(ethTokensToWithdraw).sendTransactionAsync(),
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should convert ether tokens to ether with sufficient balance', async () => {
 | 
			
		||||
            const ethToDeposit = new BigNumber(Web3Wrapper.toWei(new BigNumber(1)));
 | 
			
		||||
            await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                await etherToken.deposit().sendTransactionAsync({ value: ethToDeposit }),
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            const initEthTokenBalance = await etherToken.balanceOf(account).callAsync();
 | 
			
		||||
            const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
 | 
			
		||||
            const ethTokensToWithdraw = initEthTokenBalance;
 | 
			
		||||
            expect(ethTokensToWithdraw).to.not.be.bignumber.equal(0);
 | 
			
		||||
            const txHash = await etherToken.withdraw(ethTokensToWithdraw).sendTransactionAsync({
 | 
			
		||||
                gas: constants.MAX_ETHERTOKEN_WITHDRAW_GAS,
 | 
			
		||||
            });
 | 
			
		||||
            const receipt = await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                txHash,
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            const ethSpentOnGas = gasPrice.times(receipt.gasUsed);
 | 
			
		||||
            const finalEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
 | 
			
		||||
            const finalEthTokenBalance = await etherToken.balanceOf(account).callAsync();
 | 
			
		||||
 | 
			
		||||
            expect(finalEthBalance).to.be.bignumber.equal(
 | 
			
		||||
                initEthBalance.plus(ethTokensToWithdraw.minus(ethSpentOnGas)),
 | 
			
		||||
            );
 | 
			
		||||
            expect(finalEthTokenBalance).to.be.bignumber.equal(initEthTokenBalance.minus(ethTokensToWithdraw));
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('fallback', () => {
 | 
			
		||||
        it('should convert sent ether to ether tokens', async () => {
 | 
			
		||||
            const initEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
 | 
			
		||||
            const initEthTokenBalance = await etherToken.balanceOf(account).callAsync();
 | 
			
		||||
 | 
			
		||||
            const ethToDeposit = Web3Wrapper.toBaseUnitAmount(new BigNumber(1), 18);
 | 
			
		||||
 | 
			
		||||
            const txHash = await web3Wrapper.sendTransactionAsync({
 | 
			
		||||
                from: account,
 | 
			
		||||
                to: etherToken.address,
 | 
			
		||||
                value: ethToDeposit,
 | 
			
		||||
                gasPrice,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            const receipt = await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                txHash,
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            const ethSpentOnGas = gasPrice.times(receipt.gasUsed);
 | 
			
		||||
            const finalEthBalance = await web3Wrapper.getBalanceInWeiAsync(account);
 | 
			
		||||
            const finalEthTokenBalance = await etherToken.balanceOf(account).callAsync();
 | 
			
		||||
 | 
			
		||||
            expect(finalEthBalance).to.be.bignumber.equal(initEthBalance.minus(ethToDeposit.plus(ethSpentOnGas)));
 | 
			
		||||
            expect(finalEthTokenBalance).to.be.bignumber.equal(initEthTokenBalance.plus(ethToDeposit));
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
@@ -1,22 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 * Warning: This file is auto-generated by contracts-gen. Don't edit manually.
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
export * from '../test/generated-wrappers/dummy_erc20_token';
 | 
			
		||||
export * from '../test/generated-wrappers/dummy_multiple_return_erc20_token';
 | 
			
		||||
export * from '../test/generated-wrappers/dummy_no_return_erc20_token';
 | 
			
		||||
export * from '../test/generated-wrappers/erc20_token';
 | 
			
		||||
export * from '../test/generated-wrappers/i_erc20_token';
 | 
			
		||||
export * from '../test/generated-wrappers/i_erc20_token_v06';
 | 
			
		||||
export * from '../test/generated-wrappers/i_ether_token';
 | 
			
		||||
export * from '../test/generated-wrappers/i_ether_token_v06';
 | 
			
		||||
export * from '../test/generated-wrappers/lib_erc20_token';
 | 
			
		||||
export * from '../test/generated-wrappers/lib_erc20_token_v06';
 | 
			
		||||
export * from '../test/generated-wrappers/mintable_erc20_token';
 | 
			
		||||
export * from '../test/generated-wrappers/test_lib_erc20_token';
 | 
			
		||||
export * from '../test/generated-wrappers/test_lib_erc20_token_target';
 | 
			
		||||
export * from '../test/generated-wrappers/unlimited_allowance_erc20_token';
 | 
			
		||||
export * from '../test/generated-wrappers/untransferrable_dummy_erc20_token';
 | 
			
		||||
export * from '../test/generated-wrappers/weth9';
 | 
			
		||||
export * from '../test/generated-wrappers/zrx_token';
 | 
			
		||||
@@ -1,210 +0,0 @@
 | 
			
		||||
import { chaiSetup, constants, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
 | 
			
		||||
import { BlockchainLifecycle } from '@0x/dev-utils';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
import { Web3Wrapper } from '@0x/web3-wrapper';
 | 
			
		||||
import * as chai from 'chai';
 | 
			
		||||
 | 
			
		||||
import { ZRXTokenContract } from './wrappers';
 | 
			
		||||
 | 
			
		||||
import { artifacts } from './artifacts';
 | 
			
		||||
 | 
			
		||||
chaiSetup.configure();
 | 
			
		||||
const expect = chai.expect;
 | 
			
		||||
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
 | 
			
		||||
 | 
			
		||||
describe('ZRXToken', () => {
 | 
			
		||||
    let owner: string;
 | 
			
		||||
    let spender: string;
 | 
			
		||||
    let MAX_UINT: BigNumber;
 | 
			
		||||
    let zrxToken: ZRXTokenContract;
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        await blockchainLifecycle.startAsync();
 | 
			
		||||
    });
 | 
			
		||||
    after(async () => {
 | 
			
		||||
        await blockchainLifecycle.revertAsync();
 | 
			
		||||
    });
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        const accounts = await web3Wrapper.getAvailableAddressesAsync();
 | 
			
		||||
        owner = accounts[0];
 | 
			
		||||
        spender = accounts[1];
 | 
			
		||||
        zrxToken = await ZRXTokenContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.ZRXToken,
 | 
			
		||||
            provider,
 | 
			
		||||
            txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
        MAX_UINT = constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS;
 | 
			
		||||
    });
 | 
			
		||||
    beforeEach(async () => {
 | 
			
		||||
        await blockchainLifecycle.startAsync();
 | 
			
		||||
    });
 | 
			
		||||
    afterEach(async () => {
 | 
			
		||||
        await blockchainLifecycle.revertAsync();
 | 
			
		||||
    });
 | 
			
		||||
    describe('constants', () => {
 | 
			
		||||
        it('should have 18 decimals', async () => {
 | 
			
		||||
            const decimals = new BigNumber(await zrxToken.decimals().callAsync());
 | 
			
		||||
            const expectedDecimals = 18;
 | 
			
		||||
            expect(decimals).to.be.bignumber.equal(expectedDecimals);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should have a total supply of 1 billion tokens', async () => {
 | 
			
		||||
            const totalSupply = new BigNumber(await zrxToken.totalSupply().callAsync());
 | 
			
		||||
            const expectedTotalSupply = 1000000000;
 | 
			
		||||
            expect(Web3Wrapper.toUnitAmount(totalSupply, 18)).to.be.bignumber.equal(expectedTotalSupply);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should be named 0x Protocol Token', async () => {
 | 
			
		||||
            const name = await zrxToken.name().callAsync();
 | 
			
		||||
            const expectedName = '0x Protocol Token';
 | 
			
		||||
            expect(name).to.be.equal(expectedName);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should have the symbol ZRX', async () => {
 | 
			
		||||
            const symbol = await zrxToken.symbol().callAsync();
 | 
			
		||||
            const expectedSymbol = 'ZRX';
 | 
			
		||||
            expect(symbol).to.be.equal(expectedSymbol);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('constructor', () => {
 | 
			
		||||
        it('should initialize owner balance to totalSupply', async () => {
 | 
			
		||||
            const ownerBalance = await zrxToken.balanceOf(owner).callAsync();
 | 
			
		||||
            const totalSupply = new BigNumber(await zrxToken.totalSupply().callAsync());
 | 
			
		||||
            expect(totalSupply).to.be.bignumber.equal(ownerBalance);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('transfer', () => {
 | 
			
		||||
        it('should transfer balance from sender to receiver', async () => {
 | 
			
		||||
            const receiver = spender;
 | 
			
		||||
            const initOwnerBalance = await zrxToken.balanceOf(owner).callAsync();
 | 
			
		||||
            const amountToTransfer = new BigNumber(1);
 | 
			
		||||
            await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                await zrxToken.transfer(receiver, amountToTransfer).sendTransactionAsync({ from: owner }),
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            const finalOwnerBalance = await zrxToken.balanceOf(owner).callAsync();
 | 
			
		||||
            const finalReceiverBalance = await zrxToken.balanceOf(receiver).callAsync();
 | 
			
		||||
 | 
			
		||||
            const expectedFinalOwnerBalance = initOwnerBalance.minus(amountToTransfer);
 | 
			
		||||
            const expectedFinalReceiverBalance = amountToTransfer;
 | 
			
		||||
            expect(finalOwnerBalance).to.be.bignumber.equal(expectedFinalOwnerBalance);
 | 
			
		||||
            expect(finalReceiverBalance).to.be.bignumber.equal(expectedFinalReceiverBalance);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should return true on a 0 value transfer', async () => {
 | 
			
		||||
            const didReturnTrue = await zrxToken.transfer(spender, new BigNumber(0)).callAsync({
 | 
			
		||||
                from: owner,
 | 
			
		||||
            });
 | 
			
		||||
            expect(didReturnTrue).to.be.true();
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('transferFrom', () => {
 | 
			
		||||
        it('should return false if owner has insufficient balance', async () => {
 | 
			
		||||
            const ownerBalance = await zrxToken.balanceOf(owner).callAsync();
 | 
			
		||||
            const amountToTransfer = ownerBalance.plus(1);
 | 
			
		||||
            await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                await zrxToken.approve(spender, amountToTransfer).sendTransactionAsync({
 | 
			
		||||
                    from: owner,
 | 
			
		||||
                    gas: constants.MAX_TOKEN_APPROVE_GAS,
 | 
			
		||||
                }),
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            const didReturnTrue = await zrxToken.transferFrom(owner, spender, amountToTransfer).callAsync({
 | 
			
		||||
                from: spender,
 | 
			
		||||
            });
 | 
			
		||||
            expect(didReturnTrue).to.be.false();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should return false if spender has insufficient allowance', async () => {
 | 
			
		||||
            const ownerBalance = await zrxToken.balanceOf(owner).callAsync();
 | 
			
		||||
            const amountToTransfer = ownerBalance;
 | 
			
		||||
 | 
			
		||||
            const spenderAllowance = await zrxToken.allowance(owner, spender).callAsync();
 | 
			
		||||
            const isSpenderAllowanceInsufficient = spenderAllowance.comparedTo(amountToTransfer) < 0;
 | 
			
		||||
            expect(isSpenderAllowanceInsufficient).to.be.true();
 | 
			
		||||
 | 
			
		||||
            const didReturnTrue = await zrxToken.transferFrom(owner, spender, amountToTransfer).callAsync({
 | 
			
		||||
                from: spender,
 | 
			
		||||
            });
 | 
			
		||||
            expect(didReturnTrue).to.be.false();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should return true on a 0 value transfer', async () => {
 | 
			
		||||
            const amountToTransfer = new BigNumber(0);
 | 
			
		||||
            const didReturnTrue = await zrxToken.transferFrom(owner, spender, amountToTransfer).callAsync({
 | 
			
		||||
                from: spender,
 | 
			
		||||
            });
 | 
			
		||||
            expect(didReturnTrue).to.be.true();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should not modify spender allowance if spender allowance is 2^256 - 1', async () => {
 | 
			
		||||
            const initOwnerBalance = await zrxToken.balanceOf(owner).callAsync();
 | 
			
		||||
            const amountToTransfer = initOwnerBalance;
 | 
			
		||||
            const initSpenderAllowance = MAX_UINT;
 | 
			
		||||
            await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                await zrxToken.approve(spender, initSpenderAllowance).sendTransactionAsync({
 | 
			
		||||
                    from: owner,
 | 
			
		||||
                    gas: constants.MAX_TOKEN_APPROVE_GAS,
 | 
			
		||||
                }),
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                await zrxToken.transferFrom(owner, spender, amountToTransfer).sendTransactionAsync({
 | 
			
		||||
                    from: spender,
 | 
			
		||||
                    gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
 | 
			
		||||
                }),
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            const newSpenderAllowance = await zrxToken.allowance(owner, spender).callAsync();
 | 
			
		||||
            expect(initSpenderAllowance).to.be.bignumber.equal(newSpenderAllowance);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should transfer the correct balances if spender has sufficient allowance', async () => {
 | 
			
		||||
            const initOwnerBalance = await zrxToken.balanceOf(owner).callAsync();
 | 
			
		||||
            const initSpenderBalance = await zrxToken.balanceOf(spender).callAsync();
 | 
			
		||||
            const amountToTransfer = initOwnerBalance;
 | 
			
		||||
            const initSpenderAllowance = initOwnerBalance;
 | 
			
		||||
            await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                await zrxToken.approve(spender, initSpenderAllowance).sendTransactionAsync(),
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                await zrxToken.transferFrom(owner, spender, amountToTransfer).sendTransactionAsync({
 | 
			
		||||
                    from: spender,
 | 
			
		||||
                    gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
 | 
			
		||||
                }),
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            const newOwnerBalance = await zrxToken.balanceOf(owner).callAsync();
 | 
			
		||||
            const newSpenderBalance = await zrxToken.balanceOf(spender).callAsync();
 | 
			
		||||
 | 
			
		||||
            expect(newOwnerBalance).to.be.bignumber.equal(0);
 | 
			
		||||
            expect(newSpenderBalance).to.be.bignumber.equal(initSpenderBalance.plus(initOwnerBalance));
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should modify allowance if spender has sufficient allowance less than 2^256 - 1', async () => {
 | 
			
		||||
            const initOwnerBalance = await zrxToken.balanceOf(owner).callAsync();
 | 
			
		||||
            const amountToTransfer = initOwnerBalance;
 | 
			
		||||
            await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                await zrxToken.approve(spender, amountToTransfer).sendTransactionAsync(),
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
            await web3Wrapper.awaitTransactionSuccessAsync(
 | 
			
		||||
                await zrxToken.transferFrom(owner, spender, amountToTransfer).sendTransactionAsync({
 | 
			
		||||
                    from: spender,
 | 
			
		||||
                    gas: constants.MAX_TOKEN_TRANSFERFROM_GAS,
 | 
			
		||||
                }),
 | 
			
		||||
                constants.AWAIT_TRANSACTION_MINED_MS,
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            const newSpenderAllowance = await zrxToken.allowance(owner, spender).callAsync();
 | 
			
		||||
            expect(newSpenderAllowance).to.be.bignumber.equal(0);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
@@ -1,96 +0,0 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Use this file to configure your truffle project. It's seeded with some
 | 
			
		||||
 * common settings for different networks and features like migrations,
 | 
			
		||||
 * compilation and testing. Uncomment the ones you need or modify
 | 
			
		||||
 * them to suit your project as necessary.
 | 
			
		||||
 *
 | 
			
		||||
 * More information about configuration can be found at:
 | 
			
		||||
 *
 | 
			
		||||
 * truffleframework.com/docs/advanced/configuration
 | 
			
		||||
 *
 | 
			
		||||
 * To deploy via Infura you'll need a wallet provider (like truffle-hdwallet-provider)
 | 
			
		||||
 * to sign your transactions before they're sent to a remote public node. Infura accounts
 | 
			
		||||
 * are available for free at: infura.io/register.
 | 
			
		||||
 *
 | 
			
		||||
 * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
 | 
			
		||||
 * public/private key pairs. If you're publishing your code to GitHub make sure you load this
 | 
			
		||||
 * phrase from a file you've .gitignored so it doesn't accidentally become public.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
// const HDWalletProvider = require('truffle-hdwallet-provider');
 | 
			
		||||
// const infuraKey = "fj4jll3k.....";
 | 
			
		||||
//
 | 
			
		||||
// const fs = require('fs');
 | 
			
		||||
// const mnemonic = fs.readFileSync(".secret").toString().trim();
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
    /**
 | 
			
		||||
     * Networks define how you connect to your ethereum client and let you set the
 | 
			
		||||
     * defaults web3 uses to send transactions. If you don't specify one truffle
 | 
			
		||||
     * will spin up a development blockchain for you on port 9545 when you
 | 
			
		||||
     * run `develop` or `test`. You can ask a truffle command to use a specific
 | 
			
		||||
     * network from the command line, e.g
 | 
			
		||||
     *
 | 
			
		||||
     * $ truffle test --network <network-name>
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    networks: {
 | 
			
		||||
        // Useful for testing. The `development` name is special - truffle uses it by default
 | 
			
		||||
        // if it's defined here and no other network is specified at the command line.
 | 
			
		||||
        // You should run a client (like ganache-cli, geth or parity) in a separate terminal
 | 
			
		||||
        // tab if you use this network and you must also set the `host`, `port` and `network_id`
 | 
			
		||||
        // options below to some value.
 | 
			
		||||
        //
 | 
			
		||||
        // development: {
 | 
			
		||||
        //  host: "127.0.0.1",     // Localhost (default: none)
 | 
			
		||||
        //  port: 8545,            // Standard Ethereum port (default: none)
 | 
			
		||||
        //  network_id: "*",       // Any network (default: none)
 | 
			
		||||
        // },
 | 
			
		||||
        // Another network with more advanced options...
 | 
			
		||||
        // advanced: {
 | 
			
		||||
        // port: 8777,             // Custom port
 | 
			
		||||
        // network_id: 1342,       // Custom network
 | 
			
		||||
        // gas: 8500000,           // Gas sent with each transaction (default: ~6700000)
 | 
			
		||||
        // gasPrice: 20000000000,  // 20 gwei (in wei) (default: 100 gwei)
 | 
			
		||||
        // from: <address>,        // Account to send txs from (default: accounts[0])
 | 
			
		||||
        // websockets: true        // Enable EventEmitter interface for web3 (default: false)
 | 
			
		||||
        // },
 | 
			
		||||
        // Useful for deploying to a public network.
 | 
			
		||||
        // NB: It's important to wrap the provider as a function.
 | 
			
		||||
        // ropsten: {
 | 
			
		||||
        // provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/YOUR-PROJECT-ID`),
 | 
			
		||||
        // network_id: 3,       // Ropsten's id
 | 
			
		||||
        // gas: 5500000,        // Ropsten has a lower block limit than mainnet
 | 
			
		||||
        // confirmations: 2,    // # of confs to wait between deployments. (default: 0)
 | 
			
		||||
        // timeoutBlocks: 200,  // # of blocks before a deployment times out  (minimum/default: 50)
 | 
			
		||||
        // skipDryRun: true     // Skip dry run before migrations? (default: false for public nets )
 | 
			
		||||
        // },
 | 
			
		||||
        // Useful for private networks
 | 
			
		||||
        // private: {
 | 
			
		||||
        // provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
 | 
			
		||||
        // network_id: 2111,   // This network is yours, in the cloud.
 | 
			
		||||
        // production: true    // Treats this network as if it was a public net. (default: false)
 | 
			
		||||
        // }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Set default mocha options here, use special reporters etc.
 | 
			
		||||
    mocha: {
 | 
			
		||||
        // timeout: 100000
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Configure your compilers
 | 
			
		||||
    compilers: {
 | 
			
		||||
        solc: {
 | 
			
		||||
            version: '0.5.9',
 | 
			
		||||
            settings: {
 | 
			
		||||
                evmVersion: 'constantinople',
 | 
			
		||||
                optimizer: {
 | 
			
		||||
                    enabled: true,
 | 
			
		||||
                    runs: 1000000,
 | 
			
		||||
                    details: { yul: true, deduplicate: true, cse: true, constantOptimizer: true },
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
@@ -1,31 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
    "extends": "../../tsconfig",
 | 
			
		||||
    "compilerOptions": { "outDir": "lib", "rootDir": ".", "resolveJsonModule": true },
 | 
			
		||||
    "include": ["./src/**/*", "./test/**/*", "./generated-wrappers/**/*"],
 | 
			
		||||
    "files": [
 | 
			
		||||
        "generated-artifacts/DummyERC20Token.json",
 | 
			
		||||
        "generated-artifacts/DummyMultipleReturnERC20Token.json",
 | 
			
		||||
        "generated-artifacts/DummyNoReturnERC20Token.json",
 | 
			
		||||
        "generated-artifacts/ERC20Token.json",
 | 
			
		||||
        "generated-artifacts/WETH9.json",
 | 
			
		||||
        "generated-artifacts/ZRXToken.json",
 | 
			
		||||
        "test/generated-artifacts/DummyERC20Token.json",
 | 
			
		||||
        "test/generated-artifacts/DummyMultipleReturnERC20Token.json",
 | 
			
		||||
        "test/generated-artifacts/DummyNoReturnERC20Token.json",
 | 
			
		||||
        "test/generated-artifacts/ERC20Token.json",
 | 
			
		||||
        "test/generated-artifacts/IERC20Token.json",
 | 
			
		||||
        "test/generated-artifacts/IERC20TokenV06.json",
 | 
			
		||||
        "test/generated-artifacts/IEtherToken.json",
 | 
			
		||||
        "test/generated-artifacts/IEtherTokenV06.json",
 | 
			
		||||
        "test/generated-artifacts/LibERC20Token.json",
 | 
			
		||||
        "test/generated-artifacts/LibERC20TokenV06.json",
 | 
			
		||||
        "test/generated-artifacts/MintableERC20Token.json",
 | 
			
		||||
        "test/generated-artifacts/TestLibERC20Token.json",
 | 
			
		||||
        "test/generated-artifacts/TestLibERC20TokenTarget.json",
 | 
			
		||||
        "test/generated-artifacts/UnlimitedAllowanceERC20Token.json",
 | 
			
		||||
        "test/generated-artifacts/UntransferrableDummyERC20Token.json",
 | 
			
		||||
        "test/generated-artifacts/WETH9.json",
 | 
			
		||||
        "test/generated-artifacts/ZRXToken.json"
 | 
			
		||||
    ],
 | 
			
		||||
    "exclude": ["./deploy/solc/solc_bin"]
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
    "extends": "../../typedoc-tsconfig",
 | 
			
		||||
    "compilerOptions": {
 | 
			
		||||
        "outDir": "lib"
 | 
			
		||||
    },
 | 
			
		||||
    "include": ["./src/**/*", "./test/**/*"]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								contracts/governance/CHANGELOG.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								contracts/governance/CHANGELOG.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1681756154,
 | 
			
		||||
        "version": "1.0.4",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1681694690,
 | 
			
		||||
        "version": "1.0.3",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1681687842,
 | 
			
		||||
        "version": "1.0.2",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1681157139,
 | 
			
		||||
        "version": "1.0.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    }
 | 
			
		||||
]
 | 
			
		||||
							
								
								
									
										22
									
								
								contracts/governance/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								contracts/governance/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
<!--
 | 
			
		||||
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
 | 
			
		||||
Edit the package's CHANGELOG.json file only.
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v1.0.4 - _April 17, 2023_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.0.3 - _April 17, 2023_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.0.2 - _April 16, 2023_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.0.1 - _April 10, 2023_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
							
								
								
									
										74
									
								
								contracts/governance/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								contracts/governance/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
## Governance
 | 
			
		||||
 | 
			
		||||
This package contains contracts for the ZeroEx governance of 0x Protocol and Treasury.
 | 
			
		||||
 | 
			
		||||
## Production deployment
 | 
			
		||||
 | 
			
		||||
`ZRXWrappedToken` 0xfcfaf7834f134f5146dbb3274bab9bed4bafa917
 | 
			
		||||
`ZeroExVotesProxy` 0x9c766e51b46cbc1fa4f8b6718ed4a60ac9d591fb
 | 
			
		||||
`ZeroExVotes` 0x8d208c5514b98c5b9ceed650b02df2aeb1c73e6f
 | 
			
		||||
Protocol `ZeroExTimelock` 0xb6a1f58c5df9f13312639cddda0d128bf28cdd87
 | 
			
		||||
`ZeroExProtocolGovernor` 0xc256035fe8533f9ce362012a6ae0aefed4df30f4
 | 
			
		||||
Treasury `ZeroExTimelock` 0x0dcfb77a581bc8fe432e904643a5480cc183f38d
 | 
			
		||||
`ZeroExTreasuryGovernor` 0x4822cfc1e7699bdb9551bdfd3a838ee414bc2008
 | 
			
		||||
Security council 0x979BDb496e5f0A00af078b7a45F1E9E6bcff170F
 | 
			
		||||
 | 
			
		||||
## Design
 | 
			
		||||
 | 
			
		||||
This implementation fully decentralises governance of 0x Protocol and Treasury. This is enabled via a wrapped ZRX token and a Compound-like governors design. There are two separate governors for Protocol - `ZeroExProtocolGovernor` and Treasury - `ZeroExTreasuryGovernor` respectively working with two separate Timelock instances of the same contract implementation - `ZeroExTimelock`.
 | 
			
		||||
 | 
			
		||||
### Upgradability
 | 
			
		||||
`ZRXWrappedToken` , `ZeroExProtocolGovernor` and `ZeroExTreasuryGovernor` governors are non-upgradable by design. However the voting implementation the governors use - `ZeroExVotes` is upgradable and using the OZ `ERC1967Proxy`.
 | 
			
		||||
 | 
			
		||||
### Wrapped ZRX
 | 
			
		||||
wZRX will be issued 1-to-1 for ZRX. No locking/vesting mechanisms will exist between wZRX and ZRX and the two will be freely interchangeable. The ZRX token is non-upgradable and same will be valid for its wrapped equivalent.
 | 
			
		||||
 | 
			
		||||
The token supports delegation which allows a user to delegate their entire voting power to another account (which doesn't necessarily need to be a token holder). This is modelled on the standard OpenZeppelin `ERC20Votes` implementation. We have added logic for block number stamping delegators' balance changes stored in the `DelegateInfo.balanceLastUpdated` property. This block number information is sent in calls to `ZeroExVotes.moveVotingPower` in order to provide support for future upgrades to the vote power calculation.
 | 
			
		||||
Note that for consistency `block.number` is used for the governor settings, voting checkpoints and this delegators' balance last updated property while timelock logic for the governor uses block.timestamp.
 | 
			
		||||
 | 
			
		||||
### Governors' settings
 | 
			
		||||
Changing governors' settings for `votingDelay`, `votingPeriod` and `proposalThreshold` can be done via the normal proposal mechanism. Governors are deployed with the following initial settings:
 | 
			
		||||
 | 
			
		||||
|                                | voting delay | voting period | proposal threshold |
 | 
			
		||||
|-------------------|--------------|---------------|--------------------|
 | 
			
		||||
| Protocol governor | 2 days            | 7 days             |  1000000e18           |
 | 
			
		||||
| Treasury governor | 2 days           |  7 days             |   250000e18          |
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
This is using standard openzeppelin `GovernorSettings` implementation.
 | 
			
		||||
 | 
			
		||||
### Quorum
 | 
			
		||||
Quorum for Protocol is fixed at 10m (10000000e18) while for Treasury this is calculated as 10% of voting power of the total supply (see voting strategies below for quadratic voting power implementation specifics). The quorum calculations for Treasury are using OpenZeppelin's `GovernorVotesQuorumFraction`.
 | 
			
		||||
 | 
			
		||||
Note that in-place updates to the quorum are not supported and will need to go through a governance upgrade. Reasoning behind this can be found in this discussion https://forum.openzeppelin.com/t/quorum-default-behaviour-on-governors/34560.
 | 
			
		||||
 | 
			
		||||
### Voting strategies
 | 
			
		||||
The voting strategy will be linear 1-token-1-vote for Protocol and quadratic with threshold of 1000000e18 for Treasury (i.e. voting weight is linear up to 1m tokens and balance above that threshold is quadratic).
 | 
			
		||||
 | 
			
		||||
Worth noting is the `Checkpoint` struct design. For packing every `Checkpoint` into a single storage slot we are using the minimum uint type size for `votes` and `quadraticVotes` members, e.g.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
struct Checkpoint {
 | 
			
		||||
        uint32 fromBlock;
 | 
			
		||||
        uint96 votes;
 | 
			
		||||
        uint96 quadraticVotes;
 | 
			
		||||
    }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
since the maximum token supply is 1bn we can have maximum value for:
 | 
			
		||||
`votes` : 1bn *10^18 => can be stored in 90 bits
 | 
			
		||||
`quadraticVotes` : due to the likelihood of threshold changing and potentially bringing it closer to a linear vote, we are preemptively keeping this to the same size as linear votes slot.
 | 
			
		||||
 | 
			
		||||
### Time locks
 | 
			
		||||
Governance proposals are subject to a 3 days delay for Protocol and 2 days for Treasury. This delay allows Security Council time to review passed proposals and take action where needed.
 | 
			
		||||
 | 
			
		||||
### Security Council
 | 
			
		||||
The concept of a Security council is introduced which allows a multisig of security council members to cancel a proposal on the treasury or protocol governors and also rollback the protocol to an earlier version.
 | 
			
		||||
 | 
			
		||||
When no security council is assigned the following apply:
 | 
			
		||||
 | 
			
		||||
- ongoing proposals can still be voted on
 | 
			
		||||
- new proposals cannot be created - except assignSecurityCouncil
 | 
			
		||||
- expired proposals that are successful cannot be queued - excepted assignSecurityCouncil
 | 
			
		||||
 | 
			
		||||
There is a provision for the governors to have different security council set although initially these are the same.
 | 
			
		||||
							
								
								
									
										505
									
								
								contracts/governance/ZRXToken.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										505
									
								
								contracts/governance/ZRXToken.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,505 @@
 | 
			
		||||
{
 | 
			
		||||
    "abi": [
 | 
			
		||||
        {
 | 
			
		||||
            "constant": true,
 | 
			
		||||
            "inputs": [],
 | 
			
		||||
            "name": "name",
 | 
			
		||||
            "outputs": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "",
 | 
			
		||||
                    "type": "string"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "payable": false,
 | 
			
		||||
            "type": "function"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "constant": false,
 | 
			
		||||
            "inputs": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "_spender",
 | 
			
		||||
                    "type": "address"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "_value",
 | 
			
		||||
                    "type": "uint256"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "name": "approve",
 | 
			
		||||
            "outputs": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "",
 | 
			
		||||
                    "type": "bool"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "payable": false,
 | 
			
		||||
            "type": "function"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "constant": true,
 | 
			
		||||
            "inputs": [],
 | 
			
		||||
            "name": "totalSupply",
 | 
			
		||||
            "outputs": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "",
 | 
			
		||||
                    "type": "uint256"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "payable": false,
 | 
			
		||||
            "type": "function"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "constant": false,
 | 
			
		||||
            "inputs": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "_from",
 | 
			
		||||
                    "type": "address"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "_to",
 | 
			
		||||
                    "type": "address"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "_value",
 | 
			
		||||
                    "type": "uint256"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "name": "transferFrom",
 | 
			
		||||
            "outputs": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "",
 | 
			
		||||
                    "type": "bool"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "payable": false,
 | 
			
		||||
            "type": "function"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "constant": true,
 | 
			
		||||
            "inputs": [],
 | 
			
		||||
            "name": "decimals",
 | 
			
		||||
            "outputs": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "",
 | 
			
		||||
                    "type": "uint8"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "payable": false,
 | 
			
		||||
            "type": "function"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "constant": true,
 | 
			
		||||
            "inputs": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "_owner",
 | 
			
		||||
                    "type": "address"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "name": "balanceOf",
 | 
			
		||||
            "outputs": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "",
 | 
			
		||||
                    "type": "uint256"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "payable": false,
 | 
			
		||||
            "type": "function"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "constant": true,
 | 
			
		||||
            "inputs": [],
 | 
			
		||||
            "name": "symbol",
 | 
			
		||||
            "outputs": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "",
 | 
			
		||||
                    "type": "string"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "payable": false,
 | 
			
		||||
            "type": "function"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "constant": false,
 | 
			
		||||
            "inputs": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "_to",
 | 
			
		||||
                    "type": "address"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "_value",
 | 
			
		||||
                    "type": "uint256"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "name": "transfer",
 | 
			
		||||
            "outputs": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "",
 | 
			
		||||
                    "type": "bool"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "payable": false,
 | 
			
		||||
            "type": "function"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "constant": true,
 | 
			
		||||
            "inputs": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "_owner",
 | 
			
		||||
                    "type": "address"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "_spender",
 | 
			
		||||
                    "type": "address"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "name": "allowance",
 | 
			
		||||
            "outputs": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "",
 | 
			
		||||
                    "type": "uint256"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "payable": false,
 | 
			
		||||
            "type": "function"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "inputs": [],
 | 
			
		||||
            "payable": false,
 | 
			
		||||
            "type": "constructor"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "anonymous": false,
 | 
			
		||||
            "inputs": [
 | 
			
		||||
                {
 | 
			
		||||
                    "indexed": true,
 | 
			
		||||
                    "name": "_from",
 | 
			
		||||
                    "type": "address"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "indexed": true,
 | 
			
		||||
                    "name": "_to",
 | 
			
		||||
                    "type": "address"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "indexed": false,
 | 
			
		||||
                    "name": "_value",
 | 
			
		||||
                    "type": "uint256"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "name": "Transfer",
 | 
			
		||||
            "type": "event"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "anonymous": false,
 | 
			
		||||
            "inputs": [
 | 
			
		||||
                {
 | 
			
		||||
                    "indexed": true,
 | 
			
		||||
                    "name": "_owner",
 | 
			
		||||
                    "type": "address"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "indexed": true,
 | 
			
		||||
                    "name": "_spender",
 | 
			
		||||
                    "type": "address"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "indexed": false,
 | 
			
		||||
                    "name": "_value",
 | 
			
		||||
                    "type": "uint256"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "name": "Approval",
 | 
			
		||||
            "type": "event"
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    "bytecode": {
 | 
			
		||||
        "object": "0x60606040526b033b2e3c9fd0803ce8000000600355341561001c57fe5b5b600354600160a060020a0333166000908152602081905260409020555b5b61078d8061004a6000396000f300606060405236156100965763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde038114610098578063095ea7b31461014657806318160ddd1461018657806323b872dd146101a8578063313ce567146101ee57806370a082311461021457806395d89b411461024f578063a9059cbb146102fd578063dd62ed3e1461033d575bfe5b34156100a057fe5b6100a861037e565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014e57fe5b61017273ffffffffffffffffffffffffffffffffffffffff600435166024356103b5565b604080519115158252519081900360200190f35b341561018e57fe5b61019661042d565b60408051918252519081900360200190f35b34156101b057fe5b61017273ffffffffffffffffffffffffffffffffffffffff60043581169060243516604435610433565b604080519115158252519081900360200190f35b34156101f657fe5b6101fe6105d4565b6040805160ff9092168252519081900360200190f35b341561021c57fe5b61019673ffffffffffffffffffffffffffffffffffffffff600435166105d9565b60408051918252519081900360200190f35b341561025757fe5b6100a8610605565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561030557fe5b61017273ffffffffffffffffffffffffffffffffffffffff6004351660243561063c565b604080519115158252519081900360200190f35b341561034557fe5b61019673ffffffffffffffffffffffffffffffffffffffff60043581169060243516610727565b60408051918252519081900360200190f35b60408051808201909152601181527f30782050726f746f636f6c20546f6b656e000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60035481565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260016020908152604080832033909516835293815283822054928252819052918220548390108015906104835750828110155b80156104b6575073ffffffffffffffffffffffffffffffffffffffff841660009081526020819052604090205483810110155b156105c65773ffffffffffffffffffffffffffffffffffffffff808516600090815260208190526040808220805487019055918716815220805484900390557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156105585773ffffffffffffffffffffffffffffffffffffffff808616600090815260016020908152604080832033909416835292905220805484900390555b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a3600191506105cb565b600091505b5b509392505050565b601281565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602081905260409020545b919050565b60408051808201909152600381527f5a52580000000000000000000000000000000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff3316600090815260208190526040812054829010801590610699575073ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110155b156107185773ffffffffffffffffffffffffffffffffffffffff33811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a3506001610427565b506000610427565b5b92915050565b73ffffffffffffffffffffffffffffffffffffffff8083166000908152600160209081526040808320938516835292905220545b929150505600a165627a7a723058202dbef854545f38e5b78ec251d65db5fa0f12b6f2f0a0039063735c2dc416d6310029",
 | 
			
		||||
        "sourceMap": "4935:353:0:-;;;5056:8;5027:37;;5208:78;;;;;;;5268:11;;-1:-1:-1;;;;;5254:10:0;5245:20;:8;:20;;;;;;;;;;:34;5208:78;4935:353;;;;;;;",
 | 
			
		||||
        "linkReferences": {}
 | 
			
		||||
    },
 | 
			
		||||
    "deployedBytecode": {
 | 
			
		||||
        "object": "0x606060405236156100965763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde038114610098578063095ea7b31461014657806318160ddd1461018657806323b872dd146101a8578063313ce567146101ee57806370a082311461021457806395d89b411461024f578063a9059cbb146102fd578063dd62ed3e1461033d575bfe5b34156100a057fe5b6100a861037e565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014e57fe5b61017273ffffffffffffffffffffffffffffffffffffffff600435166024356103b5565b604080519115158252519081900360200190f35b341561018e57fe5b61019661042d565b60408051918252519081900360200190f35b34156101b057fe5b61017273ffffffffffffffffffffffffffffffffffffffff60043581169060243516604435610433565b604080519115158252519081900360200190f35b34156101f657fe5b6101fe6105d4565b6040805160ff9092168252519081900360200190f35b341561021c57fe5b61019673ffffffffffffffffffffffffffffffffffffffff600435166105d9565b60408051918252519081900360200190f35b341561025757fe5b6100a8610605565b60408051602080825283518183015283519192839290830191850190808383821561010c575b80518252602083111561010c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016100ce565b505050905090810190601f1680156101385780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561030557fe5b61017273ffffffffffffffffffffffffffffffffffffffff6004351660243561063c565b604080519115158252519081900360200190f35b341561034557fe5b61019673ffffffffffffffffffffffffffffffffffffffff60043581169060243516610727565b60408051918252519081900360200190f35b60408051808201909152601181527f30782050726f746f636f6c20546f6b656e000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff338116600081815260016020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60035481565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260016020908152604080832033909516835293815283822054928252819052918220548390108015906104835750828110155b80156104b6575073ffffffffffffffffffffffffffffffffffffffff841660009081526020819052604090205483810110155b156105c65773ffffffffffffffffffffffffffffffffffffffff808516600090815260208190526040808220805487019055918716815220805484900390557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8110156105585773ffffffffffffffffffffffffffffffffffffffff808616600090815260016020908152604080832033909416835292905220805484900390555b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a3600191506105cb565b600091505b5b509392505050565b601281565b73ffffffffffffffffffffffffffffffffffffffff81166000908152602081905260409020545b919050565b60408051808201909152600381527f5a52580000000000000000000000000000000000000000000000000000000000602082015281565b73ffffffffffffffffffffffffffffffffffffffff3316600090815260208190526040812054829010801590610699575073ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205482810110155b156107185773ffffffffffffffffffffffffffffffffffffffff33811660008181526020818152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a3506001610427565b506000610427565b5b92915050565b73ffffffffffffffffffffffffffffffffffffffff8083166000908152600160209081526040808320938516835292905220545b929150505600a165627a7a723058202dbef854545f38e5b78ec251d65db5fa0f12b6f2f0a0039063735c2dc416d6310029",
 | 
			
		||||
        "sourceMap": "4935:353:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5109:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18:2:-1;;13:3;7:5;32;59:3;53:5;48:3;41:6;93:2;88:3;85:2;78:6;73:3;67:5;152:3;;;;;117:2;108:3;;;;130;172:5;167:4;181:3;3:186;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3523:190:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5027:37;;;;;;;;;;;;;;;;;;;;;;;;;;4369:562;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4986:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3415:102;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5164:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18:2:-1;;13:3;7:5;32;59:3;53:5;48:3;41:6;93:2;88:3;85:2;78:6;73:3;67:5;152:3;;;;;117:2;108:3;;;;130;172:5;167:4;181:3;3:186;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2490:433:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3719:129;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5109:49;;;;;;;;;;;;;;;;;;;:::o;3523:190::-;3599:19;3607:10;3599:19;;3583:4;3599:19;;;:7;:19;;;;;;;;:29;;;;;;;;;;;;:38;;;3647;;;;;;;3583:4;;3599:29;:19;3647:38;;;;;;;;;;;-1:-1:-1;3702:4:0;3523:190;;;;;:::o;5027:37::-;;;;:::o;4369:562::-;4487:14;;;;4451:4;4487:14;;;:7;:14;;;;;;;;4502:10;4487:26;;;;;;;;;;;;4527:15;;;;;;;;;;:25;;;;;;:48;;;4569:6;4556:9;:19;;4527:48;:91;;;;-1:-1:-1;4605:13:0;;;:8;:13;;;;;;;;;;;4579:22;;;:39;;4527:91;4523:402;;;4634:13;;;;:8;:13;;;;;;;;;;;:23;;;;;;4671:15;;;;;;:25;;;;;;;4069:12;4714:20;;4710:95;;;4754:14;;;;;;;;:7;:14;;;;;;;;4769:10;4754:26;;;;;;;;;:36;;;;;;;4710:95;4834:3;4818:28;;4827:5;4818:28;;;4839:6;4818:28;;;;;;;;;;;;;;;;;;4867:4;4860:11;;;;4523:402;4909:5;4902:12;;4523:402;4369:562;;;;;;;:::o;4986:35::-;5019:2;4986:35;:::o;3415:102::-;3494:16;;;3468:7;3494:16;;;;;;;;;;;3415:102;;;;:::o;5164:37::-;;;;;;;;;;;;;;;;;;;:::o;2490:433::-;2635:20;2644:10;2635:20;2546:4;2635:20;;;;;;;;;;;:30;;;;;;:73;;-1:-1:-1;2695:13:0;;;:8;:13;;;;;;;;;;;2669:22;;;:39;;2635:73;2631:286;;;2724:20;2733:10;2724:20;;:8;:20;;;;;;;;;;;:30;;;;;;;2768:13;;;;;;;;;;:23;;;;;;2805:33;;;;;;;2768:13;;2805:33;;;;;;;;;;;-1:-1:-1;2859:4:0;2852:11;;2631:286;-1:-1:-1;2901:5:0;2894:12;;2631:286;2490:433;;;;;:::o;3719:129::-;3816:15;;;;3790:7;3816:15;;;:7;:15;;;;;;;;:25;;;;;;;;;;3719:129;;;;;:::o",
 | 
			
		||||
        "linkReferences": {}
 | 
			
		||||
    },
 | 
			
		||||
    "methodIdentifiers": {
 | 
			
		||||
        "allowance(address,address)": "dd62ed3e",
 | 
			
		||||
        "approve(address,uint256)": "095ea7b3",
 | 
			
		||||
        "balanceOf(address)": "70a08231",
 | 
			
		||||
        "decimals()": "313ce567",
 | 
			
		||||
        "name()": "06fdde03",
 | 
			
		||||
        "symbol()": "95d89b41",
 | 
			
		||||
        "totalSupply()": "18160ddd",
 | 
			
		||||
        "transfer(address,uint256)": "a9059cbb",
 | 
			
		||||
        "transferFrom(address,address,uint256)": "23b872dd"
 | 
			
		||||
    },
 | 
			
		||||
    "rawMetadata": "{\"compiler\":{\"version\":\"0.4.11+commit.68ef5810\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_spender\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_from\",\"type\":\"address\"},{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"},{\"name\":\"_spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_owner\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_spender\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"}],\"devdoc\":{\"methods\":{\"transferFrom(address,address,uint256)\":{\"details\":\"ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance.\",\"params\":{\"_from\":\"Address to transfer from.\",\"_to\":\"Address to transfer to.\",\"_value\":\"Amount to transfer.\"},\"return\":\"Success of transfer.\"}}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"contracts/erc20/src/ZRXToken.sol\":\"ZRXToken\"},\"libraries\":{},\"optimizer\":{\"enabled\":true,\"runs\":1000000},\"remappings\":[\":@0x/contracts-erc20/=contracts/erc20/\",\":@0x/contracts-utils/=contracts/utils/\",\":ds-test/=contracts/erc20/lib/forge-std/lib/ds-test/src/\",\":forge-std/=contracts/erc20/lib/forge-std/src/\"]},\"sources\":{\"contracts/erc20/src/ZRXToken.sol\":{\"keccak256\":\"0x8582c06b20f8b7d3d603b485b5d26f840e01d1986381b334a856833edcff0d47\",\"urls\":[\"bzzr://ef728dddbaa1e26baa6cc9fe0f83de5055bc0b17dfe488018f4ee59d68ccb5dd\"]}},\"version\":1}",
 | 
			
		||||
    "metadata": {
 | 
			
		||||
        "compiler": {
 | 
			
		||||
            "version": "0.4.11+commit.68ef5810"
 | 
			
		||||
        },
 | 
			
		||||
        "language": "Solidity",
 | 
			
		||||
        "output": {
 | 
			
		||||
            "abi": [
 | 
			
		||||
                {
 | 
			
		||||
                    "inputs": [],
 | 
			
		||||
                    "type": "function",
 | 
			
		||||
                    "name": "name",
 | 
			
		||||
                    "outputs": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "",
 | 
			
		||||
                            "type": "string"
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "inputs": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "_spender",
 | 
			
		||||
                            "type": "address"
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "_value",
 | 
			
		||||
                            "type": "uint256"
 | 
			
		||||
                        }
 | 
			
		||||
                    ],
 | 
			
		||||
                    "type": "function",
 | 
			
		||||
                    "name": "approve",
 | 
			
		||||
                    "outputs": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "",
 | 
			
		||||
                            "type": "bool"
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "inputs": [],
 | 
			
		||||
                    "type": "function",
 | 
			
		||||
                    "name": "totalSupply",
 | 
			
		||||
                    "outputs": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "",
 | 
			
		||||
                            "type": "uint256"
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "inputs": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "_from",
 | 
			
		||||
                            "type": "address"
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "_to",
 | 
			
		||||
                            "type": "address"
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "_value",
 | 
			
		||||
                            "type": "uint256"
 | 
			
		||||
                        }
 | 
			
		||||
                    ],
 | 
			
		||||
                    "type": "function",
 | 
			
		||||
                    "name": "transferFrom",
 | 
			
		||||
                    "outputs": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "",
 | 
			
		||||
                            "type": "bool"
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "inputs": [],
 | 
			
		||||
                    "type": "function",
 | 
			
		||||
                    "name": "decimals",
 | 
			
		||||
                    "outputs": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "",
 | 
			
		||||
                            "type": "uint8"
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "inputs": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "_owner",
 | 
			
		||||
                            "type": "address"
 | 
			
		||||
                        }
 | 
			
		||||
                    ],
 | 
			
		||||
                    "type": "function",
 | 
			
		||||
                    "name": "balanceOf",
 | 
			
		||||
                    "outputs": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "",
 | 
			
		||||
                            "type": "uint256"
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "inputs": [],
 | 
			
		||||
                    "type": "function",
 | 
			
		||||
                    "name": "symbol",
 | 
			
		||||
                    "outputs": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "",
 | 
			
		||||
                            "type": "string"
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "inputs": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "_to",
 | 
			
		||||
                            "type": "address"
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "_value",
 | 
			
		||||
                            "type": "uint256"
 | 
			
		||||
                        }
 | 
			
		||||
                    ],
 | 
			
		||||
                    "type": "function",
 | 
			
		||||
                    "name": "transfer",
 | 
			
		||||
                    "outputs": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "",
 | 
			
		||||
                            "type": "bool"
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "inputs": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "_owner",
 | 
			
		||||
                            "type": "address"
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "_spender",
 | 
			
		||||
                            "type": "address"
 | 
			
		||||
                        }
 | 
			
		||||
                    ],
 | 
			
		||||
                    "type": "function",
 | 
			
		||||
                    "name": "allowance",
 | 
			
		||||
                    "outputs": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "",
 | 
			
		||||
                            "type": "uint256"
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "inputs": [],
 | 
			
		||||
                    "type": "constructor"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "inputs": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "_from",
 | 
			
		||||
                            "type": "address",
 | 
			
		||||
                            "indexed": true
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "_to",
 | 
			
		||||
                            "type": "address",
 | 
			
		||||
                            "indexed": true
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "_value",
 | 
			
		||||
                            "type": "uint256",
 | 
			
		||||
                            "indexed": false
 | 
			
		||||
                        }
 | 
			
		||||
                    ],
 | 
			
		||||
                    "type": "event",
 | 
			
		||||
                    "name": "Transfer",
 | 
			
		||||
                    "anonymous": false
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "inputs": [
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "_owner",
 | 
			
		||||
                            "type": "address",
 | 
			
		||||
                            "indexed": true
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "_spender",
 | 
			
		||||
                            "type": "address",
 | 
			
		||||
                            "indexed": true
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            "internalType": null,
 | 
			
		||||
                            "name": "_value",
 | 
			
		||||
                            "type": "uint256",
 | 
			
		||||
                            "indexed": false
 | 
			
		||||
                        }
 | 
			
		||||
                    ],
 | 
			
		||||
                    "type": "event",
 | 
			
		||||
                    "name": "Approval",
 | 
			
		||||
                    "anonymous": false
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "devdoc": {
 | 
			
		||||
                "methods": {
 | 
			
		||||
                    "transferFrom(address,address,uint256)": {
 | 
			
		||||
                        "details": "ERC20 transferFrom, modified such that an allowance of MAX_UINT represents an unlimited allowance.",
 | 
			
		||||
                        "params": {
 | 
			
		||||
                            "_from": "Address to transfer from.",
 | 
			
		||||
                            "_to": "Address to transfer to.",
 | 
			
		||||
                            "_value": "Amount to transfer."
 | 
			
		||||
                        },
 | 
			
		||||
                        "return": "Success of transfer."
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "userdoc": {
 | 
			
		||||
                "methods": {}
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "settings": {
 | 
			
		||||
            "remappings": [
 | 
			
		||||
                ":@0x/contracts-erc20/=contracts/erc20/",
 | 
			
		||||
                ":@0x/contracts-utils/=contracts/utils/",
 | 
			
		||||
                ":ds-test/=contracts/erc20/lib/forge-std/lib/ds-test/src/",
 | 
			
		||||
                ":forge-std/=contracts/erc20/lib/forge-std/src/"
 | 
			
		||||
            ],
 | 
			
		||||
            "optimizer": {
 | 
			
		||||
                "enabled": true,
 | 
			
		||||
                "runs": 1000000
 | 
			
		||||
            },
 | 
			
		||||
            "compilationTarget": {
 | 
			
		||||
                "contracts/erc20/src/ZRXToken.sol": "ZRXToken"
 | 
			
		||||
            },
 | 
			
		||||
            "libraries": {}
 | 
			
		||||
        },
 | 
			
		||||
        "sources": {
 | 
			
		||||
            "contracts/erc20/src/ZRXToken.sol": {
 | 
			
		||||
                "keccak256": "0x8582c06b20f8b7d3d603b485b5d26f840e01d1986381b334a856833edcff0d47",
 | 
			
		||||
                "urls": ["bzzr://ef728dddbaa1e26baa6cc9fe0f83de5055bc0b17dfe488018f4ee59d68ccb5dd"],
 | 
			
		||||
                "license": null
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "version": 1
 | 
			
		||||
    },
 | 
			
		||||
    "id": 0
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								contracts/governance/audits/0xProtocol-06-04-2023-Final.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								contracts/governance/audits/0xProtocol-06-04-2023-Final.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								contracts/governance/audits/OxProtocol-31-03-2023-Pre.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								contracts/governance/audits/OxProtocol-31-03-2023-Pre.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										37
									
								
								contracts/governance/foundry.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								contracts/governance/foundry.toml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
[profile.default]
 | 
			
		||||
src = 'src'
 | 
			
		||||
out = 'out'
 | 
			
		||||
libs = ['lib', "../utils/contracts/src/"]
 | 
			
		||||
match_path = "test/unit/*.sol"
 | 
			
		||||
fs_permissions = [{ access = "read", path = "./" }]
 | 
			
		||||
remappings = [
 | 
			
		||||
    '@openzeppelin/=./lib/openzeppelin-contracts/contracts/',
 | 
			
		||||
    '@openzeppelin-contracts-upgradeable/=./lib/openzeppelin-contracts-upgradeable/contracts/',
 | 
			
		||||
    '@0x/contracts-utils/=../utils/',
 | 
			
		||||
]
 | 
			
		||||
solc = '0.8.19'
 | 
			
		||||
optimizer_runs = 20_000
 | 
			
		||||
via_ir = true
 | 
			
		||||
 | 
			
		||||
[profile.integration]
 | 
			
		||||
match_path = "test/integration/*.sol"
 | 
			
		||||
gas_price = 31_000_000_000
 | 
			
		||||
 | 
			
		||||
[rpc_endpoints]
 | 
			
		||||
goerli = "${GOERLI_RPC_URL}"
 | 
			
		||||
mainnet = "${MAINNET_RPC_URL}"
 | 
			
		||||
 | 
			
		||||
[etherscan]
 | 
			
		||||
goerli = { key = "${ETHERSCAN_API_KEY}" }
 | 
			
		||||
 | 
			
		||||
[profile.smt.model_checker]
 | 
			
		||||
engine = 'chc'
 | 
			
		||||
timeout = 10_000
 | 
			
		||||
targets = [
 | 
			
		||||
    'assert',
 | 
			
		||||
    'constantCondition',
 | 
			
		||||
    'divByZero',
 | 
			
		||||
    'outOfBounds',
 | 
			
		||||
    'underflow'
 | 
			
		||||
]
 | 
			
		||||
contracts = { 'src/ZeroExProtocolGovernor.sol' = [ 'ZeroExProtocolGovernor' ] }
 | 
			
		||||
							
								
								
									
										1
									
								
								contracts/governance/lib/forge-std
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								contracts/governance/lib/forge-std
									
									
									
									
									
										Submodule
									
								
							 Submodule contracts/governance/lib/forge-std added at eb980e1d4f
									
								
							
							
								
								
									
										1
									
								
								contracts/governance/lib/openzeppelin-contracts
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								contracts/governance/lib/openzeppelin-contracts
									
									
									
									
									
										Submodule
									
								
							 Submodule contracts/governance/lib/openzeppelin-contracts added at d00acef405
									
								
							 Submodule contracts/governance/lib/openzeppelin-contracts-upgradeable added at f6c4c9c4ec
									
								
							
							
								
								
									
										27
									
								
								contracts/governance/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								contracts/governance/package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@0x/governance",
 | 
			
		||||
  "version": "1.0.4",
 | 
			
		||||
  "description": "Governance implementation for the 0x protocol and treasury",
 | 
			
		||||
  "main": "index.js",
 | 
			
		||||
  "directories": {
 | 
			
		||||
    "lib": "lib",
 | 
			
		||||
    "test": "test"
 | 
			
		||||
  },
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "test": "forge test",
 | 
			
		||||
    "build": "forge build",
 | 
			
		||||
    "build:smt": "FOUNDRY_PROFILE=smt forge build",
 | 
			
		||||
    "test:integration": "source .env && FOUNDRY_PROFILE=integration forge test --fork-url $MAINNET_RPC_URL --fork-block-number 16884148 -vvv",
 | 
			
		||||
    "goerli:deploy:zrxtoken": "source .env && forge script script/DeployToken.s.sol:Deploy --rpc-url $GOERLI_RPC_URL --broadcast --slow -vvvv",
 | 
			
		||||
    "goerli:deploy:governance": "source .env && forge script script/DeployGovernance.s.sol:Deploy --rpc-url $GOERLI_RPC_URL --broadcast --slow -vvvv",
 | 
			
		||||
    "mainnet:deploy:governance": "source .env && forge script script/DeployGovernance.s.sol:Deploy --rpc-url $MAINNET_RPC_URL --broadcast --slow -vvvv"
 | 
			
		||||
  },
 | 
			
		||||
  "repository": {
 | 
			
		||||
    "type": "git",
 | 
			
		||||
    "url": "https://github.com/0xProject/protocol.git"
 | 
			
		||||
  },
 | 
			
		||||
  "publishConfig": {
 | 
			
		||||
    "access": "public"
 | 
			
		||||
  },
 | 
			
		||||
  "license": "Apache-2.0"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										80
									
								
								contracts/governance/script/DeployGovernance.s.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								contracts/governance/script/DeployGovernance.s.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,80 @@
 | 
			
		||||
// SPDX-License-Identifier: UNLICENSED
 | 
			
		||||
pragma solidity ^0.8.19;
 | 
			
		||||
 | 
			
		||||
import "forge-std/Script.sol";
 | 
			
		||||
import "forge-std/console.sol";
 | 
			
		||||
import "forge-std/console2.sol";
 | 
			
		||||
import "@openzeppelin/token/ERC20/IERC20.sol";
 | 
			
		||||
import "@openzeppelin/proxy/ERC1967/ERC1967Proxy.sol";
 | 
			
		||||
 | 
			
		||||
import "../src/ZRXWrappedToken.sol";
 | 
			
		||||
import "../src/ZeroExVotes.sol";
 | 
			
		||||
import "../src/ZeroExTimelock.sol";
 | 
			
		||||
import "../src/ZeroExProtocolGovernor.sol";
 | 
			
		||||
import "../src/ZeroExTreasuryGovernor.sol";
 | 
			
		||||
 | 
			
		||||
contract Deploy is Script {
 | 
			
		||||
    address internal constant ZRX_TOKEN = 0xE41d2489571d322189246DaFA5ebDe1F4699F498;
 | 
			
		||||
    address internal constant TREASURY = 0x0bB1810061C2f5b2088054eE184E6C79e1591101;
 | 
			
		||||
    address internal constant EXCHANGE = 0xDef1C0ded9bec7F1a1670819833240f027b25EfF;
 | 
			
		||||
    address payable internal constant SECURITY_COUNCIL = payable(0x979BDb496e5f0A00af078b7a45F1E9E6bcff170F);
 | 
			
		||||
    uint256 internal constant QUADRATIC_THRESHOLD = 1000000e18;
 | 
			
		||||
 | 
			
		||||
    function setUp() public {}
 | 
			
		||||
 | 
			
		||||
    function run() external {
 | 
			
		||||
        address deployer = vm.envAddress("DEPLOYER");
 | 
			
		||||
        vm.startBroadcast(deployer);
 | 
			
		||||
 | 
			
		||||
        console2.log("Zrx Token", ZRX_TOKEN);
 | 
			
		||||
        address wTokenPrediction = predict(deployer, vm.getNonce(deployer) + 2);
 | 
			
		||||
        ZeroExVotes votesImpl = new ZeroExVotes(wTokenPrediction, QUADRATIC_THRESHOLD);
 | 
			
		||||
        ERC1967Proxy votesProxy = new ERC1967Proxy(address(votesImpl), abi.encodeCall(votesImpl.initialize, ()));
 | 
			
		||||
        ZRXWrappedToken wToken = new ZRXWrappedToken(IERC20(ZRX_TOKEN), ZeroExVotes(address(votesProxy)));
 | 
			
		||||
 | 
			
		||||
        assert(address(wToken) == wTokenPrediction);
 | 
			
		||||
        console2.log("Wrapped Token", address(wToken));
 | 
			
		||||
 | 
			
		||||
        ZeroExVotes votes = ZeroExVotes(address(votesProxy));
 | 
			
		||||
        console2.log("Votes", address(votes));
 | 
			
		||||
 | 
			
		||||
        address[] memory proposers = new address[](0);
 | 
			
		||||
        address[] memory executors = new address[](0);
 | 
			
		||||
 | 
			
		||||
        ZeroExTimelock protocolTimelock = new ZeroExTimelock(3 days, proposers, executors, deployer);
 | 
			
		||||
        console2.log("Protocol timelock", address(protocolTimelock));
 | 
			
		||||
 | 
			
		||||
        ZeroExProtocolGovernor protocolGovernor = new ZeroExProtocolGovernor(
 | 
			
		||||
            IVotes(address(votes)),
 | 
			
		||||
            protocolTimelock,
 | 
			
		||||
            SECURITY_COUNCIL
 | 
			
		||||
        );
 | 
			
		||||
        protocolTimelock.grantRole(protocolTimelock.PROPOSER_ROLE(), address(protocolGovernor));
 | 
			
		||||
        protocolTimelock.grantRole(protocolTimelock.EXECUTOR_ROLE(), address(protocolGovernor));
 | 
			
		||||
        protocolTimelock.grantRole(protocolTimelock.CANCELLER_ROLE(), address(protocolGovernor));
 | 
			
		||||
        protocolTimelock.renounceRole(protocolTimelock.TIMELOCK_ADMIN_ROLE(), deployer);
 | 
			
		||||
        console2.log("Protocol governor", address(protocolGovernor));
 | 
			
		||||
 | 
			
		||||
        ZeroExTimelock treasuryTimelock = new ZeroExTimelock(2 days, proposers, executors, deployer);
 | 
			
		||||
        console2.log("Treasury timelock", address(treasuryTimelock));
 | 
			
		||||
 | 
			
		||||
        ZeroExTreasuryGovernor treasuryGovernor = new ZeroExTreasuryGovernor(
 | 
			
		||||
            IVotes(address(votes)),
 | 
			
		||||
            treasuryTimelock,
 | 
			
		||||
            SECURITY_COUNCIL
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        treasuryTimelock.grantRole(treasuryTimelock.PROPOSER_ROLE(), address(treasuryGovernor));
 | 
			
		||||
        treasuryTimelock.grantRole(treasuryTimelock.EXECUTOR_ROLE(), address(treasuryGovernor));
 | 
			
		||||
        treasuryTimelock.grantRole(treasuryTimelock.CANCELLER_ROLE(), address(treasuryGovernor));
 | 
			
		||||
        treasuryTimelock.renounceRole(treasuryTimelock.TIMELOCK_ADMIN_ROLE(), deployer);
 | 
			
		||||
        console2.log("Treasury governor", address(treasuryGovernor));
 | 
			
		||||
        console2.log(unicode"0x governance deployed successfully 🎉");
 | 
			
		||||
        vm.stopBroadcast();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function predict(address deployer, uint256 nonce) internal pure returns (address) {
 | 
			
		||||
        require(nonce > 0 && nonce < 128, "Invalid nonce");
 | 
			
		||||
        return address(uint160(uint256(keccak256(abi.encodePacked(bytes2(0xd694), deployer, bytes1(uint8(nonce)))))));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								contracts/governance/script/DeployToken.s.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								contracts/governance/script/DeployToken.s.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
// SPDX-License-Identifier: UNLICENSED
 | 
			
		||||
pragma solidity ^0.8.19;
 | 
			
		||||
 | 
			
		||||
import "forge-std/Script.sol";
 | 
			
		||||
import "forge-std/console2.sol";
 | 
			
		||||
 | 
			
		||||
contract Deploy is Script {
 | 
			
		||||
    function setUp() public {}
 | 
			
		||||
 | 
			
		||||
    function run() external {
 | 
			
		||||
        vm.startBroadcast(vm.envAddress("DEPLOYER"));
 | 
			
		||||
 | 
			
		||||
        bytes memory _bytecode = vm.getCode("./ZRXToken.json");
 | 
			
		||||
        address zrxToken;
 | 
			
		||||
        assembly {
 | 
			
		||||
            zrxToken := create(0, add(_bytecode, 0x20), mload(_bytecode))
 | 
			
		||||
        }
 | 
			
		||||
        console2.log("Zrx Token", zrxToken);
 | 
			
		||||
        console2.log(unicode"Zrx Token deployed successfully 🎉");
 | 
			
		||||
        vm.stopBroadcast();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										169
									
								
								contracts/governance/src/CallWithGas.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								contracts/governance/src/CallWithGas.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,169 @@
 | 
			
		||||
// SPDX-License-Identifier: MIT
 | 
			
		||||
pragma solidity 0.8.19;
 | 
			
		||||
 | 
			
		||||
library CallWithGas {
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice `staticcall` another contract forwarding a precomputed amount of
 | 
			
		||||
     *         gas.
 | 
			
		||||
     * @dev contains protections against EIP-150-induced insufficient gas
 | 
			
		||||
     *      griefing
 | 
			
		||||
     * @dev reverts iff the target is not a contract or we encounter an
 | 
			
		||||
     *      out-of-gas
 | 
			
		||||
     * @return success true iff the call succeded and returned no more than
 | 
			
		||||
     *                 `maxReturnBytes` of return data
 | 
			
		||||
     * @return returnData the return data or revert reason of the call
 | 
			
		||||
     * @param target the contract (reverts if non-contract) on which to make the
 | 
			
		||||
     *               `staticcall`
 | 
			
		||||
     * @param data the calldata to pass
 | 
			
		||||
     * @param callGas the gas to pass for the call. If the call requires more than
 | 
			
		||||
     *                the specified amount of gas and the caller didn't provide at
 | 
			
		||||
     *                least `callGas`, triggers an out-of-gas in the caller.
 | 
			
		||||
     * @param maxReturnBytes Only this many bytes of return data are read back
 | 
			
		||||
     *                       from the call. This prevents griefing the caller. If
 | 
			
		||||
     *                       more bytes are returned or the revert reason is
 | 
			
		||||
     *                       longer, success will be false and returnData will be
 | 
			
		||||
     *                       `abi.encodeWithSignature("Error(string)", "CallWithGas: returnData too long")`
 | 
			
		||||
     */
 | 
			
		||||
    function functionStaticCallWithGas(
 | 
			
		||||
        address target,
 | 
			
		||||
        bytes memory data,
 | 
			
		||||
        uint256 callGas,
 | 
			
		||||
        uint256 maxReturnBytes
 | 
			
		||||
    ) internal view returns (bool success, bytes memory returnData) {
 | 
			
		||||
        assembly ("memory-safe") {
 | 
			
		||||
            returnData := mload(0x40)
 | 
			
		||||
            success := staticcall(callGas, target, add(data, 0x20), mload(data), add(returnData, 0x20), maxReturnBytes)
 | 
			
		||||
 | 
			
		||||
            // As of the time this contract was written, `verbatim` doesn't work in
 | 
			
		||||
            // inline assembly.  Assignment of a value to a variable costs gas
 | 
			
		||||
            // (although how much is unpredictable because it depends on the Yul/IR
 | 
			
		||||
            // optimizer), as does the `GAS` opcode itself. Also solc tends to reorder
 | 
			
		||||
            // the call to `gas()` with preparing the arguments for `div`. Therefore,
 | 
			
		||||
            // the `gas()` below returns less than the actual amount of gas available
 | 
			
		||||
            // for computation at the end of the call. That makes this check slightly
 | 
			
		||||
            // too conservative. However, we do not correct for this because the
 | 
			
		||||
            // correction would become outdated (possibly too permissive) if the
 | 
			
		||||
            // opcodes are repriced.
 | 
			
		||||
 | 
			
		||||
            // https://eips.ethereum.org/EIPS/eip-150
 | 
			
		||||
            // https://ronan.eth.link/blog/ethereum-gas-dangers/
 | 
			
		||||
            if iszero(or(success, or(returndatasize(), lt(div(callGas, 63), gas())))) {
 | 
			
		||||
                // The call failed due to not enough gas left. We deliberately consume
 | 
			
		||||
                // all remaining gas with `invalid` (instead of `revert`) to make this
 | 
			
		||||
                // failure distinguishable to our caller.
 | 
			
		||||
                invalid()
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            switch gt(returndatasize(), maxReturnBytes)
 | 
			
		||||
            case 0 {
 | 
			
		||||
                switch returndatasize()
 | 
			
		||||
                case 0 {
 | 
			
		||||
                    returnData := 0x60
 | 
			
		||||
                    success := and(success, iszero(iszero(extcodesize(target))))
 | 
			
		||||
                }
 | 
			
		||||
                default {
 | 
			
		||||
                    mstore(returnData, returndatasize())
 | 
			
		||||
                    mstore(0x40, add(returnData, add(0x20, returndatasize())))
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            default {
 | 
			
		||||
                // returnData = abi.encodeWithSignature("Error(string)", "CallWithGas: returnData too long")
 | 
			
		||||
                success := 0
 | 
			
		||||
                mstore(returnData, 0) // clear potentially dirty bits
 | 
			
		||||
                mstore(add(returnData, 0x04), 0x6408c379a0) // length and selector
 | 
			
		||||
                mstore(add(returnData, 0x24), 0x20)
 | 
			
		||||
                mstore(add(returnData, 0x44), 0x20)
 | 
			
		||||
                mstore(add(returnData, 0x64), "CallWithGas: returnData too long")
 | 
			
		||||
                mstore(0x40, add(returnData, 0x84))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// See `functionCallWithGasAndValue`
 | 
			
		||||
    function functionCallWithGas(
 | 
			
		||||
        address target,
 | 
			
		||||
        bytes memory data,
 | 
			
		||||
        uint256 callGas,
 | 
			
		||||
        uint256 maxReturnBytes
 | 
			
		||||
    ) internal returns (bool success, bytes memory returnData) {
 | 
			
		||||
        return functionCallWithGasAndValue(payable(target), data, callGas, 0, maxReturnBytes);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @notice `call` another contract forwarding a precomputed amount of gas.
 | 
			
		||||
     * @notice Unlike `functionStaticCallWithGas`, a failure is not signaled if
 | 
			
		||||
     *         there is too much return data. Instead, it is simply truncated.
 | 
			
		||||
     * @dev contains protections against EIP-150-induced insufficient gas griefing
 | 
			
		||||
     * @dev reverts iff caller doesn't have enough native asset balance, the
 | 
			
		||||
     *      target is not a contract, or due to out-of-gas
 | 
			
		||||
     * @return success true iff the call succeded
 | 
			
		||||
     * @return returnData the return data or revert reason of the call
 | 
			
		||||
     * @param target the contract (reverts if non-contract) on which to make the
 | 
			
		||||
     *               `call`
 | 
			
		||||
     * @param data the calldata to pass
 | 
			
		||||
     * @param callGas the gas to pass for the call. If the call requires more than
 | 
			
		||||
     *                the specified amount of gas and the caller didn't provide at
 | 
			
		||||
     *                least `callGas`, triggers an out-of-gas in the caller.
 | 
			
		||||
     * @param value the amount of the native asset in wei to pass to the callee
 | 
			
		||||
     *              with the call
 | 
			
		||||
     * @param maxReturnBytes Only this many bytes of return data/revert reason are
 | 
			
		||||
     *                       read back from the call. This prevents griefing the
 | 
			
		||||
     *                       caller. If more bytes are returned or the revert
 | 
			
		||||
     *                       reason is longer, returnData will be truncated
 | 
			
		||||
     */
 | 
			
		||||
    function functionCallWithGasAndValue(
 | 
			
		||||
        address payable target,
 | 
			
		||||
        bytes memory data,
 | 
			
		||||
        uint256 callGas,
 | 
			
		||||
        uint256 value,
 | 
			
		||||
        uint256 maxReturnBytes
 | 
			
		||||
    ) internal returns (bool success, bytes memory returnData) {
 | 
			
		||||
        if (value > 0 && (address(this).balance < value || target.code.length == 0)) {
 | 
			
		||||
            return (success, returnData);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        assembly ("memory-safe") {
 | 
			
		||||
            returnData := mload(0x40)
 | 
			
		||||
            success := call(callGas, target, value, add(data, 0x20), mload(data), add(returnData, 0x20), maxReturnBytes)
 | 
			
		||||
 | 
			
		||||
            // As of the time this contract was written, `verbatim` doesn't work in
 | 
			
		||||
            // inline assembly.  Assignment of a value to a variable costs gas
 | 
			
		||||
            // (although how much is unpredictable because it depends on the Yul/IR
 | 
			
		||||
            // optimizer), as does the `GAS` opcode itself. Also solc tends to reorder
 | 
			
		||||
            // the call to `gas()` with preparing the arguments for `div`. Therefore,
 | 
			
		||||
            // the `gas()` below returns less than the actual amount of gas available
 | 
			
		||||
            // for computation at the end of the call. That makes this check slightly
 | 
			
		||||
            // too conservative. However, we do not correct for this because the
 | 
			
		||||
            // correction would become outdated (possibly too permissive) if the
 | 
			
		||||
            // opcodes are repriced.
 | 
			
		||||
 | 
			
		||||
            // https://eips.ethereum.org/EIPS/eip-150
 | 
			
		||||
            // https://ronan.eth.link/blog/ethereum-gas-dangers/
 | 
			
		||||
            if iszero(or(success, or(returndatasize(), lt(div(callGas, 63), gas())))) {
 | 
			
		||||
                // The call failed due to not enough gas left. We deliberately consume
 | 
			
		||||
                // all remaining gas with `invalid` (instead of `revert`) to make this
 | 
			
		||||
                // failure distinguishable to our caller.
 | 
			
		||||
                invalid()
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            switch gt(returndatasize(), maxReturnBytes)
 | 
			
		||||
            case 0 {
 | 
			
		||||
                switch returndatasize()
 | 
			
		||||
                case 0 {
 | 
			
		||||
                    returnData := 0x60
 | 
			
		||||
                    if iszero(value) {
 | 
			
		||||
                        success := and(success, iszero(iszero(extcodesize(target))))
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                default {
 | 
			
		||||
                    mstore(returnData, returndatasize())
 | 
			
		||||
                    mstore(0x40, add(returnData, add(0x20, returndatasize())))
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            default {
 | 
			
		||||
                mstore(returnData, maxReturnBytes)
 | 
			
		||||
                mstore(0x40, add(returnData, add(0x20, maxReturnBytes)))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								contracts/governance/src/IZeroExGovernor.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								contracts/governance/src/IZeroExGovernor.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2023 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.8.19;
 | 
			
		||||
 | 
			
		||||
import "./SecurityCouncil.sol";
 | 
			
		||||
import "@openzeppelin/governance/IGovernor.sol";
 | 
			
		||||
import "@openzeppelin/governance/extensions/IGovernorTimelock.sol";
 | 
			
		||||
 | 
			
		||||
abstract contract IZeroExGovernor is SecurityCouncil, IGovernor, IGovernorTimelock {
 | 
			
		||||
    function token() public virtual returns (address);
 | 
			
		||||
 | 
			
		||||
    function proposalThreshold() public view virtual returns (uint256);
 | 
			
		||||
 | 
			
		||||
    function setVotingDelay(uint256 newVotingDelay) public virtual;
 | 
			
		||||
 | 
			
		||||
    function setVotingPeriod(uint256 newVotingPeriod) public virtual;
 | 
			
		||||
 | 
			
		||||
    function setProposalThreshold(uint256 newProposalThreshold) public virtual;
 | 
			
		||||
 | 
			
		||||
    function proposalVotes(
 | 
			
		||||
        uint256 proposalId
 | 
			
		||||
    ) public view virtual returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										132
									
								
								contracts/governance/src/IZeroExVotes.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								contracts/governance/src/IZeroExVotes.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,132 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2023 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.8.19;
 | 
			
		||||
 | 
			
		||||
interface IZeroExVotes {
 | 
			
		||||
    struct Checkpoint {
 | 
			
		||||
        uint32 fromBlock;
 | 
			
		||||
        uint96 votes;
 | 
			
		||||
        uint96 quadraticVotes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Emitted when a token transfer or delegate change,
 | 
			
		||||
     * results in changes to a delegate's quadratic number of votes.
 | 
			
		||||
     */
 | 
			
		||||
    event DelegateQuadraticVotesChanged(
 | 
			
		||||
        address indexed delegate,
 | 
			
		||||
        uint256 previousQuadraticBalance,
 | 
			
		||||
        uint256 newQuadraticBalance
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Emitted when a token transfer or delegate change, results in changes to a delegate's number of votes.
 | 
			
		||||
     */
 | 
			
		||||
    event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Emitted when the total supply of the token is changed due to minting and burning which results in
 | 
			
		||||
     * the total supply checkpoint being writtenor updated.
 | 
			
		||||
     */
 | 
			
		||||
    event TotalSupplyChanged(uint256 totalSupplyVotes, uint256 totalSupplyQuadraticVotes);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Get the `pos`-th checkpoint for `account`.
 | 
			
		||||
     */
 | 
			
		||||
    function checkpoints(address account, uint32 pos) external view returns (Checkpoint memory);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Get number of checkpoints for `account`.
 | 
			
		||||
     */
 | 
			
		||||
    function numCheckpoints(address account) external view returns (uint32);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Gets the current votes balance for `account`
 | 
			
		||||
     */
 | 
			
		||||
    function getVotes(address account) external view returns (uint256);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Gets the current quadratic votes balance for `account`
 | 
			
		||||
     */
 | 
			
		||||
    function getQuadraticVotes(address account) external view returns (uint256);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Retrieve the number of votes for `account` at the end of `blockNumber`.
 | 
			
		||||
     *
 | 
			
		||||
     * Requirements:
 | 
			
		||||
     *
 | 
			
		||||
     * - `blockNumber` must have been already mined
 | 
			
		||||
     */
 | 
			
		||||
    function getPastVotes(address account, uint256 blockNumber) external view returns (uint256);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Retrieve the number of quadratic votes for `account` at the end of `blockNumber`.
 | 
			
		||||
     *
 | 
			
		||||
     * Requirements:
 | 
			
		||||
     *
 | 
			
		||||
     * - `blockNumber` must have been already mined
 | 
			
		||||
     */
 | 
			
		||||
    function getPastQuadraticVotes(address account, uint256 blockNumber) external view returns (uint256);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances.
 | 
			
		||||
     * It is but NOT the sum of all the delegated votes!
 | 
			
		||||
     *
 | 
			
		||||
     * Requirements:
 | 
			
		||||
     *
 | 
			
		||||
     * - `blockNumber` must have been already mined
 | 
			
		||||
     */
 | 
			
		||||
    function getPastTotalSupply(uint256 blockNumber) external view returns (uint256);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Retrieve the sqrt of `totalSupply` at the end of `blockNumber`. Note, this value is the square root of the
 | 
			
		||||
     * sum of all balances.
 | 
			
		||||
     * It is but NOT the sum of all the sqrt of the delegated votes!
 | 
			
		||||
     *
 | 
			
		||||
     * Requirements:
 | 
			
		||||
     *
 | 
			
		||||
     * - `blockNumber` must have been already mined
 | 
			
		||||
     */
 | 
			
		||||
    function getPastQuadraticTotalSupply(uint256 blockNumber) external view returns (uint256);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Moves the voting power corresponding to `amount` number of tokens from `src` to `dst`.
 | 
			
		||||
     * Note that if the delegator isn't delegating to anyone before the function call `src` = address(0)
 | 
			
		||||
     * @param src the delegatee we are moving voting power away from
 | 
			
		||||
     * @param dst the delegatee we are moving voting power to
 | 
			
		||||
     * @param srcBalance balance of the delegator whose delegatee is `src`. This is value _after_ the transfer.
 | 
			
		||||
     * @param dstBalance balance of the delegator whose delegatee is `dst`. This is value _after_ the transfer.
 | 
			
		||||
     * @param srcBalanceLastUpdated block number when balance of `src` was last updated.
 | 
			
		||||
     * @param dstBalanceLastUpdated block number when balance of `dst` was last updated.
 | 
			
		||||
     * @param amount The amount of tokens transferred from the source delegate to destination delegate.
 | 
			
		||||
     */
 | 
			
		||||
    function moveVotingPower(
 | 
			
		||||
        address src,
 | 
			
		||||
        address dst,
 | 
			
		||||
        uint256 srcBalance,
 | 
			
		||||
        uint256 dstBalance,
 | 
			
		||||
        uint96 srcBalanceLastUpdated,
 | 
			
		||||
        uint96 dstBalanceLastUpdated,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    ) external returns (bool);
 | 
			
		||||
 | 
			
		||||
    function writeCheckpointTotalSupplyMint(uint256 accountBalance, uint256 amount) external returns (bool);
 | 
			
		||||
 | 
			
		||||
    function writeCheckpointTotalSupplyBurn(uint256 accountBalance, uint256 amount) external returns (bool);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										85
									
								
								contracts/governance/src/SecurityCouncil.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								contracts/governance/src/SecurityCouncil.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2023 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.8.19;
 | 
			
		||||
 | 
			
		||||
abstract contract SecurityCouncil {
 | 
			
		||||
    address public securityCouncil;
 | 
			
		||||
 | 
			
		||||
    event SecurityCouncilAssigned(address securityCouncil);
 | 
			
		||||
 | 
			
		||||
    event SecurityCouncilEjected();
 | 
			
		||||
 | 
			
		||||
    modifier onlySecurityCouncil() {
 | 
			
		||||
        _checkSenderIsSecurityCouncil();
 | 
			
		||||
        _;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Checks that either a security council is assigned or the payloads array is a council assignment call.
 | 
			
		||||
     */
 | 
			
		||||
    modifier securityCouncilAssigned(bytes[] memory payloads) {
 | 
			
		||||
        if (securityCouncil == address(0) && !_payloadIsAssignSecurityCouncil(payloads)) {
 | 
			
		||||
            revert("SecurityCouncil: security council not assigned and this is not an assignment call");
 | 
			
		||||
        }
 | 
			
		||||
        _;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Assigns new security council.
 | 
			
		||||
     */
 | 
			
		||||
    function assignSecurityCouncil(address _securityCouncil) public virtual {
 | 
			
		||||
        securityCouncil = _securityCouncil;
 | 
			
		||||
 | 
			
		||||
        emit SecurityCouncilAssigned(securityCouncil);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Ejects the current security council via setting the security council address to 0.
 | 
			
		||||
     * Security council is ejected after they either cancel a proposal or execute a protocol rollback.
 | 
			
		||||
     */
 | 
			
		||||
    function ejectSecurityCouncil() internal {
 | 
			
		||||
        securityCouncil = address(0);
 | 
			
		||||
        emit SecurityCouncilEjected();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Cancel existing proposal with the submitted `targets`, `values`, `calldatas` and `descriptionHash`.
 | 
			
		||||
     */
 | 
			
		||||
    function cancel(
 | 
			
		||||
        address[] memory targets,
 | 
			
		||||
        uint256[] memory values,
 | 
			
		||||
        bytes[] memory calldatas,
 | 
			
		||||
        bytes32 descriptionHash
 | 
			
		||||
    ) public virtual;
 | 
			
		||||
 | 
			
		||||
    function _payloadIsAssignSecurityCouncil(bytes[] memory payloads) private pure returns (bool) {
 | 
			
		||||
        require(payloads.length == 1, "SecurityCouncil: more than 1 transaction in proposal");
 | 
			
		||||
        bytes memory payload = payloads[0];
 | 
			
		||||
        // Check this is as assignSecurityCouncil(address) transaction
 | 
			
		||||
        // function signature for assignSecurityCouncil(address)
 | 
			
		||||
        // = bytes4(keccak256("assignSecurityCouncil(address)"))
 | 
			
		||||
        // = 0x2761c3cd
 | 
			
		||||
        if (bytes4(payload) == bytes4(0x2761c3cd)) return true;
 | 
			
		||||
        else return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _checkSenderIsSecurityCouncil() private view {
 | 
			
		||||
        require(msg.sender == securityCouncil, "SecurityCouncil: only security council allowed");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										164
									
								
								contracts/governance/src/ZRXWrappedToken.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								contracts/governance/src/ZRXWrappedToken.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,164 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2023 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.8.19;
 | 
			
		||||
 | 
			
		||||
import "@openzeppelin/token/ERC20/ERC20.sol";
 | 
			
		||||
import "@openzeppelin/token/ERC20/extensions/draft-ERC20Permit.sol";
 | 
			
		||||
import "@openzeppelin/token/ERC20/extensions/ERC20Wrapper.sol";
 | 
			
		||||
import "@openzeppelin/governance/utils/IVotes.sol";
 | 
			
		||||
import "@openzeppelin/utils/math/SafeCast.sol";
 | 
			
		||||
import "./IZeroExVotes.sol";
 | 
			
		||||
import "./CallWithGas.sol";
 | 
			
		||||
 | 
			
		||||
contract ZRXWrappedToken is ERC20, ERC20Permit, ERC20Wrapper {
 | 
			
		||||
    using CallWithGas for address;
 | 
			
		||||
 | 
			
		||||
    struct DelegateInfo {
 | 
			
		||||
        address delegate;
 | 
			
		||||
        uint96 balanceLastUpdated;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    constructor(
 | 
			
		||||
        IERC20 wrappedToken,
 | 
			
		||||
        IZeroExVotes _zeroExVotes
 | 
			
		||||
    ) ERC20("Wrapped ZRX", "wZRX") ERC20Permit("Wrapped ZRX") ERC20Wrapper(wrappedToken) {
 | 
			
		||||
        zeroExVotes = _zeroExVotes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    IZeroExVotes public immutable zeroExVotes;
 | 
			
		||||
    mapping(address => DelegateInfo) private _delegates;
 | 
			
		||||
 | 
			
		||||
    bytes32 private constant _DELEGATION_TYPEHASH =
 | 
			
		||||
        keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Emitted when an account changes their delegate.
 | 
			
		||||
     */
 | 
			
		||||
    event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
 | 
			
		||||
 | 
			
		||||
    // The functions below are the required overrides from the base contracts
 | 
			
		||||
 | 
			
		||||
    function decimals() public pure override(ERC20, ERC20Wrapper) returns (uint8) {
 | 
			
		||||
        return 18;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _afterTokenTransfer(address from, address to, uint256 amount) internal override(ERC20) {
 | 
			
		||||
        super._afterTokenTransfer(from, to, amount);
 | 
			
		||||
 | 
			
		||||
        DelegateInfo memory fromDelegate = delegateInfo(from);
 | 
			
		||||
        DelegateInfo memory toDelegate = delegateInfo(to);
 | 
			
		||||
 | 
			
		||||
        uint256 fromBalance = fromDelegate.delegate == address(0) ? 0 : balanceOf(from) + amount;
 | 
			
		||||
        uint256 toBalance = toDelegate.delegate == address(0) ? 0 : balanceOf(to) - amount;
 | 
			
		||||
 | 
			
		||||
        if (fromDelegate.delegate != address(0)) _delegates[from].balanceLastUpdated = SafeCast.toUint96(block.number);
 | 
			
		||||
 | 
			
		||||
        if (toDelegate.delegate != address(0)) _delegates[to].balanceLastUpdated = SafeCast.toUint96(block.number);
 | 
			
		||||
 | 
			
		||||
        zeroExVotes.moveVotingPower(
 | 
			
		||||
            fromDelegate.delegate,
 | 
			
		||||
            toDelegate.delegate,
 | 
			
		||||
            fromBalance,
 | 
			
		||||
            toBalance,
 | 
			
		||||
            fromDelegate.balanceLastUpdated,
 | 
			
		||||
            toDelegate.balanceLastUpdated,
 | 
			
		||||
            amount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _mint(address account, uint256 amount) internal override(ERC20) {
 | 
			
		||||
        super._mint(account, amount);
 | 
			
		||||
 | 
			
		||||
        zeroExVotes.writeCheckpointTotalSupplyMint(balanceOf(account) - amount, amount);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _burn(address account, uint256 amount) internal override(ERC20) {
 | 
			
		||||
        super._burn(account, amount);
 | 
			
		||||
 | 
			
		||||
        address(zeroExVotes).functionCallWithGas(
 | 
			
		||||
            abi.encodeCall(zeroExVotes.writeCheckpointTotalSupplyBurn, (balanceOf(account) + amount, amount)),
 | 
			
		||||
            500_000,
 | 
			
		||||
            32
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Get the address `account` is currently delegating to.
 | 
			
		||||
     */
 | 
			
		||||
    function delegates(address account) public view returns (address) {
 | 
			
		||||
        return _delegates[account].delegate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Get the last block number when `account`'s balance changed.
 | 
			
		||||
     */
 | 
			
		||||
    function delegatorBalanceLastUpdated(address account) public view returns (uint96) {
 | 
			
		||||
        return _delegates[account].balanceLastUpdated;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function delegateInfo(address account) public view returns (DelegateInfo memory) {
 | 
			
		||||
        return _delegates[account];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Delegate votes from the sender to `delegatee`.
 | 
			
		||||
     */
 | 
			
		||||
    function delegate(address delegatee) public {
 | 
			
		||||
        _delegate(_msgSender(), delegatee);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Delegates votes from signer to `delegatee`
 | 
			
		||||
     */
 | 
			
		||||
    function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) public {
 | 
			
		||||
        require(block.timestamp <= expiry, "ERC20Votes: signature expired");
 | 
			
		||||
        address signer = ECDSA.recover(
 | 
			
		||||
            _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),
 | 
			
		||||
            v,
 | 
			
		||||
            r,
 | 
			
		||||
            s
 | 
			
		||||
        );
 | 
			
		||||
        require(nonce == _useNonce(signer), "ERC20Votes: invalid nonce");
 | 
			
		||||
        _delegate(signer, delegatee);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Change delegation for `delegator` to `delegatee`.
 | 
			
		||||
     *
 | 
			
		||||
     * Emits events {DelegateChanged} and {IZeroExVotes-DelegateVotesChanged}.
 | 
			
		||||
     */
 | 
			
		||||
    function _delegate(address delegator, address delegatee) internal virtual {
 | 
			
		||||
        DelegateInfo memory delegateInfo = delegateInfo(delegator);
 | 
			
		||||
        uint256 delegatorBalance = balanceOf(delegator);
 | 
			
		||||
 | 
			
		||||
        _delegates[delegator] = DelegateInfo(delegatee, SafeCast.toUint96(block.timestamp));
 | 
			
		||||
 | 
			
		||||
        emit DelegateChanged(delegator, delegateInfo.delegate, delegatee);
 | 
			
		||||
 | 
			
		||||
        zeroExVotes.moveVotingPower(
 | 
			
		||||
            delegateInfo.delegate,
 | 
			
		||||
            delegatee,
 | 
			
		||||
            delegatorBalance,
 | 
			
		||||
            0,
 | 
			
		||||
            delegateInfo.balanceLastUpdated,
 | 
			
		||||
            0,
 | 
			
		||||
            delegatorBalance
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										145
									
								
								contracts/governance/src/ZeroExProtocolGovernor.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								contracts/governance/src/ZeroExProtocolGovernor.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,145 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2023 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.8.19;
 | 
			
		||||
 | 
			
		||||
import "./SecurityCouncil.sol";
 | 
			
		||||
import "./ZeroExTimelock.sol";
 | 
			
		||||
import "@openzeppelin/governance/Governor.sol";
 | 
			
		||||
import "@openzeppelin/governance/extensions/GovernorSettings.sol";
 | 
			
		||||
import "@openzeppelin/governance/extensions/GovernorCountingSimple.sol";
 | 
			
		||||
import "@openzeppelin/governance/extensions/GovernorVotes.sol";
 | 
			
		||||
import "@openzeppelin/governance/extensions/GovernorTimelockControl.sol";
 | 
			
		||||
 | 
			
		||||
contract ZeroExProtocolGovernor is
 | 
			
		||||
    SecurityCouncil,
 | 
			
		||||
    Governor,
 | 
			
		||||
    GovernorSettings,
 | 
			
		||||
    GovernorCountingSimple,
 | 
			
		||||
    GovernorVotes,
 | 
			
		||||
    GovernorTimelockControl
 | 
			
		||||
{
 | 
			
		||||
    constructor(
 | 
			
		||||
        IVotes _votes,
 | 
			
		||||
        ZeroExTimelock _timelock,
 | 
			
		||||
        address _securityCouncil
 | 
			
		||||
    )
 | 
			
		||||
        Governor("ZeroExProtocolGovernor")
 | 
			
		||||
        GovernorSettings(14400 /* 2 days */, 50400 /* 7 days */, 1000000e18)
 | 
			
		||||
        GovernorVotes(_votes)
 | 
			
		||||
        GovernorTimelockControl(TimelockController(payable(_timelock)))
 | 
			
		||||
    {
 | 
			
		||||
        securityCouncil = _securityCouncil;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function quorum(uint256 blockNumber) public pure override returns (uint256) {
 | 
			
		||||
        return 10000000e18;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // The following functions are overrides required by Solidity.
 | 
			
		||||
 | 
			
		||||
    function votingDelay() public view override(IGovernor, GovernorSettings) returns (uint256) {
 | 
			
		||||
        return super.votingDelay();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function votingPeriod() public view override(IGovernor, GovernorSettings) returns (uint256) {
 | 
			
		||||
        return super.votingPeriod();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function state(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (ProposalState) {
 | 
			
		||||
        return super.state(proposalId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function propose(
 | 
			
		||||
        address[] memory targets,
 | 
			
		||||
        uint256[] memory values,
 | 
			
		||||
        bytes[] memory calldatas,
 | 
			
		||||
        string memory description
 | 
			
		||||
    ) public override(Governor, IGovernor) securityCouncilAssigned(calldatas) returns (uint256) {
 | 
			
		||||
        return super.propose(targets, values, calldatas, description);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) {
 | 
			
		||||
        return super.proposalThreshold();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function cancel(
 | 
			
		||||
        address[] memory targets,
 | 
			
		||||
        uint256[] memory values,
 | 
			
		||||
        bytes[] memory calldatas,
 | 
			
		||||
        bytes32 descriptionHash
 | 
			
		||||
    ) public override onlySecurityCouncil {
 | 
			
		||||
        _cancel(targets, values, calldatas, descriptionHash);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Like the GovernorTimelockControl.queue function but without the proposal checks,
 | 
			
		||||
    // (as there's effectively no proposal).
 | 
			
		||||
    // And also using a delay of 0 as opposed to the minimum delay of the timelock
 | 
			
		||||
    function executeRollback(
 | 
			
		||||
        address[] memory targets,
 | 
			
		||||
        uint256[] memory values,
 | 
			
		||||
        bytes[] memory calldatas,
 | 
			
		||||
        bytes32 descriptionHash
 | 
			
		||||
    ) public onlySecurityCouncil {
 | 
			
		||||
        // Execute the batch of rollbacks via the timelock controller
 | 
			
		||||
        ZeroExTimelock timelockController = ZeroExTimelock(payable(timelock()));
 | 
			
		||||
        timelockController.executeRollbackBatch(targets, values, calldatas, 0, descriptionHash);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function assignSecurityCouncil(address _securityCouncil) public override onlyGovernance {
 | 
			
		||||
        super.assignSecurityCouncil(_securityCouncil);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function queue(
 | 
			
		||||
        address[] memory targets,
 | 
			
		||||
        uint256[] memory values,
 | 
			
		||||
        bytes[] memory calldatas,
 | 
			
		||||
        bytes32 descriptionHash
 | 
			
		||||
    ) public override securityCouncilAssigned(calldatas) returns (uint256) {
 | 
			
		||||
        return super.queue(targets, values, calldatas, descriptionHash);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _execute(
 | 
			
		||||
        uint256 proposalId,
 | 
			
		||||
        address[] memory targets,
 | 
			
		||||
        uint256[] memory values,
 | 
			
		||||
        bytes[] memory calldatas,
 | 
			
		||||
        bytes32 descriptionHash
 | 
			
		||||
    ) internal override(Governor, GovernorTimelockControl) {
 | 
			
		||||
        super._execute(proposalId, targets, values, calldatas, descriptionHash);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _cancel(
 | 
			
		||||
        address[] memory targets,
 | 
			
		||||
        uint256[] memory values,
 | 
			
		||||
        bytes[] memory calldatas,
 | 
			
		||||
        bytes32 descriptionHash
 | 
			
		||||
    ) internal override(Governor, GovernorTimelockControl) returns (uint256) {
 | 
			
		||||
        return super._cancel(targets, values, calldatas, descriptionHash);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _executor() internal view override(Governor, GovernorTimelockControl) returns (address) {
 | 
			
		||||
        return super._executor();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function supportsInterface(
 | 
			
		||||
        bytes4 interfaceId
 | 
			
		||||
    ) public view override(Governor, GovernorTimelockControl) returns (bool) {
 | 
			
		||||
        return super.supportsInterface(interfaceId);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										70
									
								
								contracts/governance/src/ZeroExTimelock.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								contracts/governance/src/ZeroExTimelock.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2023 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.8.19;
 | 
			
		||||
 | 
			
		||||
import "@openzeppelin/governance/TimelockController.sol";
 | 
			
		||||
 | 
			
		||||
contract ZeroExTimelock is TimelockController {
 | 
			
		||||
    // minDelay is how long you have to wait before executing
 | 
			
		||||
    // proposers is the list of addresses that can propose
 | 
			
		||||
    // executors is the list of addresses that can execute
 | 
			
		||||
    constructor(
 | 
			
		||||
        uint256 minDelay,
 | 
			
		||||
        address[] memory proposers,
 | 
			
		||||
        address[] memory executors,
 | 
			
		||||
        address admin
 | 
			
		||||
    ) TimelockController(minDelay, proposers, executors, admin) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Execute a batch of rollback transactions. Similar to TimelockController.executeBatch function but without
 | 
			
		||||
     * the timelock checks.
 | 
			
		||||
     * Emits one {CallExecuted} event per transaction in the batch.
 | 
			
		||||
     *
 | 
			
		||||
     * Requirements:
 | 
			
		||||
     *
 | 
			
		||||
     * - the caller must have the 'executor' role.
 | 
			
		||||
     */
 | 
			
		||||
    function executeRollbackBatch(
 | 
			
		||||
        address[] calldata targets,
 | 
			
		||||
        uint256[] calldata values,
 | 
			
		||||
        bytes[] calldata payloads,
 | 
			
		||||
        bytes32 predecessor,
 | 
			
		||||
        bytes32 salt
 | 
			
		||||
    ) public payable onlyRoleOrOpenRole(EXECUTOR_ROLE) {
 | 
			
		||||
        require(targets.length > 0, "ZeroExTimelock: empty targets");
 | 
			
		||||
        require(targets.length == values.length, "ZeroExTimelock: length mismatch");
 | 
			
		||||
        require(targets.length == payloads.length, "ZeroExTimelock: length mismatch");
 | 
			
		||||
 | 
			
		||||
        bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt);
 | 
			
		||||
 | 
			
		||||
        for (uint256 i = 0; i < targets.length; ++i) {
 | 
			
		||||
            address target = targets[i];
 | 
			
		||||
            uint256 value = values[i];
 | 
			
		||||
            bytes calldata payload = payloads[i];
 | 
			
		||||
            // Check this is a rollback transaction
 | 
			
		||||
            // function signature for rollback(bytes4,address)
 | 
			
		||||
            // = bytes4(keccak256("rollback(bytes4,address)"))
 | 
			
		||||
            // = 0x9db64a40
 | 
			
		||||
            require(bytes4(payload) == bytes4(0x9db64a40), "ZeroExTimelock: not rollback");
 | 
			
		||||
 | 
			
		||||
            _execute(target, value, payload);
 | 
			
		||||
            emit CallExecuted(id, i, target, value, payload);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										154
									
								
								contracts/governance/src/ZeroExTreasuryGovernor.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								contracts/governance/src/ZeroExTreasuryGovernor.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,154 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2023 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.8.19;
 | 
			
		||||
 | 
			
		||||
import "@openzeppelin/governance/Governor.sol";
 | 
			
		||||
import "@openzeppelin/governance/extensions/GovernorSettings.sol";
 | 
			
		||||
import "@openzeppelin/governance/extensions/GovernorCountingSimple.sol";
 | 
			
		||||
import "@openzeppelin/governance/extensions/GovernorVotes.sol";
 | 
			
		||||
import "@openzeppelin/governance/extensions/GovernorVotesQuorumFraction.sol";
 | 
			
		||||
import "@openzeppelin/governance/extensions/GovernorTimelockControl.sol";
 | 
			
		||||
 | 
			
		||||
import "./IZeroExVotes.sol";
 | 
			
		||||
import "./SecurityCouncil.sol";
 | 
			
		||||
 | 
			
		||||
contract ZeroExTreasuryGovernor is
 | 
			
		||||
    SecurityCouncil,
 | 
			
		||||
    Governor,
 | 
			
		||||
    GovernorSettings,
 | 
			
		||||
    GovernorCountingSimple,
 | 
			
		||||
    GovernorVotes,
 | 
			
		||||
    GovernorVotesQuorumFraction,
 | 
			
		||||
    GovernorTimelockControl
 | 
			
		||||
{
 | 
			
		||||
    constructor(
 | 
			
		||||
        IVotes votes,
 | 
			
		||||
        TimelockController _timelock,
 | 
			
		||||
        address _securityCouncil
 | 
			
		||||
    )
 | 
			
		||||
        Governor("ZeroExTreasuryGovernor")
 | 
			
		||||
        GovernorSettings(14400 /* 2 days */, 50400 /* 7 days */, 250000e18)
 | 
			
		||||
        GovernorVotes(votes)
 | 
			
		||||
        GovernorVotesQuorumFraction(10)
 | 
			
		||||
        GovernorTimelockControl(_timelock)
 | 
			
		||||
    {
 | 
			
		||||
        securityCouncil = _securityCouncil;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Returns the "quadratic" quorum for a block number, in terms of number of votes:
 | 
			
		||||
     * `quadratic total supply * numerator / denominator`
 | 
			
		||||
     */
 | 
			
		||||
    function quorum(
 | 
			
		||||
        uint256 blockNumber
 | 
			
		||||
    ) public view override(IGovernor, GovernorVotesQuorumFraction) returns (uint256) {
 | 
			
		||||
        IZeroExVotes votes = IZeroExVotes(address(token));
 | 
			
		||||
        return (votes.getPastQuadraticTotalSupply(blockNumber) * quorumNumerator(blockNumber)) / quorumDenominator();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // The following functions are overrides required by Solidity.
 | 
			
		||||
 | 
			
		||||
    function votingDelay() public view override(IGovernor, GovernorSettings) returns (uint256) {
 | 
			
		||||
        return super.votingDelay();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function votingPeriod() public view override(IGovernor, GovernorSettings) returns (uint256) {
 | 
			
		||||
        return super.votingPeriod();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) {
 | 
			
		||||
        return super.proposalThreshold();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Overwritten GovernorVotes implementation
 | 
			
		||||
     * Read the quadratic voting weight from the token's built in snapshot mechanism (see {Governor-_getVotes}).
 | 
			
		||||
     */
 | 
			
		||||
    function _getVotes(
 | 
			
		||||
        address account,
 | 
			
		||||
        uint256 blockNumber,
 | 
			
		||||
        bytes memory /*params*/
 | 
			
		||||
    ) internal view virtual override(Governor, GovernorVotes) returns (uint256) {
 | 
			
		||||
        return IZeroExVotes(address(token)).getPastQuadraticVotes(account, blockNumber);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function state(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (ProposalState) {
 | 
			
		||||
        return super.state(proposalId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function propose(
 | 
			
		||||
        address[] memory targets,
 | 
			
		||||
        uint256[] memory values,
 | 
			
		||||
        bytes[] memory calldatas,
 | 
			
		||||
        string memory description
 | 
			
		||||
    ) public override(Governor, IGovernor) securityCouncilAssigned(calldatas) returns (uint256) {
 | 
			
		||||
        return super.propose(targets, values, calldatas, description);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function cancel(
 | 
			
		||||
        address[] memory targets,
 | 
			
		||||
        uint256[] memory values,
 | 
			
		||||
        bytes[] memory calldatas,
 | 
			
		||||
        bytes32 descriptionHash
 | 
			
		||||
    ) public override onlySecurityCouncil {
 | 
			
		||||
        _cancel(targets, values, calldatas, descriptionHash);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function assignSecurityCouncil(address _securityCouncil) public override onlyGovernance {
 | 
			
		||||
        super.assignSecurityCouncil(_securityCouncil);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function queue(
 | 
			
		||||
        address[] memory targets,
 | 
			
		||||
        uint256[] memory values,
 | 
			
		||||
        bytes[] memory calldatas,
 | 
			
		||||
        bytes32 descriptionHash
 | 
			
		||||
    ) public override securityCouncilAssigned(calldatas) returns (uint256) {
 | 
			
		||||
        return super.queue(targets, values, calldatas, descriptionHash);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _execute(
 | 
			
		||||
        uint256 proposalId,
 | 
			
		||||
        address[] memory targets,
 | 
			
		||||
        uint256[] memory values,
 | 
			
		||||
        bytes[] memory calldatas,
 | 
			
		||||
        bytes32 descriptionHash
 | 
			
		||||
    ) internal override(Governor, GovernorTimelockControl) {
 | 
			
		||||
        super._execute(proposalId, targets, values, calldatas, descriptionHash);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _cancel(
 | 
			
		||||
        address[] memory targets,
 | 
			
		||||
        uint256[] memory values,
 | 
			
		||||
        bytes[] memory calldatas,
 | 
			
		||||
        bytes32 descriptionHash
 | 
			
		||||
    ) internal override(Governor, GovernorTimelockControl) returns (uint256) {
 | 
			
		||||
        return super._cancel(targets, values, calldatas, descriptionHash);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _executor() internal view override(Governor, GovernorTimelockControl) returns (address) {
 | 
			
		||||
        return super._executor();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function supportsInterface(
 | 
			
		||||
        bytes4 interfaceId
 | 
			
		||||
    ) public view override(Governor, GovernorTimelockControl) returns (bool) {
 | 
			
		||||
        return super.supportsInterface(interfaceId);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										336
									
								
								contracts/governance/src/ZeroExVotes.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										336
									
								
								contracts/governance/src/ZeroExVotes.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,336 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2023 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.8.19;
 | 
			
		||||
 | 
			
		||||
import "@openzeppelin/utils/math/SafeCast.sol";
 | 
			
		||||
import "@openzeppelin/utils/math/Math.sol";
 | 
			
		||||
import "@openzeppelin/token/ERC20/ERC20.sol";
 | 
			
		||||
import "@openzeppelin/governance/utils/IVotes.sol";
 | 
			
		||||
import "@openzeppelin-contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
 | 
			
		||||
import "@openzeppelin-contracts-upgradeable/access/OwnableUpgradeable.sol";
 | 
			
		||||
import "@openzeppelin-contracts-upgradeable/proxy/utils/Initializable.sol";
 | 
			
		||||
import "./IZeroExVotes.sol";
 | 
			
		||||
 | 
			
		||||
contract ZeroExVotes is IZeroExVotes, Initializable, OwnableUpgradeable, UUPSUpgradeable {
 | 
			
		||||
    address public immutable token;
 | 
			
		||||
    uint256 public immutable quadraticThreshold;
 | 
			
		||||
 | 
			
		||||
    mapping(address => Checkpoint[]) internal _checkpoints;
 | 
			
		||||
    Checkpoint[] private _totalSupplyCheckpoints;
 | 
			
		||||
 | 
			
		||||
    constructor(address _token, uint256 _quadraticThreshold) {
 | 
			
		||||
        require(_token != address(0), "ZeroExVotes: token cannot be 0");
 | 
			
		||||
        token = _token;
 | 
			
		||||
        quadraticThreshold = _quadraticThreshold;
 | 
			
		||||
        _disableInitializers();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
 | 
			
		||||
 | 
			
		||||
    modifier onlyToken() {
 | 
			
		||||
        _checkSenderIsToken();
 | 
			
		||||
        _;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function initialize() public virtual onlyProxy initializer {
 | 
			
		||||
        __Ownable_init();
 | 
			
		||||
        __UUPSUpgradeable_init();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc IZeroExVotes
 | 
			
		||||
     */
 | 
			
		||||
    function checkpoints(address account, uint32 pos) public view returns (Checkpoint memory) {
 | 
			
		||||
        return _checkpoints[account][pos];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc IZeroExVotes
 | 
			
		||||
     */
 | 
			
		||||
    function numCheckpoints(address account) public view returns (uint32) {
 | 
			
		||||
        return SafeCast.toUint32(_checkpoints[account].length);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc IZeroExVotes
 | 
			
		||||
     */
 | 
			
		||||
    function getVotes(address account) public view returns (uint256) {
 | 
			
		||||
        unchecked {
 | 
			
		||||
            uint256 pos = _checkpoints[account].length;
 | 
			
		||||
            return pos == 0 ? 0 : _unsafeAccess(_checkpoints[account], pos - 1).votes;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc IZeroExVotes
 | 
			
		||||
     */
 | 
			
		||||
    function getQuadraticVotes(address account) public view returns (uint256) {
 | 
			
		||||
        unchecked {
 | 
			
		||||
            uint256 pos = _checkpoints[account].length;
 | 
			
		||||
            return pos == 0 ? 0 : _unsafeAccess(_checkpoints[account], pos - 1).quadraticVotes;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc IZeroExVotes
 | 
			
		||||
     */
 | 
			
		||||
    function getPastVotes(address account, uint256 blockNumber) public view returns (uint256) {
 | 
			
		||||
        require(blockNumber < block.number, "ZeroExVotes: block not yet mined");
 | 
			
		||||
 | 
			
		||||
        Checkpoint memory checkpoint = _checkpointsLookup(_checkpoints[account], blockNumber);
 | 
			
		||||
        return checkpoint.votes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc IZeroExVotes
 | 
			
		||||
     */
 | 
			
		||||
    function getPastQuadraticVotes(address account, uint256 blockNumber) public view returns (uint256) {
 | 
			
		||||
        require(blockNumber < block.number, "ZeroExVotes: block not yet mined");
 | 
			
		||||
 | 
			
		||||
        Checkpoint memory checkpoint = _checkpointsLookup(_checkpoints[account], blockNumber);
 | 
			
		||||
        return checkpoint.quadraticVotes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc IZeroExVotes
 | 
			
		||||
     */
 | 
			
		||||
    function getPastTotalSupply(uint256 blockNumber) public view returns (uint256) {
 | 
			
		||||
        require(blockNumber < block.number, "ZeroExVotes: block not yet mined");
 | 
			
		||||
 | 
			
		||||
        // Note that due to the disabled updates of `_totalSupplyCheckpoints` in `writeCheckpointTotalSupply` function
 | 
			
		||||
        // this always returns 0.
 | 
			
		||||
        Checkpoint memory checkpoint = _checkpointsLookup(_totalSupplyCheckpoints, blockNumber);
 | 
			
		||||
        return checkpoint.votes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc IZeroExVotes
 | 
			
		||||
     */
 | 
			
		||||
    function getPastQuadraticTotalSupply(uint256 blockNumber) public view returns (uint256) {
 | 
			
		||||
        require(blockNumber < block.number, "ZeroExVotes: block not yet mined");
 | 
			
		||||
 | 
			
		||||
        // Note that due to the disabled updates of `_totalSupplyCheckpoints` in `writeCheckpointTotalSupply` function
 | 
			
		||||
        // this always returns 0.
 | 
			
		||||
        Checkpoint memory checkpoint = _checkpointsLookup(_totalSupplyCheckpoints, blockNumber);
 | 
			
		||||
        return checkpoint.quadraticVotes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc IZeroExVotes
 | 
			
		||||
     */
 | 
			
		||||
    function moveVotingPower(
 | 
			
		||||
        address src,
 | 
			
		||||
        address dst,
 | 
			
		||||
        uint256 srcBalance,
 | 
			
		||||
        uint256 dstBalance,
 | 
			
		||||
        uint96 srcBalanceLastUpdated,
 | 
			
		||||
        uint96 dstBalanceLastUpdated,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    ) public virtual onlyToken returns (bool) {
 | 
			
		||||
        if (src != dst) {
 | 
			
		||||
            if (src != address(0)) {
 | 
			
		||||
                (
 | 
			
		||||
                    uint256 oldWeight,
 | 
			
		||||
                    uint256 newWeight,
 | 
			
		||||
                    uint256 oldQuadraticWeight,
 | 
			
		||||
                    uint256 newQuadraticWeight
 | 
			
		||||
                ) = _writeCheckpoint(_checkpoints[src], _subtract, srcBalance, srcBalanceLastUpdated, amount);
 | 
			
		||||
 | 
			
		||||
                emit DelegateVotesChanged(src, oldWeight, newWeight);
 | 
			
		||||
                emit DelegateQuadraticVotesChanged(src, oldQuadraticWeight, newQuadraticWeight);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (dst != address(0)) {
 | 
			
		||||
                (
 | 
			
		||||
                    uint256 oldWeight,
 | 
			
		||||
                    uint256 newWeight,
 | 
			
		||||
                    uint256 oldQuadraticWeight,
 | 
			
		||||
                    uint256 newQuadraticWeight
 | 
			
		||||
                ) = _writeCheckpoint(_checkpoints[dst], _add, dstBalance, dstBalanceLastUpdated, amount);
 | 
			
		||||
 | 
			
		||||
                emit DelegateVotesChanged(dst, oldWeight, newWeight);
 | 
			
		||||
                emit DelegateQuadraticVotesChanged(dst, oldQuadraticWeight, newQuadraticWeight);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc IZeroExVotes
 | 
			
		||||
     */
 | 
			
		||||
    function writeCheckpointTotalSupplyMint(
 | 
			
		||||
        uint256 accountBalance,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    ) public virtual onlyToken returns (bool) {
 | 
			
		||||
        (, uint256 newWeight, , uint256 newQuadraticWeight) = _writeCheckpoint(
 | 
			
		||||
            _totalSupplyCheckpoints,
 | 
			
		||||
            _add,
 | 
			
		||||
            accountBalance,
 | 
			
		||||
            0,
 | 
			
		||||
            amount
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        emit TotalSupplyChanged(newWeight, newQuadraticWeight);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc IZeroExVotes
 | 
			
		||||
     */
 | 
			
		||||
    function writeCheckpointTotalSupplyBurn(
 | 
			
		||||
        uint256 accountBalance,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    ) public virtual onlyToken returns (bool) {
 | 
			
		||||
        (, uint256 newWeight, , uint256 newQuadraticWeight) = _writeCheckpoint(
 | 
			
		||||
            _totalSupplyCheckpoints,
 | 
			
		||||
            _subtract,
 | 
			
		||||
            accountBalance,
 | 
			
		||||
            0,
 | 
			
		||||
            amount
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        emit TotalSupplyChanged(newWeight, newQuadraticWeight);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Lookup a value in a list of (sorted) checkpoints.
 | 
			
		||||
     * Implementation as in openzeppelin/token/ERC20/extensions/ERC20Votes.sol except here we return the entire
 | 
			
		||||
     * checkpoint rather than part of it
 | 
			
		||||
     */
 | 
			
		||||
    function _checkpointsLookup(
 | 
			
		||||
        Checkpoint[] storage ckpts,
 | 
			
		||||
        uint256 blockNumber
 | 
			
		||||
    ) internal view returns (Checkpoint memory checkpoint) {
 | 
			
		||||
        // We run a binary search to look for the earliest checkpoint taken after `blockNumber`.
 | 
			
		||||
        //
 | 
			
		||||
        // Initially we check if the block is recent to narrow the search range.
 | 
			
		||||
        // During the loop, the index of the wanted checkpoint remains in the range [low-1, high).
 | 
			
		||||
        // With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the
 | 
			
		||||
        // invariant.
 | 
			
		||||
        // - If the middle checkpoint is after `blockNumber`, we look in [low, mid)
 | 
			
		||||
        // - If the middle checkpoint is before or equal to `blockNumber`, we look in [mid+1, high)
 | 
			
		||||
        // Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not
 | 
			
		||||
        // out of bounds (in which case we're looking too far in the past and the result is 0).
 | 
			
		||||
        // Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is
 | 
			
		||||
        // past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out
 | 
			
		||||
        // the same.
 | 
			
		||||
        uint256 length = ckpts.length;
 | 
			
		||||
 | 
			
		||||
        uint256 low = 0;
 | 
			
		||||
        uint256 high = length;
 | 
			
		||||
 | 
			
		||||
        if (length > 5) {
 | 
			
		||||
            uint256 mid = length - Math.sqrt(length);
 | 
			
		||||
            if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
 | 
			
		||||
                high = mid;
 | 
			
		||||
            } else {
 | 
			
		||||
                low = mid + 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        while (low < high) {
 | 
			
		||||
            uint256 mid = Math.average(low, high);
 | 
			
		||||
            if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
 | 
			
		||||
                high = mid;
 | 
			
		||||
            } else {
 | 
			
		||||
                low = mid + 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Leaving here for posterity this is the original OZ implementation which we've replaced
 | 
			
		||||
        // return high == 0 ? 0 : _unsafeAccess(ckpts, high - 1).votes;
 | 
			
		||||
        if (high != 0) checkpoint = _unsafeAccess(ckpts, high - 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _writeCheckpoint(
 | 
			
		||||
        Checkpoint[] storage ckpts,
 | 
			
		||||
        function(uint256, uint256) view returns (uint256) op,
 | 
			
		||||
        uint256 userBalance,
 | 
			
		||||
        uint96 balanceLastUpdated,
 | 
			
		||||
        uint256 delta
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
        virtual
 | 
			
		||||
        returns (uint256 oldWeight, uint256 newWeight, uint256 oldQuadraticWeight, uint256 newQuadraticWeight)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 pos = ckpts.length;
 | 
			
		||||
 | 
			
		||||
        Checkpoint memory oldCkpt = pos == 0 ? Checkpoint(0, 0, 0) : _unsafeAccess(ckpts, pos - 1);
 | 
			
		||||
 | 
			
		||||
        oldWeight = oldCkpt.votes;
 | 
			
		||||
        newWeight = op(oldWeight, delta);
 | 
			
		||||
 | 
			
		||||
        oldQuadraticWeight = oldCkpt.quadraticVotes;
 | 
			
		||||
 | 
			
		||||
        // Remove the entire sqrt userBalance from quadratic voting power.
 | 
			
		||||
        // Note that `userBalance` is value _after_ transfer.
 | 
			
		||||
        if (pos > 0) {
 | 
			
		||||
            uint256 oldQuadraticVotingPower = userBalance <= quadraticThreshold
 | 
			
		||||
                ? userBalance
 | 
			
		||||
                : quadraticThreshold + Math.sqrt((userBalance - quadraticThreshold) * 1e18);
 | 
			
		||||
            oldCkpt.quadraticVotes -= SafeCast.toUint96(oldQuadraticVotingPower);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // if wallet > threshold, calculate quadratic power over the treshold only, below threshold is linear
 | 
			
		||||
        uint256 newBalance = op(userBalance, delta);
 | 
			
		||||
        uint256 newQuadraticBalance = newBalance <= quadraticThreshold
 | 
			
		||||
            ? newBalance
 | 
			
		||||
            : quadraticThreshold + Math.sqrt((newBalance - quadraticThreshold) * 1e18);
 | 
			
		||||
        newQuadraticWeight = oldCkpt.quadraticVotes + newQuadraticBalance;
 | 
			
		||||
 | 
			
		||||
        if (pos > 0 && oldCkpt.fromBlock == block.number) {
 | 
			
		||||
            Checkpoint storage chpt = _unsafeAccess(ckpts, pos - 1);
 | 
			
		||||
            chpt.votes = SafeCast.toUint96(newWeight);
 | 
			
		||||
            chpt.quadraticVotes = SafeCast.toUint96(newQuadraticWeight);
 | 
			
		||||
        } else {
 | 
			
		||||
            ckpts.push(
 | 
			
		||||
                Checkpoint({
 | 
			
		||||
                    fromBlock: SafeCast.toUint32(block.number),
 | 
			
		||||
                    votes: SafeCast.toUint96(newWeight),
 | 
			
		||||
                    quadraticVotes: SafeCast.toUint96(newQuadraticWeight)
 | 
			
		||||
                })
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _add(uint256 a, uint256 b) private pure returns (uint256) {
 | 
			
		||||
        return a + b;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _subtract(uint256 a, uint256 b) private pure returns (uint256) {
 | 
			
		||||
        return a - b;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
 | 
			
		||||
     * Implementation from openzeppelin/token/ERC20/extensions/ERC20Votes.sol
 | 
			
		||||
     * https://github.com/ethereum/solidity/issues/9117
 | 
			
		||||
     */
 | 
			
		||||
    function _unsafeAccess(Checkpoint[] storage ckpts, uint256 pos) internal pure returns (Checkpoint storage result) {
 | 
			
		||||
        assembly ("memory-safe") {
 | 
			
		||||
            mstore(0, ckpts.slot)
 | 
			
		||||
            result.slot := add(keccak256(0, 0x20), pos)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _checkSenderIsToken() private {
 | 
			
		||||
        require(msg.sender == token, "ZeroExVotes: only token allowed");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										167
									
								
								contracts/governance/test/BaseTest.t.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								contracts/governance/test/BaseTest.t.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,167 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2023 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.8.19;
 | 
			
		||||
 | 
			
		||||
import "forge-std/Test.sol";
 | 
			
		||||
import "forge-std/console.sol";
 | 
			
		||||
import "@openzeppelin/token/ERC20/ERC20.sol";
 | 
			
		||||
import "@openzeppelin/proxy/ERC1967/ERC1967Proxy.sol";
 | 
			
		||||
import "./mocks/ZRXMock.sol";
 | 
			
		||||
import "../src/ZRXWrappedToken.sol";
 | 
			
		||||
import "../src/ZeroExVotes.sol";
 | 
			
		||||
import "../src/ZeroExTimelock.sol";
 | 
			
		||||
import "../src/ZeroExProtocolGovernor.sol";
 | 
			
		||||
import "../src/ZeroExTreasuryGovernor.sol";
 | 
			
		||||
 | 
			
		||||
contract BaseTest is Test {
 | 
			
		||||
    address payable internal account1 = payable(vm.addr(1));
 | 
			
		||||
    address payable internal account2 = payable(vm.addr(2));
 | 
			
		||||
    address payable internal account3 = payable(vm.addr(3));
 | 
			
		||||
    address payable internal account4 = payable(vm.addr(4));
 | 
			
		||||
    address payable internal securityCouncil = payable(vm.addr(5));
 | 
			
		||||
    uint256 internal quadraticThreshold = 1000000e18;
 | 
			
		||||
 | 
			
		||||
    bytes32 internal constant DELEGATION_TYPEHASH =
 | 
			
		||||
        keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
 | 
			
		||||
 | 
			
		||||
    constructor() {
 | 
			
		||||
        vm.deal(account1, 1e20);
 | 
			
		||||
        vm.deal(account2, 1e20);
 | 
			
		||||
        vm.deal(account3, 1e20);
 | 
			
		||||
        vm.deal(account4, 1e20);
 | 
			
		||||
        vm.deal(securityCouncil, 1e20);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setupGovernance(
 | 
			
		||||
        IERC20 zrxToken
 | 
			
		||||
    ) internal returns (ZRXWrappedToken, ZeroExVotes, ZeroExTimelock, ZeroExTimelock, address, address) {
 | 
			
		||||
        (ZRXWrappedToken token, ZeroExVotes votes) = setupZRXWrappedToken(zrxToken);
 | 
			
		||||
 | 
			
		||||
        vm.startPrank(account1);
 | 
			
		||||
        address[] memory proposers = new address[](0);
 | 
			
		||||
        address[] memory executors = new address[](0);
 | 
			
		||||
 | 
			
		||||
        ZeroExTimelock protocolTimelock = new ZeroExTimelock(3 days, proposers, executors, account1);
 | 
			
		||||
        ZeroExProtocolGovernor protocolGovernor = new ZeroExProtocolGovernor(
 | 
			
		||||
            IVotes(address(votes)),
 | 
			
		||||
            protocolTimelock,
 | 
			
		||||
            securityCouncil
 | 
			
		||||
        );
 | 
			
		||||
        protocolTimelock.grantRole(protocolTimelock.PROPOSER_ROLE(), address(protocolGovernor));
 | 
			
		||||
        protocolTimelock.grantRole(protocolTimelock.EXECUTOR_ROLE(), address(protocolGovernor));
 | 
			
		||||
        protocolTimelock.grantRole(protocolTimelock.CANCELLER_ROLE(), address(protocolGovernor));
 | 
			
		||||
 | 
			
		||||
        ZeroExTimelock treasuryTimelock = new ZeroExTimelock(2 days, proposers, executors, account1);
 | 
			
		||||
        ZeroExTreasuryGovernor treasuryGovernor = new ZeroExTreasuryGovernor(
 | 
			
		||||
            IVotes(address(votes)),
 | 
			
		||||
            treasuryTimelock,
 | 
			
		||||
            securityCouncil
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        treasuryTimelock.grantRole(treasuryTimelock.PROPOSER_ROLE(), address(treasuryGovernor));
 | 
			
		||||
        treasuryTimelock.grantRole(treasuryTimelock.EXECUTOR_ROLE(), address(treasuryGovernor));
 | 
			
		||||
        treasuryTimelock.grantRole(treasuryTimelock.CANCELLER_ROLE(), address(treasuryGovernor));
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        return (token, votes, protocolTimelock, treasuryTimelock, address(protocolGovernor), address(treasuryGovernor));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setupZRXWrappedToken(IERC20 zrxToken) internal returns (ZRXWrappedToken, ZeroExVotes) {
 | 
			
		||||
        vm.startPrank(account1);
 | 
			
		||||
        address wTokenPrediction = predictAddress(account1, vm.getNonce(account1) + 2);
 | 
			
		||||
        ZeroExVotes votesImpl = new ZeroExVotes(wTokenPrediction, quadraticThreshold);
 | 
			
		||||
        ERC1967Proxy votesProxy = new ERC1967Proxy(address(votesImpl), abi.encodeCall(votesImpl.initialize, ()));
 | 
			
		||||
        ZRXWrappedToken wToken = new ZRXWrappedToken(zrxToken, ZeroExVotes(address(votesProxy)));
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        assert(address(wToken) == wTokenPrediction);
 | 
			
		||||
 | 
			
		||||
        return (wToken, ZeroExVotes(address(votesProxy)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function mockZRXToken() internal returns (IERC20 zrxToken) {
 | 
			
		||||
        vm.startPrank(account1);
 | 
			
		||||
        bytes memory _bytecode = vm.getCode("./ZRXToken.json");
 | 
			
		||||
        assembly {
 | 
			
		||||
            zrxToken := create(0, add(_bytecode, 0x20), mload(_bytecode))
 | 
			
		||||
        }
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Sourced from https://github.com/grappafinance/core/blob/master/src/test/utils/Utilities.sol
 | 
			
		||||
    function predictAddress(address _origin, uint256 _nonce) public pure returns (address) {
 | 
			
		||||
        if (_nonce == 0x00) {
 | 
			
		||||
            return
 | 
			
		||||
                address(
 | 
			
		||||
                    uint160(uint256(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), _origin, bytes1(0x80)))))
 | 
			
		||||
                );
 | 
			
		||||
        }
 | 
			
		||||
        if (_nonce <= 0x7f) {
 | 
			
		||||
            return
 | 
			
		||||
                address(
 | 
			
		||||
                    uint160(uint256(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), _origin, uint8(_nonce)))))
 | 
			
		||||
                );
 | 
			
		||||
        }
 | 
			
		||||
        if (_nonce <= 0xff) {
 | 
			
		||||
            return
 | 
			
		||||
                address(
 | 
			
		||||
                    uint160(
 | 
			
		||||
                        uint256(
 | 
			
		||||
                            keccak256(
 | 
			
		||||
                                abi.encodePacked(bytes1(0xd7), bytes1(0x94), _origin, bytes1(0x81), uint8(_nonce))
 | 
			
		||||
                            )
 | 
			
		||||
                        )
 | 
			
		||||
                    )
 | 
			
		||||
                );
 | 
			
		||||
        }
 | 
			
		||||
        if (_nonce <= 0xffff) {
 | 
			
		||||
            return
 | 
			
		||||
                address(
 | 
			
		||||
                    uint160(
 | 
			
		||||
                        uint256(
 | 
			
		||||
                            keccak256(
 | 
			
		||||
                                abi.encodePacked(bytes1(0xd8), bytes1(0x94), _origin, bytes1(0x82), uint16(_nonce))
 | 
			
		||||
                            )
 | 
			
		||||
                        )
 | 
			
		||||
                    )
 | 
			
		||||
                );
 | 
			
		||||
        }
 | 
			
		||||
        if (_nonce <= 0xffffff) {
 | 
			
		||||
            return
 | 
			
		||||
                address(
 | 
			
		||||
                    uint160(
 | 
			
		||||
                        uint256(
 | 
			
		||||
                            keccak256(
 | 
			
		||||
                                abi.encodePacked(bytes1(0xd9), bytes1(0x94), _origin, bytes1(0x83), uint24(_nonce))
 | 
			
		||||
                            )
 | 
			
		||||
                        )
 | 
			
		||||
                    )
 | 
			
		||||
                );
 | 
			
		||||
        }
 | 
			
		||||
        return
 | 
			
		||||
            address(
 | 
			
		||||
                uint160(
 | 
			
		||||
                    uint256(
 | 
			
		||||
                        keccak256(abi.encodePacked(bytes1(0xda), bytes1(0x94), _origin, bytes1(0x84), uint32(_nonce)))
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
            );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										454
									
								
								contracts/governance/test/integration/GovernanceE2E.t.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										454
									
								
								contracts/governance/test/integration/GovernanceE2E.t.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,454 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2023 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.8.19;
 | 
			
		||||
 | 
			
		||||
import "@openzeppelin/token/ERC20/IERC20.sol";
 | 
			
		||||
import "../mocks/IZeroExMock.sol";
 | 
			
		||||
import "../mocks/IZrxTreasuryMock.sol";
 | 
			
		||||
import "../mocks/IStakingMock.sol";
 | 
			
		||||
import "../mocks/IZrxVaultMock.sol";
 | 
			
		||||
import "../BaseTest.t.sol";
 | 
			
		||||
import "../../src/ZRXWrappedToken.sol";
 | 
			
		||||
import "../../src/ZeroExVotes.sol";
 | 
			
		||||
import "../../src/ZeroExTimelock.sol";
 | 
			
		||||
import "../../src/ZeroExProtocolGovernor.sol";
 | 
			
		||||
import "../../src/ZeroExTreasuryGovernor.sol";
 | 
			
		||||
 | 
			
		||||
contract GovernanceE2ETest is BaseTest {
 | 
			
		||||
    uint256 internal mainnetFork;
 | 
			
		||||
    string internal MAINNET_RPC_URL = vm.envString("MAINNET_RPC_URL");
 | 
			
		||||
 | 
			
		||||
    struct DelegatorPool {
 | 
			
		||||
        address delegator;
 | 
			
		||||
        bytes32 pool;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    address internal constant ZRX_TOKEN = 0xE41d2489571d322189246DaFA5ebDe1F4699F498;
 | 
			
		||||
    address internal constant MATIC_TOKEN = 0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0;
 | 
			
		||||
    address internal constant WCELO_TOKEN = 0xE452E6Ea2dDeB012e20dB73bf5d3863A3Ac8d77a;
 | 
			
		||||
    address internal constant WYV_TOKEN = 0x056017c55aE7AE32d12AeF7C679dF83A85ca75Ff;
 | 
			
		||||
 | 
			
		||||
    address internal constant EXCHANGE_PROXY = 0xDef1C0ded9bec7F1a1670819833240f027b25EfF;
 | 
			
		||||
    address internal constant EXCHANGE_GOVERNOR = 0x618F9C67CE7Bf1a50afa1E7e0238422601b0ff6e;
 | 
			
		||||
    address internal constant TREASURY = 0x0bB1810061C2f5b2088054eE184E6C79e1591101;
 | 
			
		||||
    address internal constant STAKING = 0xa26e80e7Dea86279c6d778D702Cc413E6CFfA777; // Holds ~$262K in WETH for rewards
 | 
			
		||||
    address internal constant ZRX_VAULT = 0xBa7f8b5fB1b19c1211c5d49550fcD149177A5Eaf; // Holds ~$10m in staked ZRX
 | 
			
		||||
    address internal constant STAKING_AND_VAULT_OWNER = 0x7D3455421BbC5Ed534a83c88FD80387dc8271392;
 | 
			
		||||
 | 
			
		||||
    address internal staker1 = 0x885c327cAD2aebb969dfaAb4c928B73CA17e3887;
 | 
			
		||||
    address internal staker2 = 0x03c823e96F6964076C118395F08a2D7edF0f8a8C;
 | 
			
		||||
 | 
			
		||||
    address[] internal topStakers = [
 | 
			
		||||
        0x5775afA796818ADA27b09FaF5c90d101f04eF600,
 | 
			
		||||
        0xE1bdcd3B70e077D2d66ADcbe78be3941F0BF380B,
 | 
			
		||||
        0xcCa71809E8870AFEB72c4720d0fe50d5C3230e05,
 | 
			
		||||
        0x828FD91d3e3a9FFa6305e78B9aE2Cfbc5B5D9f6B,
 | 
			
		||||
        0x4A36C3DA5d367B148d17265e7d7feafcf8fb4a21,
 | 
			
		||||
        0xEeff6fd32DeaFe1a9d3258A51c7F952F9FF0B2Ce,
 | 
			
		||||
        0x1D0738b927dFCBFBD59A9F0944BbD1860d3B9248,
 | 
			
		||||
        0x0C073E7248C1b548a08b27dD3af5D0f39c774280,
 | 
			
		||||
        0xA178FF321335BB777A7E21A56376592F69556b9c,
 | 
			
		||||
        0xD06CfBb59d2e8918F84D99d981039d7706DCA288
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    // voting power 1500000e18
 | 
			
		||||
    address internal voter1 = 0x292c6DAE7417B3D31d8B6e1d2EeA0258d14C4C4b;
 | 
			
		||||
    bytes32 internal voter1Pool = 0x0000000000000000000000000000000000000000000000000000000000000030;
 | 
			
		||||
    bytes32[] internal voter1_operated_poolIds = [voter1Pool];
 | 
			
		||||
 | 
			
		||||
    // voting power 1500000.5e18
 | 
			
		||||
    address internal voter2 = 0x4990cE223209FCEc4ec4c1ff6E0E81eebD8Cca08;
 | 
			
		||||
    bytes32 internal voter2Pool = 0x0000000000000000000000000000000000000000000000000000000000000031;
 | 
			
		||||
    bytes32[] internal voter2_operated_poolIds = [voter2Pool];
 | 
			
		||||
 | 
			
		||||
    // voting power 1500000e18
 | 
			
		||||
    address internal voter3 = 0x5265Bde27F57E738bE6c1F6AB3544e82cdc92a8f;
 | 
			
		||||
    bytes32 internal voter3Pool = 0x0000000000000000000000000000000000000000000000000000000000000032;
 | 
			
		||||
    bytes32[] internal voter3_operated_poolIds = [voter3Pool];
 | 
			
		||||
 | 
			
		||||
    // voting power 1500000e18
 | 
			
		||||
    address internal voter4 = 0xcA9F5049c1Ea8FC78574f94B7Cf5bE5fEE354C31;
 | 
			
		||||
    bytes32 internal voter4Pool = 0x0000000000000000000000000000000000000000000000000000000000000034;
 | 
			
		||||
    bytes32[] internal voter4_operated_poolIds = [voter4Pool];
 | 
			
		||||
 | 
			
		||||
    // voting power 1500000e18
 | 
			
		||||
    address internal voter5 = 0xDBB5664a9DBCB98F6365804880e5b277B3155422;
 | 
			
		||||
    bytes32 internal voter5Pool = 0x0000000000000000000000000000000000000000000000000000000000000035;
 | 
			
		||||
    bytes32[] internal voter5_operated_poolIds = [voter5Pool];
 | 
			
		||||
 | 
			
		||||
    // voting power 2291490.952353335e18
 | 
			
		||||
    address internal voter6 = 0x9a4Eb1101C0c053505Bd71d2fFa27Ed902DEaD85;
 | 
			
		||||
    bytes32 internal voter6Pool = 0x0000000000000000000000000000000000000000000000000000000000000029;
 | 
			
		||||
    bytes32[] internal voter6_operated_poolIds = [voter6Pool];
 | 
			
		||||
 | 
			
		||||
    // voting power 4575984.325e18
 | 
			
		||||
    address internal voter7 = 0x9564177EC8052C92752a488a71769F710aA0A41D;
 | 
			
		||||
    bytes32 internal voter7Pool = 0x0000000000000000000000000000000000000000000000000000000000000025;
 | 
			
		||||
    bytes32[] internal voter7_operated_poolIds = [voter7Pool];
 | 
			
		||||
 | 
			
		||||
    IERC20 internal token;
 | 
			
		||||
    IERC20 internal maticToken;
 | 
			
		||||
    IERC20 internal wceloToken;
 | 
			
		||||
    IERC20 internal wyvToken;
 | 
			
		||||
 | 
			
		||||
    IZeroExMock internal exchange;
 | 
			
		||||
    IZrxTreasuryMock internal treasury;
 | 
			
		||||
    IZrxVaultMock internal vault;
 | 
			
		||||
    IStakingMock internal staking;
 | 
			
		||||
    IERC20 internal weth;
 | 
			
		||||
 | 
			
		||||
    ZRXWrappedToken internal wToken;
 | 
			
		||||
    ZeroExVotes internal votes;
 | 
			
		||||
    ZeroExTimelock internal protocolTimelock;
 | 
			
		||||
    ZeroExTimelock internal treasuryTimelock;
 | 
			
		||||
    ZeroExProtocolGovernor internal protocolGovernor;
 | 
			
		||||
    ZeroExTreasuryGovernor internal treasuryGovernor;
 | 
			
		||||
 | 
			
		||||
    function setUp() public {
 | 
			
		||||
        mainnetFork = vm.createFork(MAINNET_RPC_URL);
 | 
			
		||||
        vm.selectFork(mainnetFork);
 | 
			
		||||
 | 
			
		||||
        token = IERC20(ZRX_TOKEN);
 | 
			
		||||
        maticToken = IERC20(MATIC_TOKEN);
 | 
			
		||||
        wceloToken = IERC20(WCELO_TOKEN);
 | 
			
		||||
        wyvToken = IERC20(WYV_TOKEN);
 | 
			
		||||
 | 
			
		||||
        exchange = IZeroExMock(payable(EXCHANGE_PROXY));
 | 
			
		||||
        treasury = IZrxTreasuryMock(TREASURY);
 | 
			
		||||
        vault = IZrxVaultMock(ZRX_VAULT);
 | 
			
		||||
        staking = IStakingMock(STAKING);
 | 
			
		||||
        weth = IERC20(staking.getWethContract());
 | 
			
		||||
 | 
			
		||||
        address protocolGovernorAddress;
 | 
			
		||||
        address treasuryGovernorAddress;
 | 
			
		||||
        (
 | 
			
		||||
            wToken,
 | 
			
		||||
            votes,
 | 
			
		||||
            protocolTimelock,
 | 
			
		||||
            treasuryTimelock,
 | 
			
		||||
            protocolGovernorAddress,
 | 
			
		||||
            treasuryGovernorAddress
 | 
			
		||||
        ) = setupGovernance(token);
 | 
			
		||||
 | 
			
		||||
        protocolGovernor = ZeroExProtocolGovernor(payable(protocolGovernorAddress));
 | 
			
		||||
        treasuryGovernor = ZeroExTreasuryGovernor(payable(treasuryGovernorAddress));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testProtocolGovernanceMigration() public {
 | 
			
		||||
        // initially the zrx exchange is owned by the legacy exchange governor
 | 
			
		||||
        assertEq(exchange.owner(), EXCHANGE_GOVERNOR);
 | 
			
		||||
 | 
			
		||||
        // transfer ownership to new protocol governor
 | 
			
		||||
        vm.prank(EXCHANGE_GOVERNOR);
 | 
			
		||||
        exchange.transferOwnership(address(protocolGovernor));
 | 
			
		||||
        assertEq(exchange.owner(), address(protocolGovernor));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testTreasuryGovernanceMigration() public {
 | 
			
		||||
        // Create a proposal to migrate to new governor
 | 
			
		||||
 | 
			
		||||
        uint256 currentEpoch = staking.currentEpoch();
 | 
			
		||||
        uint256 executionEpoch = currentEpoch + 2;
 | 
			
		||||
 | 
			
		||||
        vm.startPrank(voter3);
 | 
			
		||||
 | 
			
		||||
        IZrxTreasuryMock.ProposedAction[] memory actions = new IZrxTreasuryMock.ProposedAction[](4);
 | 
			
		||||
 | 
			
		||||
        // Transfer MATIC
 | 
			
		||||
        uint256 maticBalance = maticToken.balanceOf(address(treasury));
 | 
			
		||||
        actions[0] = IZrxTreasuryMock.ProposedAction({
 | 
			
		||||
            target: MATIC_TOKEN,
 | 
			
		||||
            data: abi.encodeCall(maticToken.transfer, (address(treasuryGovernor), maticBalance)),
 | 
			
		||||
            value: 0
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Transfer ZRX
 | 
			
		||||
        uint256 zrxBalance = token.balanceOf(address(treasury));
 | 
			
		||||
        actions[1] = IZrxTreasuryMock.ProposedAction({
 | 
			
		||||
            target: ZRX_TOKEN,
 | 
			
		||||
            data: abi.encodeCall(token.transfer, (address(treasuryGovernor), zrxBalance)),
 | 
			
		||||
            value: 0
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Transfer wCELO
 | 
			
		||||
        uint256 wceloBalance = wceloToken.balanceOf(address(treasury));
 | 
			
		||||
        actions[2] = IZrxTreasuryMock.ProposedAction({
 | 
			
		||||
            target: WCELO_TOKEN,
 | 
			
		||||
            data: abi.encodeCall(wceloToken.transfer, (address(treasuryGovernor), wceloBalance)),
 | 
			
		||||
            value: 0
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Transfer WYV
 | 
			
		||||
        uint256 wyvBalance = wyvToken.balanceOf(address(treasury));
 | 
			
		||||
        actions[3] = IZrxTreasuryMock.ProposedAction({
 | 
			
		||||
            target: WYV_TOKEN,
 | 
			
		||||
            data: abi.encodeCall(wyvToken.transfer, (address(treasuryGovernor), wyvBalance)),
 | 
			
		||||
            value: 0
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        uint256 proposalId = treasury.propose(
 | 
			
		||||
            actions,
 | 
			
		||||
            executionEpoch,
 | 
			
		||||
            "Z-5 Migrate to new treasury governor",
 | 
			
		||||
            voter3_operated_poolIds
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Once a proposal is created, it becomes open for voting at the epoch after next (currentEpoch + 2)
 | 
			
		||||
        // and is open for the voting period (currently set to 3 days).
 | 
			
		||||
        uint256 epochDurationInSeconds = staking.epochDurationInSeconds(); // Currently set to 604800 seconds = 7 days
 | 
			
		||||
        uint256 currentEpochEndTime = staking.currentEpochStartTimeInSeconds() + epochDurationInSeconds;
 | 
			
		||||
 | 
			
		||||
        vm.warp(currentEpochEndTime + 1);
 | 
			
		||||
        staking.endEpoch();
 | 
			
		||||
        vm.warp(block.timestamp + epochDurationInSeconds + 1);
 | 
			
		||||
        staking.endEpoch();
 | 
			
		||||
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
        // quorum is 10,000,000e18 so reach that via the following votes
 | 
			
		||||
        vm.prank(voter1);
 | 
			
		||||
        treasury.castVote(proposalId, true, voter1_operated_poolIds);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        vm.prank(voter2);
 | 
			
		||||
        treasury.castVote(proposalId, true, voter2_operated_poolIds);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        vm.prank(voter3);
 | 
			
		||||
        treasury.castVote(proposalId, true, voter3_operated_poolIds);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        vm.prank(voter4);
 | 
			
		||||
        treasury.castVote(proposalId, true, voter4_operated_poolIds);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        vm.prank(voter5);
 | 
			
		||||
        treasury.castVote(proposalId, true, voter5_operated_poolIds);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        vm.prank(voter6);
 | 
			
		||||
        treasury.castVote(proposalId, true, voter6_operated_poolIds);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        vm.prank(voter7);
 | 
			
		||||
        treasury.castVote(proposalId, true, voter7_operated_poolIds);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        vm.warp(block.timestamp + 3 days + 1);
 | 
			
		||||
 | 
			
		||||
        // Execute proposal
 | 
			
		||||
        treasury.execute(proposalId, actions);
 | 
			
		||||
 | 
			
		||||
        // Assert value of treasury has correctly transferred
 | 
			
		||||
        uint256 maticBalanceNewTreasury = maticToken.balanceOf(address(treasuryGovernor));
 | 
			
		||||
        assertEq(maticBalanceNewTreasury, maticBalance);
 | 
			
		||||
 | 
			
		||||
        uint256 zrxBalanceNewTreasury = token.balanceOf(address(treasuryGovernor));
 | 
			
		||||
        assertEq(zrxBalanceNewTreasury, zrxBalance);
 | 
			
		||||
 | 
			
		||||
        uint256 wceloBalanceNewTreasury = wceloToken.balanceOf(address(treasuryGovernor));
 | 
			
		||||
        assertEq(wceloBalanceNewTreasury, wceloBalance);
 | 
			
		||||
 | 
			
		||||
        uint256 wyvBalanceNewTreasury = wyvToken.balanceOf(address(treasuryGovernor));
 | 
			
		||||
        assertEq(wyvBalanceNewTreasury, wyvBalance);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Test entering catastrophic failure mode on the zrx vault to decomission v3 staking
 | 
			
		||||
    function testCatastrophicFailureModeOnStaking() public {
 | 
			
		||||
        DelegatorPool[5] memory delegatorPools = [
 | 
			
		||||
            DelegatorPool(
 | 
			
		||||
                0x0ee1F33A2EB0da738FdF035C48d62d75e996a3bd,
 | 
			
		||||
                0x0000000000000000000000000000000000000000000000000000000000000016
 | 
			
		||||
            ),
 | 
			
		||||
            DelegatorPool(
 | 
			
		||||
                0xcAb3d8cBBb3dA1bDabfB003B9C828B27a821717f,
 | 
			
		||||
                0x0000000000000000000000000000000000000000000000000000000000000017
 | 
			
		||||
            ),
 | 
			
		||||
            DelegatorPool(
 | 
			
		||||
                0x7f88b00Db27a500fBfA7EbC9c3CaA2Dea6F59d5b,
 | 
			
		||||
                0x0000000000000000000000000000000000000000000000000000000000000014
 | 
			
		||||
            ),
 | 
			
		||||
            DelegatorPool(
 | 
			
		||||
                0xcE266E6123B682f7A7388097e2155b5379D9AC78,
 | 
			
		||||
                0x0000000000000000000000000000000000000000000000000000000000000014
 | 
			
		||||
            ),
 | 
			
		||||
            DelegatorPool(
 | 
			
		||||
                0xBa4f44E774158408E2DC6c5cb65BC995F0a89180, // pool operator
 | 
			
		||||
                0x0000000000000000000000000000000000000000000000000000000000000017
 | 
			
		||||
            )
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        // Enter catastrophic failure mode on the zrx vault
 | 
			
		||||
        vm.prank(STAKING_AND_VAULT_OWNER);
 | 
			
		||||
        vault.enterCatastrophicFailure();
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Stakes can still be withdrawn
 | 
			
		||||
        // staker1 withdraws
 | 
			
		||||
        uint256 stake1 = vault.balanceOf(staker1);
 | 
			
		||||
        uint256 balance1 = token.balanceOf(staker1);
 | 
			
		||||
        assertGt(stake1, 0);
 | 
			
		||||
 | 
			
		||||
        vm.prank(staker1);
 | 
			
		||||
        vault.withdrawAllFrom(staker1);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        assertEq(vault.balanceOf(staker1), 0);
 | 
			
		||||
        assertEq(token.balanceOf(staker1), stake1 + balance1);
 | 
			
		||||
 | 
			
		||||
        // staker2 withdraws
 | 
			
		||||
        uint256 stake2 = vault.balanceOf(staker2);
 | 
			
		||||
        uint256 balance2 = token.balanceOf(staker2);
 | 
			
		||||
        assertGt(stake2, 0);
 | 
			
		||||
 | 
			
		||||
        vm.prank(staker2);
 | 
			
		||||
        vault.withdrawAllFrom(staker2);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        assertEq(vault.balanceOf(staker2), 0);
 | 
			
		||||
        assertEq(token.balanceOf(staker2), stake2 + balance2);
 | 
			
		||||
 | 
			
		||||
        // Test top stakers can withdraw
 | 
			
		||||
        for (uint256 i = 0; i < topStakers.length; i++) {
 | 
			
		||||
            address staker = topStakers[i];
 | 
			
		||||
            uint256 stake = vault.balanceOf(staker);
 | 
			
		||||
            uint256 balance = token.balanceOf(staker);
 | 
			
		||||
            assertGt(stake, 0);
 | 
			
		||||
 | 
			
		||||
            vm.prank(staker);
 | 
			
		||||
            vault.withdrawAllFrom(staker);
 | 
			
		||||
            vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
            assertEq(vault.balanceOf(staker), 0);
 | 
			
		||||
            assertEq(token.balanceOf(staker), stake + balance);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Delegator can withdraw rewards
 | 
			
		||||
        for (uint256 i = 0; i < delegatorPools.length; i++) {
 | 
			
		||||
            address delegator = delegatorPools[i].delegator;
 | 
			
		||||
            bytes32 pool = delegatorPools[i].pool;
 | 
			
		||||
            uint256 reward = staking.computeRewardBalanceOfDelegator(pool, delegator);
 | 
			
		||||
            assertGt(reward, 0);
 | 
			
		||||
            uint256 balanceBeforeReward = weth.balanceOf(delegator);
 | 
			
		||||
 | 
			
		||||
            vm.prank(delegator);
 | 
			
		||||
            staking.withdrawDelegatorRewards(pool);
 | 
			
		||||
            vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
            assertEq(weth.balanceOf(delegator), balanceBeforeReward + reward);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testSwitchDelegationInCatastrophicMode() public {
 | 
			
		||||
        // Enter catastrophic failure mode on the zrx vault
 | 
			
		||||
        vm.prank(STAKING_AND_VAULT_OWNER);
 | 
			
		||||
        vault.enterCatastrophicFailure();
 | 
			
		||||
 | 
			
		||||
        // 0x delegator
 | 
			
		||||
        address delegator = 0x5775afA796818ADA27b09FaF5c90d101f04eF600;
 | 
			
		||||
 | 
			
		||||
        uint256 stake = vault.balanceOf(delegator);
 | 
			
		||||
        uint256 balance = token.balanceOf(delegator);
 | 
			
		||||
        assertGt(stake, 0);
 | 
			
		||||
 | 
			
		||||
        // Withdraw stake all at once
 | 
			
		||||
        vm.startPrank(delegator);
 | 
			
		||||
        vault.withdrawAllFrom(delegator);
 | 
			
		||||
 | 
			
		||||
        assertEq(vault.balanceOf(delegator), 0);
 | 
			
		||||
        assertEq(token.balanceOf(delegator), stake + balance);
 | 
			
		||||
 | 
			
		||||
        // delegate 1M ZRX to 0x4990cE223209FCEc4ec4c1ff6E0E81eebD8Cca08
 | 
			
		||||
        vm.roll(block.number + 1);
 | 
			
		||||
        address delegate = 0x4990cE223209FCEc4ec4c1ff6E0E81eebD8Cca08;
 | 
			
		||||
        uint256 amountToDelegate = 1000000e18;
 | 
			
		||||
 | 
			
		||||
        // Approve the wrapped token and deposit 1m ZRX
 | 
			
		||||
        token.approve(address(wToken), amountToDelegate);
 | 
			
		||||
        wToken.depositFor(delegator, amountToDelegate);
 | 
			
		||||
 | 
			
		||||
        assertEq(wToken.balanceOf(delegator), amountToDelegate);
 | 
			
		||||
 | 
			
		||||
        vm.roll(block.number + 1);
 | 
			
		||||
        wToken.delegate(delegate);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        assertEq(votes.getVotes(delegate), amountToDelegate);
 | 
			
		||||
        assertEq(votes.getQuadraticVotes(delegate), amountToDelegate);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testSwitchDelegationInNormalOperationMode() public {
 | 
			
		||||
        // 0x delegator
 | 
			
		||||
        address delegator = 0x5775afA796818ADA27b09FaF5c90d101f04eF600;
 | 
			
		||||
        uint256 balance = token.balanceOf(delegator);
 | 
			
		||||
 | 
			
		||||
        // Undelegate stake from pool 0x35
 | 
			
		||||
        vm.startPrank(delegator);
 | 
			
		||||
        staking.moveStake(
 | 
			
		||||
            IStructs.StakeInfo(
 | 
			
		||||
                IStructs.StakeStatus.DELEGATED,
 | 
			
		||||
                0x0000000000000000000000000000000000000000000000000000000000000035
 | 
			
		||||
            ),
 | 
			
		||||
            IStructs.StakeInfo(IStructs.StakeStatus.UNDELEGATED, bytes32(0)),
 | 
			
		||||
            3000000000000000000000000
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Undelegate stake from pool 0x38
 | 
			
		||||
        IStructs.StoredBalance memory storedBalance38 = staking.getStakeDelegatedToPoolByOwner(
 | 
			
		||||
            delegator,
 | 
			
		||||
            0x0000000000000000000000000000000000000000000000000000000000000038
 | 
			
		||||
        );
 | 
			
		||||
        staking.moveStake(
 | 
			
		||||
            IStructs.StakeInfo(
 | 
			
		||||
                IStructs.StakeStatus.DELEGATED,
 | 
			
		||||
                0x0000000000000000000000000000000000000000000000000000000000000038
 | 
			
		||||
            ),
 | 
			
		||||
            IStructs.StakeInfo(IStructs.StakeStatus.UNDELEGATED, bytes32(0)),
 | 
			
		||||
            storedBalance38.currentEpochBalance
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Warp past an epochs and unstake
 | 
			
		||||
        uint256 epochEndTime = staking.getCurrentEpochEarliestEndTimeInSeconds();
 | 
			
		||||
        vm.warp(epochEndTime + 1);
 | 
			
		||||
        staking.endEpoch();
 | 
			
		||||
 | 
			
		||||
        staking.unstake(6000000000000000000000000);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        assertEq(token.balanceOf(delegator), balance + 2 * 3000000000000000000000000);
 | 
			
		||||
 | 
			
		||||
        // delegate 1M ZRX to 0x4990cE223209FCEc4ec4c1ff6E0E81eebD8Cca08
 | 
			
		||||
        vm.roll(block.number + 1);
 | 
			
		||||
        address delegate = 0x4990cE223209FCEc4ec4c1ff6E0E81eebD8Cca08;
 | 
			
		||||
        uint256 amountToDelegate = 1000000e18;
 | 
			
		||||
 | 
			
		||||
        // Approve the wrapped token and deposit 1m ZRX
 | 
			
		||||
        token.approve(address(wToken), amountToDelegate);
 | 
			
		||||
        wToken.depositFor(delegator, amountToDelegate);
 | 
			
		||||
 | 
			
		||||
        assertEq(wToken.balanceOf(delegator), amountToDelegate);
 | 
			
		||||
 | 
			
		||||
        vm.roll(block.number + 1);
 | 
			
		||||
        wToken.delegate(delegate);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        assertEq(votes.getVotes(delegate), amountToDelegate);
 | 
			
		||||
        assertEq(votes.getQuadraticVotes(delegate), amountToDelegate);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								contracts/governance/test/mocks/CubeRoot.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								contracts/governance/test/mocks/CubeRoot.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
// SPDX-License-Identifier: MIT
 | 
			
		||||
pragma solidity ^0.8.19;
 | 
			
		||||
 | 
			
		||||
library CubeRoot {
 | 
			
		||||
    /// @dev Returns the cube root of `x`.
 | 
			
		||||
    /// Credit to pleasemarkdarkly under MIT license
 | 
			
		||||
    // Originaly from https://github.com/pleasemarkdarkly/fei-protocol-core-hh/blob/main/contracts/utils/Roots.sol
 | 
			
		||||
    function cbrt(uint y) internal pure returns (uint z) {
 | 
			
		||||
        // Newton's method https://en.wikipedia.org/wiki/Cube_root#Numerical_methods
 | 
			
		||||
        if (y > 7) {
 | 
			
		||||
            z = y;
 | 
			
		||||
            uint x = y / 3 + 1;
 | 
			
		||||
            while (x < z) {
 | 
			
		||||
                z = x;
 | 
			
		||||
                x = (y / (x * x) + (2 * x)) / 3;
 | 
			
		||||
            }
 | 
			
		||||
        } else if (y != 0) {
 | 
			
		||||
            z = 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										36
									
								
								contracts/governance/test/mocks/IOwnableFeature.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								contracts/governance/test/mocks/IOwnableFeature.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
  Copyright 2023 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.8.19;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/v08/interfaces/IOwnableV08.sol";
 | 
			
		||||
 | 
			
		||||
/// @dev Owner management and migration features.
 | 
			
		||||
interface IOwnableFeature is IOwnableV08 {
 | 
			
		||||
    /// @dev Emitted when `migrate()` is called.
 | 
			
		||||
    /// @param caller The caller of `migrate()`.
 | 
			
		||||
    /// @param migrator The migration contract.
 | 
			
		||||
    /// @param newOwner The address of the new owner.
 | 
			
		||||
    event Migrated(address caller, address migrator, address newOwner);
 | 
			
		||||
 | 
			
		||||
    /// @dev Execute a migration function in the context of the ZeroEx contract.
 | 
			
		||||
    ///      The result of the function being called should be the magic bytes
 | 
			
		||||
    ///      0x2c64c5ef (`keccack('MIGRATE_SUCCESS')`). Only callable by the owner.
 | 
			
		||||
    ///      The owner will be temporarily set to `address(this)` inside the call.
 | 
			
		||||
    ///      Before returning, the owner will be set to `newOwner`.
 | 
			
		||||
    /// @param target The migrator contract address.
 | 
			
		||||
    /// @param newOwner The address of the new owner.
 | 
			
		||||
    /// @param data The call data.
 | 
			
		||||
    function migrate(address target, bytes calldata data, address newOwner) external;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,48 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
  Copyright 2023 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.8.19;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
/// @dev Basic registry management features.
 | 
			
		||||
interface ISimpleFunctionRegistryFeature {
 | 
			
		||||
    /// @dev A function implementation was updated via `extend()` or `rollback()`.
 | 
			
		||||
    /// @param selector The function selector.
 | 
			
		||||
    /// @param oldImpl The implementation contract address being replaced.
 | 
			
		||||
    /// @param newImpl The replacement implementation contract address.
 | 
			
		||||
    event ProxyFunctionUpdated(bytes4 indexed selector, address oldImpl, address newImpl);
 | 
			
		||||
 | 
			
		||||
    /// @dev Roll back to a prior implementation of a function.
 | 
			
		||||
    /// @param selector The function selector.
 | 
			
		||||
    /// @param targetImpl The address of an older implementation of the function.
 | 
			
		||||
    function rollback(bytes4 selector, address targetImpl) external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Register or replace a function.
 | 
			
		||||
    /// @param selector The function selector.
 | 
			
		||||
    /// @param impl The implementation contract for the function.
 | 
			
		||||
    function extend(bytes4 selector, address impl) external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Retrieve the length of the rollback history for a function.
 | 
			
		||||
    /// @param selector The function selector.
 | 
			
		||||
    /// @return rollbackLength The number of items in the rollback history for
 | 
			
		||||
    ///         the function.
 | 
			
		||||
    function getRollbackLength(bytes4 selector) external view returns (uint256 rollbackLength);
 | 
			
		||||
 | 
			
		||||
    /// @dev Retrieve an entry in the rollback history for a function.
 | 
			
		||||
    /// @param selector The function selector.
 | 
			
		||||
    /// @param idx The index in the rollback history.
 | 
			
		||||
    /// @return impl An implementation address for the function at
 | 
			
		||||
    ///         index `idx`.
 | 
			
		||||
    function getRollbackEntryAtIndex(bytes4 selector, uint256 idx) external view returns (address impl);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										196
									
								
								contracts/governance/test/mocks/IStakingMock.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								contracts/governance/test/mocks/IStakingMock.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,196 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2021 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.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import "./IZrxVaultMock.sol";
 | 
			
		||||
import "./IStructs.sol";
 | 
			
		||||
import "./IStorageMock.sol";
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.8.19;
 | 
			
		||||
 | 
			
		||||
interface IStakingMock is IStorageMock {
 | 
			
		||||
    /// @dev Adds a new exchange address
 | 
			
		||||
    /// @param addr Address of exchange contract to add
 | 
			
		||||
    function addExchangeAddress(address addr) external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Create a new staking pool. The sender will be the operator of this pool.
 | 
			
		||||
    /// Note that an operator must be payable.
 | 
			
		||||
    /// @param operatorShare Portion of rewards owned by the operator, in ppm.
 | 
			
		||||
    /// @param addOperatorAsMaker Adds operator to the created pool as a maker for convenience iff true.
 | 
			
		||||
    /// @return poolId The unique pool id generated for this pool.
 | 
			
		||||
    function createStakingPool(uint32 operatorShare, bool addOperatorAsMaker) external returns (bytes32 poolId);
 | 
			
		||||
 | 
			
		||||
    /// @dev Decreases the operator share for the given pool (i.e. increases pool rewards for members).
 | 
			
		||||
    /// @param poolId Unique Id of pool.
 | 
			
		||||
    /// @param newOperatorShare The newly decreased percentage of any rewards owned by the operator.
 | 
			
		||||
    function decreaseStakingPoolOperatorShare(bytes32 poolId, uint32 newOperatorShare) external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Begins a new epoch, preparing the prior one for finalization.
 | 
			
		||||
    ///      Throws if not enough time has passed between epochs or if the
 | 
			
		||||
    ///      previous epoch was not fully finalized.
 | 
			
		||||
    /// @return numPoolsToFinalize The number of unfinalized pools.
 | 
			
		||||
    function endEpoch() external returns (uint256);
 | 
			
		||||
 | 
			
		||||
    /// @dev Instantly finalizes a single pool that earned rewards in the previous
 | 
			
		||||
    ///      epoch, crediting it rewards for members and withdrawing operator's
 | 
			
		||||
    ///      rewards as WETH. This can be called by internal functions that need
 | 
			
		||||
    ///      to finalize a pool immediately. Does nothing if the pool is already
 | 
			
		||||
    ///      finalized or did not earn rewards in the previous epoch.
 | 
			
		||||
    /// @param poolId The pool ID to finalize.
 | 
			
		||||
    function finalizePool(bytes32 poolId) external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Initialize storage owned by this contract.
 | 
			
		||||
    ///      This function should not be called directly.
 | 
			
		||||
    ///      The StakingProxy contract will call it in `attachStakingContract()`.
 | 
			
		||||
    function init() external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Allows caller to join a staking pool as a maker.
 | 
			
		||||
    /// @param poolId Unique id of pool.
 | 
			
		||||
    function joinStakingPoolAsMaker(bytes32 poolId) external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Moves stake between statuses: 'undelegated' or 'delegated'.
 | 
			
		||||
    ///      Delegated stake can also be moved between pools.
 | 
			
		||||
    ///      This change comes into effect next epoch.
 | 
			
		||||
    /// @param from status to move stake out of.
 | 
			
		||||
    /// @param to status to move stake into.
 | 
			
		||||
    /// @param amount of stake to move.
 | 
			
		||||
    function moveStake(IStructs.StakeInfo calldata from, IStructs.StakeInfo calldata to, uint256 amount) external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Pays a protocol fee in ETH.
 | 
			
		||||
    /// @param makerAddress The address of the order's maker.
 | 
			
		||||
    /// @param payerAddress The address that is responsible for paying the protocol fee.
 | 
			
		||||
    /// @param protocolFee The amount of protocol fees that should be paid.
 | 
			
		||||
    function payProtocolFee(address makerAddress, address payerAddress, uint256 protocolFee) external payable;
 | 
			
		||||
 | 
			
		||||
    /// @dev Removes an existing exchange address
 | 
			
		||||
    /// @param addr Address of exchange contract to remove
 | 
			
		||||
    function removeExchangeAddress(address addr) external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Set all configurable parameters at once.
 | 
			
		||||
    /// @param _epochDurationInSeconds Minimum seconds between epochs.
 | 
			
		||||
    /// @param _rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm.
 | 
			
		||||
    /// @param _minimumPoolStake Minimum amount of stake required in a pool to collect rewards.
 | 
			
		||||
    /// @param _cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor.
 | 
			
		||||
    /// @param _cobbDouglasAlphaDenominator Denominator for cobb douglas alpha factor.
 | 
			
		||||
    function setParams(
 | 
			
		||||
        uint256 _epochDurationInSeconds,
 | 
			
		||||
        uint32 _rewardDelegatedStakeWeight,
 | 
			
		||||
        uint256 _minimumPoolStake,
 | 
			
		||||
        uint32 _cobbDouglasAlphaNumerator,
 | 
			
		||||
        uint32 _cobbDouglasAlphaDenominator
 | 
			
		||||
    ) external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Stake ZRX tokens. Tokens are deposited into the ZRX Vault.
 | 
			
		||||
    ///      Unstake to retrieve the ZRX. Stake is in the 'Active' status.
 | 
			
		||||
    /// @param amount of ZRX to stake.
 | 
			
		||||
    function stake(uint256 amount) external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Unstake. Tokens are withdrawn from the ZRX Vault and returned to
 | 
			
		||||
    ///      the staker. Stake must be in the 'undelegated' status in both the
 | 
			
		||||
    ///      current and next epoch in order to be unstaked.
 | 
			
		||||
    /// @param amount of ZRX to unstake.
 | 
			
		||||
    function unstake(uint256 amount) external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Withdraws the caller's WETH rewards that have accumulated
 | 
			
		||||
    ///      until the last epoch.
 | 
			
		||||
    /// @param poolId Unique id of pool.
 | 
			
		||||
    function withdrawDelegatorRewards(bytes32 poolId) external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Computes the reward balance in ETH of a specific member of a pool.
 | 
			
		||||
    /// @param poolId Unique id of pool.
 | 
			
		||||
    /// @param member The member of the pool.
 | 
			
		||||
    /// @return reward Balance in ETH.
 | 
			
		||||
    function computeRewardBalanceOfDelegator(bytes32 poolId, address member) external view returns (uint256 reward);
 | 
			
		||||
 | 
			
		||||
    /// @dev Computes the reward balance in ETH of the operator of a pool.
 | 
			
		||||
    /// @param poolId Unique id of pool.
 | 
			
		||||
    /// @return reward Balance in ETH.
 | 
			
		||||
    function computeRewardBalanceOfOperator(bytes32 poolId) external view returns (uint256 reward);
 | 
			
		||||
 | 
			
		||||
    /// @dev Returns the earliest end time in seconds of this epoch.
 | 
			
		||||
    ///      The next epoch can begin once this time is reached.
 | 
			
		||||
    ///      Epoch period = [startTimeInSeconds..endTimeInSeconds)
 | 
			
		||||
    /// @return Time in seconds.
 | 
			
		||||
    function getCurrentEpochEarliestEndTimeInSeconds() external view returns (uint256);
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets global stake for a given status.
 | 
			
		||||
    /// @param stakeStatus UNDELEGATED or DELEGATED
 | 
			
		||||
    /// @return balance Global stake for given status.
 | 
			
		||||
    function getGlobalStakeByStatus(
 | 
			
		||||
        IStructs.StakeStatus stakeStatus
 | 
			
		||||
    ) external view returns (IStructs.StoredBalance memory balance);
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets an owner's stake balances by status.
 | 
			
		||||
    /// @param staker Owner of stake.
 | 
			
		||||
    /// @param stakeStatus UNDELEGATED or DELEGATED
 | 
			
		||||
    /// @return balance Owner's stake balances for given status.
 | 
			
		||||
    function getOwnerStakeByStatus(
 | 
			
		||||
        address staker,
 | 
			
		||||
        IStructs.StakeStatus stakeStatus
 | 
			
		||||
    ) external view returns (IStructs.StoredBalance memory balance);
 | 
			
		||||
 | 
			
		||||
    /// @dev Retrieves all configurable parameter values.
 | 
			
		||||
    /// @return _epochDurationInSeconds Minimum seconds between epochs.
 | 
			
		||||
    /// @return _rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm.
 | 
			
		||||
    /// @return _minimumPoolStake Minimum amount of stake required in a pool to collect rewards.
 | 
			
		||||
    /// @return _cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor.
 | 
			
		||||
    /// @return _cobbDouglasAlphaDenominator Denominator for cobb douglas alpha factor.
 | 
			
		||||
    function getParams()
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (
 | 
			
		||||
            uint256 _epochDurationInSeconds,
 | 
			
		||||
            uint32 _rewardDelegatedStakeWeight,
 | 
			
		||||
            uint256 _minimumPoolStake,
 | 
			
		||||
            uint32 _cobbDouglasAlphaNumerator,
 | 
			
		||||
            uint32 _cobbDouglasAlphaDenominator
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    /// @param staker of stake.
 | 
			
		||||
    /// @param poolId Unique Id of pool.
 | 
			
		||||
    /// @return balance Stake delegated to pool by staker.
 | 
			
		||||
    function getStakeDelegatedToPoolByOwner(
 | 
			
		||||
        address staker,
 | 
			
		||||
        bytes32 poolId
 | 
			
		||||
    ) external view returns (IStructs.StoredBalance memory balance);
 | 
			
		||||
 | 
			
		||||
    /// @dev Returns a staking pool
 | 
			
		||||
    /// @param poolId Unique id of pool.
 | 
			
		||||
    function getStakingPool(bytes32 poolId) external view returns (IStructs.Pool memory);
 | 
			
		||||
 | 
			
		||||
    /// @dev Get stats on a staking pool in this epoch.
 | 
			
		||||
    /// @param poolId Pool Id to query.
 | 
			
		||||
    /// @return PoolStats struct for pool id.
 | 
			
		||||
    function getStakingPoolStatsThisEpoch(bytes32 poolId) external view returns (IStructs.PoolStats memory);
 | 
			
		||||
 | 
			
		||||
    /// @dev Returns the total stake delegated to a specific staking pool,
 | 
			
		||||
    ///      across all members.
 | 
			
		||||
    /// @param poolId Unique Id of pool.
 | 
			
		||||
    /// @return balance Total stake delegated to pool.
 | 
			
		||||
    function getTotalStakeDelegatedToPool(bytes32 poolId) external view returns (IStructs.StoredBalance memory balance);
 | 
			
		||||
 | 
			
		||||
    /// @dev An overridable way to access the deployed WETH contract.
 | 
			
		||||
    ///      Must be view to allow overrides to access state.
 | 
			
		||||
    /// @return wethContract The WETH contract instance.
 | 
			
		||||
    function getWethContract() external view returns (address wethContract);
 | 
			
		||||
 | 
			
		||||
    /// @dev An overridable way to access the deployed zrxVault.
 | 
			
		||||
    ///      Must be view to allow overrides to access state.
 | 
			
		||||
    /// @return zrxVault The zrxVault contract.
 | 
			
		||||
    function getZrxVault() external view returns (IZrxVaultMock zrxVault);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								contracts/governance/test/mocks/IStorageMock.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								contracts/governance/test/mocks/IStorageMock.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2021 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.8.19;
 | 
			
		||||
 | 
			
		||||
import "./IZrxVaultMock.sol";
 | 
			
		||||
import "./IStructs.sol";
 | 
			
		||||
 | 
			
		||||
interface IStorageMock {
 | 
			
		||||
    function stakingContract() external view returns (address);
 | 
			
		||||
 | 
			
		||||
    function lastPoolId() external view returns (bytes32);
 | 
			
		||||
 | 
			
		||||
    function numMakersByPoolId(bytes32 poolId) external view returns (uint256);
 | 
			
		||||
 | 
			
		||||
    function currentEpoch() external view returns (uint256);
 | 
			
		||||
 | 
			
		||||
    function currentEpochStartTimeInSeconds() external view returns (uint256);
 | 
			
		||||
 | 
			
		||||
    function protocolFeesThisEpochByPool(bytes32 poolId) external view returns (uint256);
 | 
			
		||||
 | 
			
		||||
    function validExchanges(address exchangeAddress) external view returns (bool);
 | 
			
		||||
 | 
			
		||||
    function epochDurationInSeconds() external view returns (uint256);
 | 
			
		||||
 | 
			
		||||
    function rewardDelegatedStakeWeight() external view returns (uint32);
 | 
			
		||||
 | 
			
		||||
    function minimumPoolStake() external view returns (uint256);
 | 
			
		||||
 | 
			
		||||
    function cobbDouglasAlphaNumerator() external view returns (uint32);
 | 
			
		||||
 | 
			
		||||
    function cobbDouglasAlphaDenominator() external view returns (uint32);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										92
									
								
								contracts/governance/test/mocks/IStructs.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								contracts/governance/test/mocks/IStructs.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,92 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2021 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.8.19;
 | 
			
		||||
 | 
			
		||||
interface IStructs {
 | 
			
		||||
    /// @dev Stats for a pool that earned rewards.
 | 
			
		||||
    /// @param feesCollected Fees collected in ETH by this pool.
 | 
			
		||||
    /// @param weightedStake Amount of weighted stake in the pool.
 | 
			
		||||
    /// @param membersStake Amount of non-operator stake in the pool.
 | 
			
		||||
    struct PoolStats {
 | 
			
		||||
        uint256 feesCollected;
 | 
			
		||||
        uint256 weightedStake;
 | 
			
		||||
        uint256 membersStake;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Holds stats aggregated across a set of pools.
 | 
			
		||||
    /// @param rewardsAvailable Rewards (ETH) available to the epoch
 | 
			
		||||
    ///        being finalized (the previous epoch). This is simply the balance
 | 
			
		||||
    ///        of the contract at the end of the epoch.
 | 
			
		||||
    /// @param numPoolsToFinalize The number of pools that have yet to be finalized through `finalizePools()`.
 | 
			
		||||
    /// @param totalFeesCollected The total fees collected for the epoch being finalized.
 | 
			
		||||
    /// @param totalWeightedStake The total fees collected for the epoch being finalized.
 | 
			
		||||
    /// @param totalRewardsFinalized Amount of rewards that have been paid during finalization.
 | 
			
		||||
    struct AggregatedStats {
 | 
			
		||||
        uint256 rewardsAvailable;
 | 
			
		||||
        uint256 numPoolsToFinalize;
 | 
			
		||||
        uint256 totalFeesCollected;
 | 
			
		||||
        uint256 totalWeightedStake;
 | 
			
		||||
        uint256 totalRewardsFinalized;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Encapsulates a balance for the current and next epochs.
 | 
			
		||||
    /// Note that these balances may be stale if the current epoch
 | 
			
		||||
    /// is greater than `currentEpoch`.
 | 
			
		||||
    /// @param currentEpoch the current epoch
 | 
			
		||||
    /// @param currentEpochBalance balance in the current epoch.
 | 
			
		||||
    /// @param nextEpochBalance balance in `currentEpoch+1`.
 | 
			
		||||
    struct StoredBalance {
 | 
			
		||||
        uint64 currentEpoch;
 | 
			
		||||
        uint96 currentEpochBalance;
 | 
			
		||||
        uint96 nextEpochBalance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Statuses that stake can exist in.
 | 
			
		||||
    ///      Any stake can be (re)delegated effective at the next epoch
 | 
			
		||||
    ///      Undelegated stake can be withdrawn if it is available in both the current and next epoch
 | 
			
		||||
    enum StakeStatus {
 | 
			
		||||
        UNDELEGATED,
 | 
			
		||||
        DELEGATED
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Info used to describe a status.
 | 
			
		||||
    /// @param status of the stake.
 | 
			
		||||
    /// @param poolId Unique Id of pool. This is set when status=DELEGATED.
 | 
			
		||||
    struct StakeInfo {
 | 
			
		||||
        StakeStatus status;
 | 
			
		||||
        bytes32 poolId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Struct to represent a fraction.
 | 
			
		||||
    /// @param numerator of fraction.
 | 
			
		||||
    /// @param denominator of fraction.
 | 
			
		||||
    struct Fraction {
 | 
			
		||||
        uint256 numerator;
 | 
			
		||||
        uint256 denominator;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Holds the metadata for a staking pool.
 | 
			
		||||
    /// @param operator of the pool.
 | 
			
		||||
    /// @param operatorShare Fraction of the total balance owned by the operator, in ppm.
 | 
			
		||||
    struct Pool {
 | 
			
		||||
        address operator;
 | 
			
		||||
        uint32 operatorShare;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,30 +1,24 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2022 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Copyright 2023 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.6;
 | 
			
		||||
pragma solidity ^0.8.19;
 | 
			
		||||
 | 
			
		||||
import "forge-std/Test.sol";
 | 
			
		||||
import "./IOwnableFeature.sol";
 | 
			
		||||
import "./ISimpleFunctionRegistryFeature.sol";
 | 
			
		||||
 | 
			
		||||
contract ContractTest is Test {
 | 
			
		||||
    function setUp() public {}
 | 
			
		||||
 | 
			
		||||
    function testExample() public {
 | 
			
		||||
        assertTrue(true);
 | 
			
		||||
    }
 | 
			
		||||
/// @dev Minimal viable Exchange Proxy interface for governance use.
 | 
			
		||||
interface IZeroExMock is IOwnableFeature, ISimpleFunctionRegistryFeature {
 | 
			
		||||
    /// @dev Fallback for just receiving ether.
 | 
			
		||||
    receive() external payable;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										159
									
								
								contracts/governance/test/mocks/IZrxTreasuryMock.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								contracts/governance/test/mocks/IZrxTreasuryMock.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,159 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2021 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.8.19;
 | 
			
		||||
 | 
			
		||||
import "./IStakingMock.sol";
 | 
			
		||||
 | 
			
		||||
/// @dev Minimal viable Treasury interface for governance use.
 | 
			
		||||
interface IZrxTreasuryMock {
 | 
			
		||||
    struct TreasuryParameters {
 | 
			
		||||
        uint256 votingPeriod;
 | 
			
		||||
        uint256 proposalThreshold;
 | 
			
		||||
        uint256 quorumThreshold;
 | 
			
		||||
        bytes32 defaultPoolId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct ProposedAction {
 | 
			
		||||
        address target;
 | 
			
		||||
        bytes data;
 | 
			
		||||
        uint256 value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct Proposal {
 | 
			
		||||
        bytes32 actionsHash;
 | 
			
		||||
        uint256 executionEpoch;
 | 
			
		||||
        uint256 voteEpoch;
 | 
			
		||||
        uint256 votesFor;
 | 
			
		||||
        uint256 votesAgainst;
 | 
			
		||||
        bool executed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    event ProposalCreated(
 | 
			
		||||
        address proposer,
 | 
			
		||||
        bytes32[] operatedPoolIds,
 | 
			
		||||
        uint256 proposalId,
 | 
			
		||||
        ProposedAction[] actions,
 | 
			
		||||
        uint256 executionEpoch,
 | 
			
		||||
        string description
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    event VoteCast(address voter, bytes32[] operatedPoolIds, uint256 proposalId, bool support, uint256 votingPower);
 | 
			
		||||
 | 
			
		||||
    event ProposalExecuted(uint256 proposalId);
 | 
			
		||||
 | 
			
		||||
    function stakingProxy() external view returns (IStakingMock);
 | 
			
		||||
 | 
			
		||||
    function defaultPoolId() external view returns (bytes32);
 | 
			
		||||
 | 
			
		||||
    function votingPeriod() external view returns (uint256);
 | 
			
		||||
 | 
			
		||||
    function proposalThreshold() external view returns (uint256);
 | 
			
		||||
 | 
			
		||||
    function quorumThreshold() external view returns (uint256);
 | 
			
		||||
 | 
			
		||||
    /// @dev Updates the proposal and quorum thresholds to the given
 | 
			
		||||
    ///      values. Note that this function is only callable by the
 | 
			
		||||
    ///      treasury contract itself, so the threshold can only be
 | 
			
		||||
    ///      updated via a successful treasury proposal.
 | 
			
		||||
    /// @param newProposalThreshold The new value for the proposal threshold.
 | 
			
		||||
    /// @param newQuorumThreshold The new value for the quorum threshold.
 | 
			
		||||
    function updateThresholds(uint256 newProposalThreshold, uint256 newQuorumThreshold) external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Creates a proposal to send ZRX from this treasury on the
 | 
			
		||||
    ///      the given actions. Must have at least `proposalThreshold`
 | 
			
		||||
    ///      of voting power to call this function. See `getVotingPower`
 | 
			
		||||
    ///      for how voting power is computed. If a proposal is successfully
 | 
			
		||||
    ///      created, voting starts at the epoch after next (currentEpoch + 2).
 | 
			
		||||
    ///      If the vote passes, the proposal is executable during the
 | 
			
		||||
    ///      `executionEpoch`. See `hasProposalPassed` for the passing criteria.
 | 
			
		||||
    /// @param actions The proposed ZRX actions. An action specifies a
 | 
			
		||||
    ///        contract call.
 | 
			
		||||
    /// @param executionEpoch The epoch during which the proposal is to
 | 
			
		||||
    ///        be executed if it passes. Must be at least two epochs
 | 
			
		||||
    ///        from the current epoch.
 | 
			
		||||
    /// @param description A text description for the proposal.
 | 
			
		||||
    /// @param operatedPoolIds The pools operated by `msg.sender`. The
 | 
			
		||||
    ///        ZRX currently delegated to those pools will be accounted
 | 
			
		||||
    ///        for in the voting power.
 | 
			
		||||
    /// @return proposalId The ID of the newly created proposal.
 | 
			
		||||
    function propose(
 | 
			
		||||
        ProposedAction[] calldata actions,
 | 
			
		||||
        uint256 executionEpoch,
 | 
			
		||||
        string calldata description,
 | 
			
		||||
        bytes32[] calldata operatedPoolIds
 | 
			
		||||
    ) external returns (uint256 proposalId);
 | 
			
		||||
 | 
			
		||||
    /// @dev Casts a vote for the given proposal. Only callable
 | 
			
		||||
    ///      during the voting period for that proposal.
 | 
			
		||||
    ///      One address can only vote once.
 | 
			
		||||
    ///      See `getVotingPower` for how voting power is computed.
 | 
			
		||||
    /// @param proposalId The ID of the proposal to vote on.
 | 
			
		||||
    /// @param support Whether to support the proposal or not.
 | 
			
		||||
    /// @param operatedPoolIds The pools operated by `msg.sender`. The
 | 
			
		||||
    ///        ZRX currently delegated to those pools will be accounted
 | 
			
		||||
    ///        for in the voting power.
 | 
			
		||||
    function castVote(uint256 proposalId, bool support, bytes32[] calldata operatedPoolIds) external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Casts a vote for the given proposal, by signature.
 | 
			
		||||
    ///      Only callable during the voting period for that proposal.
 | 
			
		||||
    ///      One address/voter can only vote once.
 | 
			
		||||
    ///      See `getVotingPower` for how voting power is computed.
 | 
			
		||||
    /// @param proposalId The ID of the proposal to vote on.
 | 
			
		||||
    /// @param support Whether to support the proposal or not.
 | 
			
		||||
    /// @param operatedPoolIds The pools operated by the signer. The
 | 
			
		||||
    ///        ZRX currently delegated to those pools will be accounted
 | 
			
		||||
    ///        for in the voting power.
 | 
			
		||||
    /// @param v the v field of the signature
 | 
			
		||||
    /// @param r the r field of the signature
 | 
			
		||||
    /// @param s the s field of the signature
 | 
			
		||||
    function castVoteBySignature(
 | 
			
		||||
        uint256 proposalId,
 | 
			
		||||
        bool support,
 | 
			
		||||
        bytes32[] memory operatedPoolIds,
 | 
			
		||||
        uint8 v,
 | 
			
		||||
        bytes32 r,
 | 
			
		||||
        bytes32 s
 | 
			
		||||
    ) external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Executes a proposal that has passed and is
 | 
			
		||||
    ///      currently executable.
 | 
			
		||||
    /// @param proposalId The ID of the proposal to execute.
 | 
			
		||||
    /// @param actions Actions associated with the proposal to execute.
 | 
			
		||||
    function execute(uint256 proposalId, ProposedAction[] memory actions) external payable;
 | 
			
		||||
 | 
			
		||||
    /// @dev Returns the total number of proposals.
 | 
			
		||||
    /// @return count The number of proposals.
 | 
			
		||||
    function proposalCount() external view returns (uint256 count);
 | 
			
		||||
 | 
			
		||||
    /// @dev Computes the current voting power of the given account.
 | 
			
		||||
    ///      Voting power is equal to:
 | 
			
		||||
    ///      (ZRX delegated to the default pool) +
 | 
			
		||||
    ///      0.5 * (ZRX delegated to other pools) +
 | 
			
		||||
    ///      0.5 * (ZRX delegated to pools operated by account)
 | 
			
		||||
    /// @param account The address of the account.
 | 
			
		||||
    /// @param operatedPoolIds The pools operated by `account`. The
 | 
			
		||||
    ///        ZRX currently delegated to those pools will be accounted
 | 
			
		||||
    ///        for in the voting power.
 | 
			
		||||
    /// @return votingPower The current voting power of the given account.
 | 
			
		||||
    function getVotingPower(
 | 
			
		||||
        address account,
 | 
			
		||||
        bytes32[] calldata operatedPoolIds
 | 
			
		||||
    ) external view returns (uint256 votingPower);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										83
									
								
								contracts/governance/test/mocks/IZrxVaultMock.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								contracts/governance/test/mocks/IZrxVaultMock.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.8.19;
 | 
			
		||||
 | 
			
		||||
interface IZrxVaultMock {
 | 
			
		||||
    /// @dev Emmitted whenever a StakingProxy is set in a vault.
 | 
			
		||||
    event StakingProxySet(address stakingProxyAddress);
 | 
			
		||||
 | 
			
		||||
    /// @dev Emitted when the Staking contract is put into Catastrophic Failure Mode
 | 
			
		||||
    /// @param sender Address of sender (`msg.sender`)
 | 
			
		||||
    event InCatastrophicFailureMode(address sender);
 | 
			
		||||
 | 
			
		||||
    /// @dev Emitted when Zrx Tokens are deposited into the vault.
 | 
			
		||||
    /// @param staker of Zrx Tokens.
 | 
			
		||||
    /// @param amount of Zrx Tokens deposited.
 | 
			
		||||
    event Deposit(address indexed staker, uint256 amount);
 | 
			
		||||
 | 
			
		||||
    /// @dev Emitted when Zrx Tokens are withdrawn from the vault.
 | 
			
		||||
    /// @param staker of Zrx Tokens.
 | 
			
		||||
    /// @param amount of Zrx Tokens withdrawn.
 | 
			
		||||
    event Withdraw(address indexed staker, uint256 amount);
 | 
			
		||||
 | 
			
		||||
    /// @dev Emitted whenever the ZRX AssetProxy is set.
 | 
			
		||||
    event ZrxProxySet(address zrxProxyAddress);
 | 
			
		||||
 | 
			
		||||
    /// @dev Sets the address of the StakingProxy contract.
 | 
			
		||||
    /// Note that only the contract staker can call this function.
 | 
			
		||||
    /// @param _stakingProxyAddress Address of Staking proxy contract.
 | 
			
		||||
    function setStakingProxy(address _stakingProxyAddress) external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Vault enters into Catastrophic Failure Mode.
 | 
			
		||||
    /// *** WARNING - ONCE IN CATOSTROPHIC FAILURE MODE, YOU CAN NEVER GO BACK! ***
 | 
			
		||||
    /// Note that only the contract staker can call this function.
 | 
			
		||||
    function enterCatastrophicFailure() external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Sets the Zrx proxy.
 | 
			
		||||
    /// Note that only the contract staker can call this.
 | 
			
		||||
    /// Note that this can only be called when *not* in Catastrophic Failure mode.
 | 
			
		||||
    /// @param zrxProxyAddress Address of the 0x Zrx Proxy.
 | 
			
		||||
    function setZrxProxy(address zrxProxyAddress) external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Deposit an `amount` of Zrx Tokens from `staker` into the vault.
 | 
			
		||||
    /// Note that only the Staking contract can call this.
 | 
			
		||||
    /// Note that this can only be called when *not* in Catastrophic Failure mode.
 | 
			
		||||
    /// @param staker of Zrx Tokens.
 | 
			
		||||
    /// @param amount of Zrx Tokens to deposit.
 | 
			
		||||
    function depositFrom(address staker, uint256 amount) external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Withdraw an `amount` of Zrx Tokens to `staker` from the vault.
 | 
			
		||||
    /// Note that only the Staking contract can call this.
 | 
			
		||||
    /// Note that this can only be called when *not* in Catastrophic Failure mode.
 | 
			
		||||
    /// @param staker of Zrx Tokens.
 | 
			
		||||
    /// @param amount of Zrx Tokens to withdraw.
 | 
			
		||||
    function withdrawFrom(address staker, uint256 amount) external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Withdraw ALL Zrx Tokens to `staker` from the vault.
 | 
			
		||||
    /// Note that this can only be called when *in* Catastrophic Failure mode.
 | 
			
		||||
    /// @param staker of Zrx Tokens.
 | 
			
		||||
    function withdrawAllFrom(address staker) external returns (uint256);
 | 
			
		||||
 | 
			
		||||
    /// @dev Returns the balance in Zrx Tokens of the `staker`
 | 
			
		||||
    /// @return Balance in Zrx.
 | 
			
		||||
    function balanceOf(address staker) external view returns (uint256);
 | 
			
		||||
 | 
			
		||||
    /// @dev Returns the entire balance of Zrx tokens in the vault.
 | 
			
		||||
    function balanceOfZrxVault() external view returns (uint256);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2019 ZeroEx Intl.
 | 
			
		||||
  Copyright 2023 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,16 +17,15 @@
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.9;
 | 
			
		||||
pragma solidity ^0.8.19;
 | 
			
		||||
 | 
			
		||||
library LibAddressArrayRichErrors {
 | 
			
		||||
    // bytes4(keccak256("MismanagedMemoryError(uint256,uint256)"))
 | 
			
		||||
    bytes4 internal constant MISMANAGED_MEMORY_ERROR_SELECTOR = 0x5fc83722;
 | 
			
		||||
import "forge-std/Test.sol";
 | 
			
		||||
import "@openzeppelin/token/ERC20/ERC20.sol";
 | 
			
		||||
 | 
			
		||||
    function MismanagedMemoryError(
 | 
			
		||||
        uint256 freeMemPtr,
 | 
			
		||||
        uint256 addressArrayEndPtr
 | 
			
		||||
    ) internal pure returns (bytes memory) {
 | 
			
		||||
        return abi.encodeWithSelector(MISMANAGED_MEMORY_ERROR_SELECTOR, freeMemPtr, addressArrayEndPtr);
 | 
			
		||||
// TODO remove this contract and work with an instance of ZRX compiled with 0.4
 | 
			
		||||
// when the following is resolved https://linear.app/0xproject/issue/PRO-44/zrx-artifact-is-incompatible-with-foundry
 | 
			
		||||
contract ZRXMock is ERC20 {
 | 
			
		||||
    constructor() ERC20("0x Protocol Token", "ZRX") {
 | 
			
		||||
        _mint(msg.sender, 10 ** 27);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								contracts/governance/test/mocks/ZeroExMock.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								contracts/governance/test/mocks/ZeroExMock.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
// SPDX-License-Identifier: MIT
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.8.19;
 | 
			
		||||
 | 
			
		||||
contract ZeroExMock {
 | 
			
		||||
    mapping(bytes4 => address) public implementations;
 | 
			
		||||
 | 
			
		||||
    function rollback(bytes4 selector, address targetImpl) public {
 | 
			
		||||
        implementations[selector] = targetImpl;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2019 ZeroEx Intl.
 | 
			
		||||
  Copyright 2023 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
@@ -15,13 +16,17 @@
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
pragma solidity ^0.8.19;
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.9;
 | 
			
		||||
import "../../src/ZeroExVotes.sol";
 | 
			
		||||
 | 
			
		||||
import "./IERC20Token.sol";
 | 
			
		||||
contract ZeroExVotesMalicious is ZeroExVotes {
 | 
			
		||||
    constructor(address _token, uint256 _quadraticThreshold) ZeroExVotes(_token, _quadraticThreshold) {}
 | 
			
		||||
 | 
			
		||||
contract IEtherToken is IERC20Token {
 | 
			
		||||
    function deposit() public payable;
 | 
			
		||||
 | 
			
		||||
    function withdraw(uint256 amount) public;
 | 
			
		||||
    function writeCheckpointTotalSupplyBurn(
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        uint256 accountBalance
 | 
			
		||||
    ) public virtual override onlyToken returns (bool) {
 | 
			
		||||
        revert("I am evil");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										215
									
								
								contracts/governance/test/mocks/ZeroExVotesMigration.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								contracts/governance/test/mocks/ZeroExVotesMigration.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,215 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2023 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.8.19;
 | 
			
		||||
 | 
			
		||||
import {ZeroExVotes} from "../../src/ZeroExVotes.sol";
 | 
			
		||||
import {SafeCast} from "@openzeppelin/utils/math/SafeCast.sol";
 | 
			
		||||
import {Math} from "@openzeppelin/utils/math/Math.sol";
 | 
			
		||||
import {CubeRoot} from "./CubeRoot.sol";
 | 
			
		||||
 | 
			
		||||
contract ZeroExVotesMigration is ZeroExVotes {
 | 
			
		||||
    uint32 public migrationBlock;
 | 
			
		||||
 | 
			
		||||
    constructor(address _token, uint256 _quadraticThreshold) ZeroExVotes(_token, _quadraticThreshold) {}
 | 
			
		||||
 | 
			
		||||
    function initialize() public virtual override onlyProxy reinitializer(2) {
 | 
			
		||||
        migrationBlock = uint32(block.number);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct CheckpointMigration {
 | 
			
		||||
        uint32 fromBlock;
 | 
			
		||||
        uint96 votes;
 | 
			
		||||
        uint96 quadraticVotes;
 | 
			
		||||
        uint32 migratedVotes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _toMigration(Checkpoint storage ckpt) internal pure returns (CheckpointMigration storage result) {
 | 
			
		||||
        assembly {
 | 
			
		||||
            result.slot := ckpt.slot
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _toMigration(Checkpoint[] storage ckpt) internal pure returns (CheckpointMigration[] storage result) {
 | 
			
		||||
        assembly {
 | 
			
		||||
            result.slot := ckpt.slot
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getMigratedVotes(address account) public view returns (uint256) {
 | 
			
		||||
        uint256 pos = _checkpoints[account].length;
 | 
			
		||||
        if (pos == 0) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        Checkpoint storage ckpt = _unsafeAccess(_checkpoints[account], pos - 1);
 | 
			
		||||
        if (ckpt.fromBlock <= migrationBlock) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        return _toMigration(ckpt).migratedVotes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getPastMigratedVotes(address account, uint256 blockNumber) public view returns (uint256) {
 | 
			
		||||
        require(blockNumber < block.number, "ZeroExVotesMigration: block not yet mined");
 | 
			
		||||
        if (blockNumber <= migrationBlock) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Checkpoint storage checkpoint = _checkpointsLookupStorage(_checkpoints[account], blockNumber);
 | 
			
		||||
        if (checkpoint.fromBlock <= migrationBlock) {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
        return _toMigration(checkpoint).migratedVotes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _checkpointsLookupStorage(
 | 
			
		||||
        Checkpoint[] storage ckpts,
 | 
			
		||||
        uint256 blockNumber
 | 
			
		||||
    ) internal view returns (Checkpoint storage result) {
 | 
			
		||||
        // We run a binary search to look for the earliest checkpoint taken after `blockNumber`.
 | 
			
		||||
        //
 | 
			
		||||
        // Initially we check if the block is recent to narrow the search range.
 | 
			
		||||
        // During the loop, the index of the wanted checkpoint remains in the range [low-1, high).
 | 
			
		||||
        // With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the
 | 
			
		||||
        // invariant.
 | 
			
		||||
        // - If the middle checkpoint is after `blockNumber`, we look in [low, mid)
 | 
			
		||||
        // - If the middle checkpoint is before or equal to `blockNumber`, we look in [mid+1, high)
 | 
			
		||||
        // Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not
 | 
			
		||||
        // out of bounds (in which case we're looking too far in the past and the result is 0).
 | 
			
		||||
        // Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is
 | 
			
		||||
        // past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out
 | 
			
		||||
        // the same.
 | 
			
		||||
        uint256 length = ckpts.length;
 | 
			
		||||
 | 
			
		||||
        uint256 low = 0;
 | 
			
		||||
        uint256 high = length;
 | 
			
		||||
 | 
			
		||||
        if (length > 5) {
 | 
			
		||||
            uint256 mid = length - Math.sqrt(length);
 | 
			
		||||
            if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
 | 
			
		||||
                high = mid;
 | 
			
		||||
            } else {
 | 
			
		||||
                low = mid + 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        while (low < high) {
 | 
			
		||||
            uint256 mid = Math.average(low, high);
 | 
			
		||||
            if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
 | 
			
		||||
                high = mid;
 | 
			
		||||
            } else {
 | 
			
		||||
                low = mid + 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Leaving here for posterity this is the original OZ implementation which we've replaced
 | 
			
		||||
        // return high == 0 ? 0 : _unsafeAccess(ckpts, high - 1).votes;
 | 
			
		||||
        // Checkpoint memory checkpoint = high == 0 ? Checkpoint(0, 0, 0) : _unsafeAccess(ckpts, high - 1);
 | 
			
		||||
        // return checkpoint;
 | 
			
		||||
        // TODO: bad. very bad. only works on accident
 | 
			
		||||
        if (high > 0) {
 | 
			
		||||
            result = _unsafeAccess(ckpts, high - 1);
 | 
			
		||||
        } else {
 | 
			
		||||
            // suppress compiler warning, which really shouldn't be suppressed
 | 
			
		||||
            assembly {
 | 
			
		||||
                result.slot := 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO: we're not handling totalSupply
 | 
			
		||||
 | 
			
		||||
    // TODO: need to return the migrated weight
 | 
			
		||||
    function _writeCheckpoint(
 | 
			
		||||
        Checkpoint[] storage ckpts,
 | 
			
		||||
        function(uint256, uint256) view returns (uint256) op,
 | 
			
		||||
        uint256 userBalance,
 | 
			
		||||
        uint96 balanceLastUpdated,
 | 
			
		||||
        uint256 delta
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
        virtual
 | 
			
		||||
        override
 | 
			
		||||
        returns (uint256 oldWeight, uint256 newWeight, uint256 oldQuadraticWeight, uint256 newQuadraticWeight)
 | 
			
		||||
    {
 | 
			
		||||
        uint256 pos = ckpts.length;
 | 
			
		||||
 | 
			
		||||
        CheckpointMigration memory oldCkpt = pos == 0
 | 
			
		||||
            ? CheckpointMigration(0, 0, 0, 0)
 | 
			
		||||
            : _toMigration(_unsafeAccess(ckpts, pos - 1));
 | 
			
		||||
 | 
			
		||||
        oldWeight = oldCkpt.votes;
 | 
			
		||||
        newWeight = op(oldWeight, delta);
 | 
			
		||||
 | 
			
		||||
        oldQuadraticWeight = oldCkpt.quadraticVotes;
 | 
			
		||||
 | 
			
		||||
        if (pos > 0) {
 | 
			
		||||
            deductOldWeightFromCheckpoint(oldCkpt, userBalance, balanceLastUpdated);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // if wallet > threshold, calculate quadratic power over the treshold only, below threshold is linear
 | 
			
		||||
        uint256 newBalance = op(userBalance, delta);
 | 
			
		||||
        uint256 newQuadraticBalance = newBalance <= quadraticThreshold
 | 
			
		||||
            ? newBalance
 | 
			
		||||
            : quadraticThreshold + Math.sqrt((newBalance - quadraticThreshold) * 1e18);
 | 
			
		||||
        newQuadraticWeight = oldCkpt.quadraticVotes + newQuadraticBalance;
 | 
			
		||||
        uint256 newMigratedWeight = oldCkpt.migratedVotes + CubeRoot.cbrt(newBalance);
 | 
			
		||||
 | 
			
		||||
        if (pos > 0 && oldCkpt.fromBlock == block.number) {
 | 
			
		||||
            addCheckpoint(ckpts, pos, newWeight, newQuadraticWeight, newMigratedWeight);
 | 
			
		||||
        } else {
 | 
			
		||||
            _toMigration(ckpts).push(
 | 
			
		||||
                CheckpointMigration({
 | 
			
		||||
                    fromBlock: SafeCast.toUint32(block.number),
 | 
			
		||||
                    votes: SafeCast.toUint96(newWeight),
 | 
			
		||||
                    quadraticVotes: SafeCast.toUint96(newQuadraticWeight),
 | 
			
		||||
                    migratedVotes: SafeCast.toUint32(newMigratedWeight)
 | 
			
		||||
                })
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function deductOldWeightFromCheckpoint(
 | 
			
		||||
        CheckpointMigration memory oldCkpt,
 | 
			
		||||
        uint256 userBalance,
 | 
			
		||||
        uint96 balanceLastUpdated
 | 
			
		||||
    ) internal {
 | 
			
		||||
        // Remove the entire sqrt userBalance from quadratic voting power.
 | 
			
		||||
        // Note that `userBalance` is value _after_ transfer.
 | 
			
		||||
        uint256 oldQuadraticVotingPower = userBalance <= quadraticThreshold
 | 
			
		||||
            ? userBalance
 | 
			
		||||
            : quadraticThreshold + Math.sqrt((userBalance - quadraticThreshold) * 1e18);
 | 
			
		||||
        oldCkpt.quadraticVotes -= SafeCast.toUint96(oldQuadraticVotingPower);
 | 
			
		||||
 | 
			
		||||
        if (balanceLastUpdated > migrationBlock) {
 | 
			
		||||
            oldCkpt.migratedVotes -= SafeCast.toUint32(CubeRoot.cbrt(userBalance));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function addCheckpoint(
 | 
			
		||||
        Checkpoint[] storage ckpts,
 | 
			
		||||
        uint256 pos,
 | 
			
		||||
        uint256 newWeight,
 | 
			
		||||
        uint256 newQuadraticWeight,
 | 
			
		||||
        uint256 newMigratedWeight
 | 
			
		||||
    ) internal {
 | 
			
		||||
        CheckpointMigration storage chpt = _toMigration(_unsafeAccess(ckpts, pos - 1));
 | 
			
		||||
        chpt.votes = SafeCast.toUint96(newWeight);
 | 
			
		||||
        chpt.quadraticVotes = SafeCast.toUint96(newQuadraticWeight);
 | 
			
		||||
        chpt.migratedVotes = SafeCast.toUint32(newMigratedWeight);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										315
									
								
								contracts/governance/test/unit/ZRXWrappedTokenTest.t.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										315
									
								
								contracts/governance/test/unit/ZRXWrappedTokenTest.t.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,315 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2023 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.8.19;
 | 
			
		||||
 | 
			
		||||
import "../BaseTest.t.sol";
 | 
			
		||||
import "../../src/ZRXWrappedToken.sol";
 | 
			
		||||
import "@openzeppelin/token/ERC20/ERC20.sol";
 | 
			
		||||
 | 
			
		||||
contract ZRXWrappedTokenTest is BaseTest {
 | 
			
		||||
    IERC20 private token;
 | 
			
		||||
    ZRXWrappedToken private wToken;
 | 
			
		||||
    ZeroExVotes private votes;
 | 
			
		||||
 | 
			
		||||
    function setUp() public {
 | 
			
		||||
        token = mockZRXToken();
 | 
			
		||||
        (wToken, votes, , , , ) = setupGovernance(token);
 | 
			
		||||
        vm.startPrank(account1);
 | 
			
		||||
        token.transfer(account2, 100e18);
 | 
			
		||||
        token.transfer(account3, 200e18);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldReturnCorrectSymbol() public {
 | 
			
		||||
        string memory wZRXSymbol = wToken.symbol();
 | 
			
		||||
        assertEq(wZRXSymbol, "wZRX");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldReturnCorrectName() public {
 | 
			
		||||
        string memory wZRXName = wToken.name();
 | 
			
		||||
        assertEq(wZRXName, "Wrapped ZRX");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldReturnCorrectNumberOfDecimals() public {
 | 
			
		||||
        uint8 wZRXDecimals = wToken.decimals();
 | 
			
		||||
        assertEq(wZRXDecimals, 18);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldBeAbleToWrapZRX() public {
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
 | 
			
		||||
        // Approve the wrapped token and deposit 1e18 ZRX
 | 
			
		||||
        token.approve(address(wToken), 1e18);
 | 
			
		||||
        wToken.depositFor(account2, 1e18);
 | 
			
		||||
 | 
			
		||||
        // Check the token balances even out
 | 
			
		||||
        uint256 wTokenBalance = wToken.balanceOf(account2);
 | 
			
		||||
        assertEq(wTokenBalance, 1e18);
 | 
			
		||||
        uint256 tokenBalance = token.balanceOf(account2);
 | 
			
		||||
        assertEq(tokenBalance, 100e18 - wTokenBalance);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldBeAbleToUnwrapToZRX() public {
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
 | 
			
		||||
        // Approve the wrapped token and deposit 1e18 ZRX
 | 
			
		||||
        token.approve(address(wToken), 1e18);
 | 
			
		||||
        wToken.depositFor(account2, 1e18);
 | 
			
		||||
 | 
			
		||||
        // Withdraw 1e6 wZRX back to ZRX to own account
 | 
			
		||||
        wToken.withdrawTo(account2, 1e6);
 | 
			
		||||
 | 
			
		||||
        // Check token balances even out
 | 
			
		||||
        uint256 wTokenBalance = wToken.balanceOf(account2);
 | 
			
		||||
        assertEq(wTokenBalance, 1e18 - 1e6);
 | 
			
		||||
        uint256 tokenBalance = token.balanceOf(account2);
 | 
			
		||||
        assertEq(tokenBalance, 100e18 - wTokenBalance);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldBeAbleToUnwrapToZRXToAnotherAccount() public {
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
 | 
			
		||||
        // Approve the wrapped token and deposit 1e18 ZRX
 | 
			
		||||
        token.approve(address(wToken), 1e18);
 | 
			
		||||
        wToken.depositFor(account2, 1e18);
 | 
			
		||||
 | 
			
		||||
        // Withdraw 1e7 wZRX back to ZRX to account4 (which owns no tokens to start with)
 | 
			
		||||
        wToken.withdrawTo(account4, 1e7);
 | 
			
		||||
 | 
			
		||||
        // Check token balances even out
 | 
			
		||||
        uint256 wTokenBalance2 = wToken.balanceOf(account2);
 | 
			
		||||
        assertEq(wTokenBalance2, 1e18 - 1e7);
 | 
			
		||||
 | 
			
		||||
        uint256 tokenBalance4 = token.balanceOf(account4);
 | 
			
		||||
        assertEq(tokenBalance4, 1e7);
 | 
			
		||||
 | 
			
		||||
        uint256 tokenBalance2 = token.balanceOf(account2);
 | 
			
		||||
        assertEq(tokenBalance2, 100e18 - wTokenBalance2 - tokenBalance4);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testWrappedZRXTotalsAreCorrect() public {
 | 
			
		||||
        // Wrap 1e18 and check total supply is correct
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        token.approve(address(wToken), 1e18);
 | 
			
		||||
        wToken.depositFor(account2, 1e18);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
        uint256 wTokenBalance = wToken.totalSupply();
 | 
			
		||||
        assertEq(wTokenBalance, 1e18);
 | 
			
		||||
 | 
			
		||||
        // Wrap 2e18 more and check total supply is correct
 | 
			
		||||
        vm.startPrank(account3);
 | 
			
		||||
        token.approve(address(wToken), 2e18);
 | 
			
		||||
        wToken.depositFor(account3, 2e18);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
        wTokenBalance = wToken.totalSupply();
 | 
			
		||||
        assertEq(wTokenBalance, 1e18 + 2e18);
 | 
			
		||||
 | 
			
		||||
        // Unwrap 1e7 and check total supply is correct
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        wToken.withdrawTo(account2, 1e7);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
        wTokenBalance = wToken.totalSupply();
 | 
			
		||||
        assertEq(wTokenBalance, 3e18 - 1e7);
 | 
			
		||||
 | 
			
		||||
        // Unwrap 8e17 and check total supply is correct
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        wToken.withdrawTo(account2, 8e17);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
        wTokenBalance = wToken.totalSupply();
 | 
			
		||||
        assertEq(wTokenBalance, 3e18 - 1e7 - 8e17);
 | 
			
		||||
 | 
			
		||||
        // We are not keeping record of total balances so check they are zero
 | 
			
		||||
        assertEq(votes.getPastTotalSupply(0), 0);
 | 
			
		||||
        assertEq(votes.getPastQuadraticTotalSupply(0), 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testWhenMintingFirstTimeForAccountTotalSupplyCheckpointsAreCorrect() public {
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
 | 
			
		||||
        // Approve the wrapped token and deposit 1e18 ZRX
 | 
			
		||||
        token.approve(address(wToken), 1e18);
 | 
			
		||||
        vm.roll(2);
 | 
			
		||||
        wToken.depositFor(account2, 1e18);
 | 
			
		||||
        vm.roll(3);
 | 
			
		||||
 | 
			
		||||
        // Check the totals are correct
 | 
			
		||||
        uint256 totalSupplyVotes = votes.getPastTotalSupply(2);
 | 
			
		||||
        uint256 totalSupplyQuadraticVotes = votes.getPastQuadraticTotalSupply(2);
 | 
			
		||||
        assertEq(totalSupplyVotes, 1e18);
 | 
			
		||||
        assertEq(totalSupplyQuadraticVotes, 1e18);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testWhenMintingForAccountWithExistingBalanceTotalSupplyCheckpointsAreCorrect() public {
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
 | 
			
		||||
        // Approve the wrapped token and deposit 1e18 ZRX
 | 
			
		||||
        token.approve(address(wToken), 5e18);
 | 
			
		||||
        wToken.depositFor(account2, 1e18);
 | 
			
		||||
 | 
			
		||||
        vm.roll(2);
 | 
			
		||||
        // Depost 3e18 more for the same account
 | 
			
		||||
        wToken.depositFor(account2, 3e18);
 | 
			
		||||
        vm.roll(3);
 | 
			
		||||
 | 
			
		||||
        // Check the totals are correct
 | 
			
		||||
        uint256 totalSupplyVotes = votes.getPastTotalSupply(2);
 | 
			
		||||
        uint256 totalSupplyQuadraticVotes = votes.getPastQuadraticTotalSupply(2);
 | 
			
		||||
        assertEq(totalSupplyVotes, 4e18);
 | 
			
		||||
        assertEq(totalSupplyQuadraticVotes, 4e18);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testWhenMintingForMultipleAccountsTotalSupplyCheckpointsAreCorrect() public {
 | 
			
		||||
        // Deposit 1e18 ZRX by account2
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        token.approve(address(wToken), 5e18);
 | 
			
		||||
        wToken.depositFor(account2, 1e18);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Deposit 2e18 ZRX by account3
 | 
			
		||||
        vm.startPrank(account3);
 | 
			
		||||
        token.approve(address(wToken), 2e18);
 | 
			
		||||
        wToken.depositFor(account3, 2e18);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Deposit 4e18 ZRX by account2
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        vm.roll(2);
 | 
			
		||||
        wToken.depositFor(account2, 4e18);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
        vm.roll(3);
 | 
			
		||||
 | 
			
		||||
        // Check the totals are correct
 | 
			
		||||
        uint256 totalSupplyVotes = votes.getPastTotalSupply(2);
 | 
			
		||||
        uint256 totalSupplyQuadraticVotes = votes.getPastQuadraticTotalSupply(2);
 | 
			
		||||
        assertEq(totalSupplyVotes, 7e18);
 | 
			
		||||
        assertEq(totalSupplyQuadraticVotes, 5e18 + 2e18);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testWhenBurningForMultipleAccountsTotalSupplyCheckpointsAreCorrect() public {
 | 
			
		||||
        // Deposit 5e18 ZRX by account2
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        token.approve(address(wToken), 5e18);
 | 
			
		||||
        wToken.depositFor(account2, 5e18);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Deposit 2e18 ZRX by account3
 | 
			
		||||
        vm.startPrank(account3);
 | 
			
		||||
        token.approve(address(wToken), 2e18);
 | 
			
		||||
        wToken.depositFor(account3, 2e18);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Burn 4e18 ZRX by account2
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        vm.roll(2);
 | 
			
		||||
        wToken.withdrawTo(account2, 4e18);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
        vm.roll(3);
 | 
			
		||||
 | 
			
		||||
        // Check the totals are correct
 | 
			
		||||
        uint256 totalSupplyVotes = votes.getPastTotalSupply(2);
 | 
			
		||||
        uint256 totalSupplyQuadraticVotes = votes.getPastQuadraticTotalSupply(2);
 | 
			
		||||
        assertEq(totalSupplyVotes, 3e18);
 | 
			
		||||
        assertEq(totalSupplyQuadraticVotes, 1e18 + 2e18);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldBeAbleToTransferCorrectly() public {
 | 
			
		||||
        assertEq(wToken.balanceOf(account4), 0);
 | 
			
		||||
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        token.approve(address(wToken), 1e18);
 | 
			
		||||
        wToken.depositFor(account2, 1e18);
 | 
			
		||||
        wToken.transfer(account4, 1e17);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        assertEq(wToken.balanceOf(account4), 1e17);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldTransferVotingPowerWhenTransferringTokens() public {
 | 
			
		||||
        // Account 2 wraps ZRX and delegates voting power to itself
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        token.approve(address(wToken), 10e18);
 | 
			
		||||
        wToken.depositFor(account2, 10e18);
 | 
			
		||||
        wToken.delegate(account2);
 | 
			
		||||
 | 
			
		||||
        wToken.transfer(account3, 3e18);
 | 
			
		||||
 | 
			
		||||
        assertEq(wToken.balanceOf(account2), 7e18);
 | 
			
		||||
        assertEq(wToken.balanceOf(account3), 3e18);
 | 
			
		||||
 | 
			
		||||
        assertEq(votes.getVotes(account2), 7e18);
 | 
			
		||||
        assertEq(votes.getQuadraticVotes(account2), 7e18);
 | 
			
		||||
 | 
			
		||||
        // Since account3 is not delegating to anyone, they should have no voting power
 | 
			
		||||
        assertEq(votes.getVotes(account3), 0);
 | 
			
		||||
        assertEq(votes.getQuadraticVotes(account3), 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldUpdateVotingPowerWhenDepositing() public {
 | 
			
		||||
        // Account 2 wraps ZRX and delegates voting power to itself
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        token.approve(address(wToken), 10e18);
 | 
			
		||||
        wToken.depositFor(account2, 7e18);
 | 
			
		||||
        wToken.delegate(account2);
 | 
			
		||||
 | 
			
		||||
        assertEq(votes.getVotes(account2), 7e18);
 | 
			
		||||
        assertEq(votes.getQuadraticVotes(account2), 7e18);
 | 
			
		||||
 | 
			
		||||
        wToken.depositFor(account2, 2e18);
 | 
			
		||||
        assertEq(votes.getVotes(account2), 9e18);
 | 
			
		||||
        assertEq(votes.getQuadraticVotes(account2), 9e18);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldUpdateVotingPowerWhenWithdrawing() public {
 | 
			
		||||
        // Account 2 wraps ZRX and delegates voting power to itself
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        token.approve(address(wToken), 10e18);
 | 
			
		||||
        wToken.depositFor(account2, 10e18);
 | 
			
		||||
        wToken.delegate(account2);
 | 
			
		||||
 | 
			
		||||
        assertEq(votes.getVotes(account2), 10e18);
 | 
			
		||||
        assertEq(votes.getQuadraticVotes(account2), 10e18);
 | 
			
		||||
 | 
			
		||||
        wToken.withdrawTo(account2, 2e18);
 | 
			
		||||
        assertEq(votes.getVotes(account2), 8e18);
 | 
			
		||||
        assertEq(votes.getQuadraticVotes(account2), 8e18);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldSetDelegateBalanceLastUpdatedOnTransfer() public {
 | 
			
		||||
        ZRXWrappedToken.DelegateInfo memory account2DelegateInfo = wToken.delegateInfo(account2);
 | 
			
		||||
        assertEq(account2DelegateInfo.delegate, address(0));
 | 
			
		||||
        assertEq(account2DelegateInfo.balanceLastUpdated, 0);
 | 
			
		||||
 | 
			
		||||
        // Account 2 wraps ZRX and delegates voting power to account3
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        token.approve(address(wToken), 10e18);
 | 
			
		||||
        wToken.depositFor(account2, 10e18);
 | 
			
		||||
        wToken.delegate(account3);
 | 
			
		||||
 | 
			
		||||
        account2DelegateInfo = wToken.delegateInfo(account2);
 | 
			
		||||
        assertEq(account2DelegateInfo.delegate, account3);
 | 
			
		||||
        assertEq(account2DelegateInfo.balanceLastUpdated, 1); // Set to the block.number
 | 
			
		||||
 | 
			
		||||
        vm.roll(3);
 | 
			
		||||
        wToken.transfer(account3, 3e18);
 | 
			
		||||
 | 
			
		||||
        account2DelegateInfo = wToken.delegateInfo(account2);
 | 
			
		||||
        assertEq(account2DelegateInfo.delegate, account3);
 | 
			
		||||
        assertEq(account2DelegateInfo.balanceLastUpdated, 3);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										460
									
								
								contracts/governance/test/unit/ZeroExGovernorBaseTest.t.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										460
									
								
								contracts/governance/test/unit/ZeroExGovernorBaseTest.t.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,460 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2023 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 IZeroExGovernorANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
pragma solidity ^0.8.19;
 | 
			
		||||
 | 
			
		||||
import "../BaseTest.t.sol";
 | 
			
		||||
import "../../src/IZeroExGovernor.sol";
 | 
			
		||||
import "../../src/ZeroExTimelock.sol";
 | 
			
		||||
import "../../src/ZeroExProtocolGovernor.sol";
 | 
			
		||||
import "../../src/ZRXWrappedToken.sol";
 | 
			
		||||
import "@openzeppelin/token/ERC20/ERC20.sol";
 | 
			
		||||
import "@openzeppelin/mocks/CallReceiverMock.sol";
 | 
			
		||||
 | 
			
		||||
abstract contract ZeroExGovernorBaseTest is BaseTest {
 | 
			
		||||
    IERC20 public token;
 | 
			
		||||
    ZRXWrappedToken internal wToken;
 | 
			
		||||
    ZeroExVotes internal votes;
 | 
			
		||||
    ZeroExTimelock internal timelock;
 | 
			
		||||
    IZeroExGovernor internal governor;
 | 
			
		||||
    CallReceiverMock internal callReceiverMock;
 | 
			
		||||
 | 
			
		||||
    string internal governorName;
 | 
			
		||||
    uint256 internal proposalThreshold;
 | 
			
		||||
 | 
			
		||||
    event SecurityCouncilAssigned(address securityCouncil);
 | 
			
		||||
    event SecurityCouncilEjected();
 | 
			
		||||
 | 
			
		||||
    function initialiseAccounts() public {
 | 
			
		||||
        vm.startPrank(account1);
 | 
			
		||||
        token.transfer(account2, 10000000e18);
 | 
			
		||||
        token.transfer(account3, 2000000e18);
 | 
			
		||||
        token.transfer(account4, 3000000e18);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Setup accounts 2,3 and 4 to vote
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        token.approve(address(wToken), 10000000e18);
 | 
			
		||||
        wToken.depositFor(account2, 10000000e18);
 | 
			
		||||
        wToken.delegate(account2);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        vm.startPrank(account3);
 | 
			
		||||
        token.approve(address(wToken), 2000000e18);
 | 
			
		||||
        wToken.depositFor(account3, 2000000e18);
 | 
			
		||||
        wToken.delegate(account3);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        vm.startPrank(account4);
 | 
			
		||||
        token.approve(address(wToken), 3000000e18);
 | 
			
		||||
        wToken.depositFor(account4, 3000000e18);
 | 
			
		||||
        wToken.delegate(account4);
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        callReceiverMock = new CallReceiverMock();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setSecurityCouncil(address council) internal {
 | 
			
		||||
        address[] memory targets = new address[](1);
 | 
			
		||||
        targets[0] = address(governor);
 | 
			
		||||
 | 
			
		||||
        uint256[] memory values = new uint256[](1);
 | 
			
		||||
        values[0] = 0;
 | 
			
		||||
 | 
			
		||||
        bytes[] memory calldatas = new bytes[](1);
 | 
			
		||||
        calldatas[0] = abi.encodeWithSelector(governor.assignSecurityCouncil.selector, council);
 | 
			
		||||
 | 
			
		||||
        vm.roll(2);
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        uint256 proposalId = governor.propose(targets, values, calldatas, "Assign new security council");
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Fast forward to after vote start
 | 
			
		||||
        vm.roll(governor.proposalSnapshot(proposalId) + 1);
 | 
			
		||||
 | 
			
		||||
        // Vote
 | 
			
		||||
        vm.prank(account2);
 | 
			
		||||
        governor.castVote(proposalId, 1); // Vote "for"
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Fast forward to vote end
 | 
			
		||||
        vm.roll(governor.proposalDeadline(proposalId) + 1);
 | 
			
		||||
 | 
			
		||||
        // Queue proposal
 | 
			
		||||
        governor.queue(targets, values, calldatas, keccak256(bytes("Assign new security council")));
 | 
			
		||||
        vm.warp(governor.proposalEta(proposalId) + 1);
 | 
			
		||||
 | 
			
		||||
        // Execute proposal
 | 
			
		||||
        governor.execute(targets, values, calldatas, keccak256("Assign new security council"));
 | 
			
		||||
 | 
			
		||||
        assertEq(governor.securityCouncil(), council);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldReturnCorrectName() public {
 | 
			
		||||
        assertEq(governor.name(), governorName);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldReturnCorrectVotingDelay() public {
 | 
			
		||||
        assertEq(governor.votingDelay(), 14400);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldReturnCorrectVotingPeriod() public {
 | 
			
		||||
        assertEq(governor.votingPeriod(), 50400);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldReturnCorrectProposalThreshold() public {
 | 
			
		||||
        assertEq(governor.proposalThreshold(), proposalThreshold);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldReturnCorrectToken() public {
 | 
			
		||||
        assertEq(address(governor.token()), address(votes));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldReturnCorrectTimelock() public {
 | 
			
		||||
        assertEq(address(governor.timelock()), address(timelock));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldReturnCorrectSecurityCouncil() public {
 | 
			
		||||
        assertEq(governor.securityCouncil(), securityCouncil);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testCanAssignSecurityCouncil() public {
 | 
			
		||||
        // Create a proposal
 | 
			
		||||
        address[] memory targets = new address[](1);
 | 
			
		||||
        targets[0] = address(governor);
 | 
			
		||||
 | 
			
		||||
        uint256[] memory values = new uint256[](1);
 | 
			
		||||
        values[0] = 0;
 | 
			
		||||
 | 
			
		||||
        bytes[] memory calldatas = new bytes[](1);
 | 
			
		||||
        calldatas[0] = abi.encodeWithSelector(governor.assignSecurityCouncil.selector, account1);
 | 
			
		||||
 | 
			
		||||
        vm.roll(2);
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        uint256 proposalId = governor.propose(targets, values, calldatas, "Assign new security council");
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Fast forward to after vote start
 | 
			
		||||
        vm.roll(governor.proposalSnapshot(proposalId) + 1);
 | 
			
		||||
 | 
			
		||||
        // Vote
 | 
			
		||||
        vm.prank(account2);
 | 
			
		||||
        governor.castVote(proposalId, 1); // Vote "for"
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Fast forward to vote end
 | 
			
		||||
        vm.roll(governor.proposalDeadline(proposalId) + 1);
 | 
			
		||||
 | 
			
		||||
        // Queue proposal
 | 
			
		||||
        governor.queue(targets, values, calldatas, keccak256(bytes("Assign new security council")));
 | 
			
		||||
        vm.warp(governor.proposalEta(proposalId) + 1);
 | 
			
		||||
 | 
			
		||||
        // Execute proposal
 | 
			
		||||
        vm.expectEmit(true, false, false, false);
 | 
			
		||||
        emit SecurityCouncilAssigned(account1);
 | 
			
		||||
        governor.execute(targets, values, calldatas, keccak256("Assign new security council"));
 | 
			
		||||
 | 
			
		||||
        assertEq(governor.securityCouncil(), account1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testCannotAssignSecurityCouncilOutsideOfGovernance() public {
 | 
			
		||||
        vm.expectRevert("Governor: onlyGovernance");
 | 
			
		||||
        governor.assignSecurityCouncil(account1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // This functionality is currently not enabled
 | 
			
		||||
    // Leaving this test for potential future use.
 | 
			
		||||
    function testFailSecurityCouncilAreEjectedAfterCancellingAProposal() public {
 | 
			
		||||
        // Create a proposal
 | 
			
		||||
        address[] memory targets = new address[](1);
 | 
			
		||||
        targets[0] = address(callReceiverMock);
 | 
			
		||||
 | 
			
		||||
        uint256[] memory values = new uint256[](1);
 | 
			
		||||
        values[0] = 0;
 | 
			
		||||
 | 
			
		||||
        bytes[] memory calldatas = new bytes[](1);
 | 
			
		||||
        calldatas[0] = abi.encodeWithSignature("mockFunction()");
 | 
			
		||||
 | 
			
		||||
        vm.roll(2);
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        uint256 proposalId = governor.propose(targets, values, calldatas, "Proposal description");
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Fast forward to after vote start
 | 
			
		||||
        vm.roll(governor.proposalSnapshot(proposalId) + 1);
 | 
			
		||||
 | 
			
		||||
        // Vote
 | 
			
		||||
        vm.prank(account2);
 | 
			
		||||
        governor.castVote(proposalId, 1); // Vote "for"
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Fast forward to vote end
 | 
			
		||||
        vm.roll(governor.proposalDeadline(proposalId) + 1);
 | 
			
		||||
 | 
			
		||||
        IGovernor.ProposalState state = governor.state(proposalId);
 | 
			
		||||
        assertEq(uint256(state), uint256(IGovernor.ProposalState.Succeeded));
 | 
			
		||||
 | 
			
		||||
        // Queue proposal
 | 
			
		||||
        governor.queue(targets, values, calldatas, keccak256(bytes("Proposal description")));
 | 
			
		||||
 | 
			
		||||
        // Cancel the proposal
 | 
			
		||||
        vm.warp(governor.proposalEta(proposalId));
 | 
			
		||||
 | 
			
		||||
        vm.prank(securityCouncil);
 | 
			
		||||
 | 
			
		||||
        vm.expectEmit(true, false, false, false);
 | 
			
		||||
        emit SecurityCouncilEjected();
 | 
			
		||||
        governor.cancel(targets, values, calldatas, keccak256(bytes("Proposal description")));
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        state = governor.state(proposalId);
 | 
			
		||||
        assertEq(uint256(state), uint256(IGovernor.ProposalState.Canceled));
 | 
			
		||||
 | 
			
		||||
        assertEq(governor.securityCouncil(), address(0));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testWhenNoSecurityCouncilCannottSubmitProposals() public {
 | 
			
		||||
        setSecurityCouncil(address(0));
 | 
			
		||||
 | 
			
		||||
        address[] memory targets = new address[](1);
 | 
			
		||||
        targets[0] = address(callReceiverMock);
 | 
			
		||||
 | 
			
		||||
        uint256[] memory values = new uint256[](1);
 | 
			
		||||
        values[0] = 0;
 | 
			
		||||
 | 
			
		||||
        bytes[] memory calldatas = new bytes[](1);
 | 
			
		||||
        calldatas[0] = abi.encodeWithSignature("mockFunction()");
 | 
			
		||||
 | 
			
		||||
        vm.expectRevert("SecurityCouncil: security council not assigned and this is not an assignment call");
 | 
			
		||||
        governor.propose(targets, values, calldatas, "Proposal description");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testWhenNoSecurityCouncilCannotQueueSuccessfulProposals() public {
 | 
			
		||||
        // Create a proposal
 | 
			
		||||
        address[] memory targets = new address[](1);
 | 
			
		||||
        targets[0] = address(callReceiverMock);
 | 
			
		||||
 | 
			
		||||
        uint256[] memory values = new uint256[](1);
 | 
			
		||||
        values[0] = 0;
 | 
			
		||||
 | 
			
		||||
        bytes[] memory calldatas = new bytes[](1);
 | 
			
		||||
        calldatas[0] = abi.encodeWithSignature("mockFunction()");
 | 
			
		||||
 | 
			
		||||
        vm.roll(2);
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        uint256 proposalId = governor.propose(targets, values, calldatas, "Proposal description");
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Fast forward to after vote start
 | 
			
		||||
        vm.roll(governor.proposalSnapshot(proposalId) + 1);
 | 
			
		||||
 | 
			
		||||
        // Vote
 | 
			
		||||
        vm.prank(account2);
 | 
			
		||||
        governor.castVote(proposalId, 1); // Vote "for"
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Fast forward to vote end
 | 
			
		||||
        vm.roll(governor.proposalDeadline(proposalId) + 1);
 | 
			
		||||
 | 
			
		||||
        // Set security council to address(0)
 | 
			
		||||
        setSecurityCouncil(address(0));
 | 
			
		||||
 | 
			
		||||
        vm.expectRevert("SecurityCouncil: security council not assigned and this is not an assignment call");
 | 
			
		||||
        governor.queue(targets, values, calldatas, keccak256(bytes("Proposal description")));
 | 
			
		||||
 | 
			
		||||
        IGovernor.ProposalState state = governor.state(proposalId);
 | 
			
		||||
        assertEq(uint256(state), uint256(IGovernor.ProposalState.Succeeded));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testWhenNoSecurityCouncilCanPassProposalToAssignSecurityCouncil() public {
 | 
			
		||||
        setSecurityCouncil(address(0));
 | 
			
		||||
 | 
			
		||||
        setSecurityCouncil(account1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testCannotPassABadProposalToSetSecurityCouncil() public {
 | 
			
		||||
        setSecurityCouncil(address(0));
 | 
			
		||||
 | 
			
		||||
        address[] memory targets = new address[](2);
 | 
			
		||||
        targets[0] = address(governor);
 | 
			
		||||
        targets[1] = address(callReceiverMock);
 | 
			
		||||
 | 
			
		||||
        uint256[] memory values = new uint256[](2);
 | 
			
		||||
        values[0] = 0;
 | 
			
		||||
        values[1] = 0;
 | 
			
		||||
 | 
			
		||||
        bytes[] memory calldatas = new bytes[](2);
 | 
			
		||||
        calldatas[0] = abi.encodeWithSelector(governor.assignSecurityCouncil.selector, account1);
 | 
			
		||||
        calldatas[1] = abi.encodeWithSignature("mockFunction()");
 | 
			
		||||
 | 
			
		||||
        vm.roll(2);
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        vm.expectRevert("SecurityCouncil: more than 1 transaction in proposal");
 | 
			
		||||
        governor.propose(targets, values, calldatas, "Assign new security council");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testCanUpdateVotingDelaySetting() public {
 | 
			
		||||
        // Create a proposal
 | 
			
		||||
        address[] memory targets = new address[](1);
 | 
			
		||||
        targets[0] = address(governor);
 | 
			
		||||
 | 
			
		||||
        uint256[] memory values = new uint256[](1);
 | 
			
		||||
        values[0] = 0;
 | 
			
		||||
 | 
			
		||||
        bytes[] memory calldatas = new bytes[](1);
 | 
			
		||||
        calldatas[0] = abi.encodeWithSelector(governor.setVotingDelay.selector, 3 days);
 | 
			
		||||
 | 
			
		||||
        vm.roll(2);
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        uint256 proposalId = governor.propose(targets, values, calldatas, "Increase voting delay to 3 days");
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Fast forward to after vote start
 | 
			
		||||
        vm.roll(governor.proposalSnapshot(proposalId) + 1);
 | 
			
		||||
 | 
			
		||||
        // Vote
 | 
			
		||||
        vm.prank(account2);
 | 
			
		||||
        governor.castVote(proposalId, 1); // Vote "for"
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Fast forward to vote end
 | 
			
		||||
        vm.roll(governor.proposalDeadline(proposalId) + 1);
 | 
			
		||||
 | 
			
		||||
        // Queue proposal
 | 
			
		||||
        governor.queue(targets, values, calldatas, keccak256(bytes("Increase voting delay to 3 days")));
 | 
			
		||||
        vm.warp(governor.proposalEta(proposalId) + 1);
 | 
			
		||||
        // Execute proposal
 | 
			
		||||
        governor.execute(targets, values, calldatas, keccak256("Increase voting delay to 3 days"));
 | 
			
		||||
 | 
			
		||||
        assertEq(governor.votingDelay(), 3 days);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testCanUpdateVotingPeriodSetting() public {
 | 
			
		||||
        // Create a proposal
 | 
			
		||||
        address[] memory targets = new address[](1);
 | 
			
		||||
        targets[0] = address(governor);
 | 
			
		||||
 | 
			
		||||
        uint256[] memory values = new uint256[](1);
 | 
			
		||||
        values[0] = 0;
 | 
			
		||||
 | 
			
		||||
        bytes[] memory calldatas = new bytes[](1);
 | 
			
		||||
        calldatas[0] = abi.encodeWithSelector(governor.setVotingPeriod.selector, 14 days);
 | 
			
		||||
 | 
			
		||||
        vm.roll(2);
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        uint256 proposalId = governor.propose(targets, values, calldatas, "Increase voting period to 14 days");
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Fast forward to after vote start
 | 
			
		||||
        vm.roll(governor.proposalSnapshot(proposalId) + 1);
 | 
			
		||||
 | 
			
		||||
        // Vote
 | 
			
		||||
        vm.prank(account2);
 | 
			
		||||
        governor.castVote(proposalId, 1); // Vote "for"
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Fast forward to vote end
 | 
			
		||||
        vm.roll(governor.proposalDeadline(proposalId) + 1);
 | 
			
		||||
 | 
			
		||||
        // Queue proposal
 | 
			
		||||
        governor.queue(targets, values, calldatas, keccak256(bytes("Increase voting period to 14 days")));
 | 
			
		||||
        vm.warp(governor.proposalEta(proposalId) + 1);
 | 
			
		||||
        // Execute proposal
 | 
			
		||||
        governor.execute(targets, values, calldatas, keccak256("Increase voting period to 14 days"));
 | 
			
		||||
 | 
			
		||||
        assertEq(governor.votingPeriod(), 14 days);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testCanUpdateProposalThresholdSetting() public {
 | 
			
		||||
        // Create a proposal
 | 
			
		||||
        address[] memory targets = new address[](1);
 | 
			
		||||
        targets[0] = address(governor);
 | 
			
		||||
 | 
			
		||||
        uint256[] memory values = new uint256[](1);
 | 
			
		||||
        values[0] = 0;
 | 
			
		||||
 | 
			
		||||
        bytes[] memory calldatas = new bytes[](1);
 | 
			
		||||
        calldatas[0] = abi.encodeWithSelector(governor.setProposalThreshold.selector, 2000000e18);
 | 
			
		||||
 | 
			
		||||
        vm.roll(2);
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        uint256 proposalId = governor.propose(targets, values, calldatas, "Increase proposal threshold to 2000000e18");
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Fast forward to after vote start
 | 
			
		||||
        vm.roll(governor.proposalSnapshot(proposalId) + 1);
 | 
			
		||||
 | 
			
		||||
        // Vote
 | 
			
		||||
        vm.prank(account2);
 | 
			
		||||
        governor.castVote(proposalId, 1); // Vote "for"
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Fast forward to vote end
 | 
			
		||||
        vm.roll(governor.proposalDeadline(proposalId) + 1);
 | 
			
		||||
 | 
			
		||||
        // Queue proposal
 | 
			
		||||
        governor.queue(targets, values, calldatas, keccak256(bytes("Increase proposal threshold to 2000000e18")));
 | 
			
		||||
        vm.warp(governor.proposalEta(proposalId) + 1);
 | 
			
		||||
        // Execute proposal
 | 
			
		||||
        governor.execute(targets, values, calldatas, keccak256("Increase proposal threshold to 2000000e18"));
 | 
			
		||||
 | 
			
		||||
        assertEq(governor.proposalThreshold(), 2000000e18);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testCanUpdateTimelockDelay() public {
 | 
			
		||||
        // Create a proposal
 | 
			
		||||
        address[] memory targets = new address[](1);
 | 
			
		||||
        targets[0] = address(timelock);
 | 
			
		||||
 | 
			
		||||
        uint256[] memory values = new uint256[](1);
 | 
			
		||||
        values[0] = 0;
 | 
			
		||||
 | 
			
		||||
        bytes[] memory calldatas = new bytes[](1);
 | 
			
		||||
        calldatas[0] = abi.encodeWithSelector(timelock.updateDelay.selector, 7 days);
 | 
			
		||||
 | 
			
		||||
        vm.roll(2);
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        uint256 proposalId = governor.propose(targets, values, calldatas, "Increase timelock delay to 7 days");
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Fast forward to after vote start
 | 
			
		||||
        vm.roll(governor.proposalSnapshot(proposalId) + 1);
 | 
			
		||||
 | 
			
		||||
        // Vote
 | 
			
		||||
        vm.prank(account2);
 | 
			
		||||
        governor.castVote(proposalId, 1); // Vote "for"
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Fast forward to vote end
 | 
			
		||||
        vm.roll(governor.proposalDeadline(proposalId) + 1);
 | 
			
		||||
 | 
			
		||||
        // Queue proposal
 | 
			
		||||
        governor.queue(targets, values, calldatas, keccak256(bytes("Increase timelock delay to 7 days")));
 | 
			
		||||
        vm.warp(governor.proposalEta(proposalId) + 1);
 | 
			
		||||
        // Execute proposal
 | 
			
		||||
        governor.execute(targets, values, calldatas, keccak256("Increase timelock delay to 7 days"));
 | 
			
		||||
 | 
			
		||||
        assertEq(timelock.getMinDelay(), 7 days);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testSupportsGovernanceInterfaces() public {
 | 
			
		||||
        assertTrue(governor.supportsInterface(type(IGovernorTimelock).interfaceId));
 | 
			
		||||
        assertTrue(governor.supportsInterface(type(IGovernor).interfaceId));
 | 
			
		||||
        assertTrue(governor.supportsInterface(type(IERC1155Receiver).interfaceId));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										169
									
								
								contracts/governance/test/unit/ZeroExProtocolGovernor.t.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								contracts/governance/test/unit/ZeroExProtocolGovernor.t.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,169 @@
 | 
			
		||||
// SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2023 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.8.19;
 | 
			
		||||
 | 
			
		||||
import "./ZeroExGovernorBaseTest.t.sol";
 | 
			
		||||
import "../mocks/ZeroExMock.sol";
 | 
			
		||||
import "../../src/ZeroExProtocolGovernor.sol";
 | 
			
		||||
 | 
			
		||||
contract ZeroExProtocolGovernorTest is ZeroExGovernorBaseTest {
 | 
			
		||||
    ZeroExProtocolGovernor internal protocolGovernor;
 | 
			
		||||
    ZeroExMock internal zeroExMock;
 | 
			
		||||
    uint256 internal quorum;
 | 
			
		||||
 | 
			
		||||
    event CallExecuted(bytes32 indexed id, uint256 indexed index, address target, uint256 value, bytes data);
 | 
			
		||||
 | 
			
		||||
    function setUp() public {
 | 
			
		||||
        governorName = "ZeroExProtocolGovernor";
 | 
			
		||||
        proposalThreshold = 1000000e18;
 | 
			
		||||
        quorum = 10000000e18;
 | 
			
		||||
 | 
			
		||||
        address governorAddress;
 | 
			
		||||
 | 
			
		||||
        token = mockZRXToken();
 | 
			
		||||
        (wToken, votes, timelock, , governorAddress, ) = setupGovernance(token);
 | 
			
		||||
        governor = IZeroExGovernor(governorAddress);
 | 
			
		||||
        protocolGovernor = ZeroExProtocolGovernor(payable(governorAddress));
 | 
			
		||||
        zeroExMock = new ZeroExMock();
 | 
			
		||||
        initialiseAccounts();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldReturnCorrectQuorum() public {
 | 
			
		||||
        assertEq(governor.quorum(block.number), quorum);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testShouldBeAbleToExecuteASuccessfulProposal() public {
 | 
			
		||||
        // Create a proposal
 | 
			
		||||
        address[] memory targets = new address[](1);
 | 
			
		||||
        targets[0] = address(callReceiverMock);
 | 
			
		||||
 | 
			
		||||
        uint256[] memory values = new uint256[](1);
 | 
			
		||||
        values[0] = 0;
 | 
			
		||||
 | 
			
		||||
        bytes[] memory calldatas = new bytes[](1);
 | 
			
		||||
        calldatas[0] = abi.encodeWithSignature("mockFunction()");
 | 
			
		||||
 | 
			
		||||
        vm.roll(2);
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        uint256 proposalId = governor.propose(targets, values, calldatas, "Proposal description");
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Fast forward to after vote start
 | 
			
		||||
        vm.roll(governor.proposalSnapshot(proposalId) + 1);
 | 
			
		||||
 | 
			
		||||
        // Vote
 | 
			
		||||
        vm.prank(account2);
 | 
			
		||||
        governor.castVote(proposalId, 1); // Vote "for"
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
        vm.prank(account3);
 | 
			
		||||
        governor.castVote(proposalId, 0); // Vote "against"
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
        vm.prank(account4);
 | 
			
		||||
        governor.castVote(proposalId, 2); // Vote "abstain"
 | 
			
		||||
        vm.stopPrank();
 | 
			
		||||
 | 
			
		||||
        // Fast forward to vote end
 | 
			
		||||
        vm.roll(governor.proposalDeadline(proposalId) + 1);
 | 
			
		||||
 | 
			
		||||
        // Get vote results
 | 
			
		||||
        (uint256 votesAgainst, uint256 votesFor, uint256 votesAbstain) = governor.proposalVotes(proposalId);
 | 
			
		||||
        assertEq(votesFor, 10000000e18);
 | 
			
		||||
        assertEq(votesAgainst, 2000000e18);
 | 
			
		||||
        assertEq(votesAbstain, 3000000e18);
 | 
			
		||||
 | 
			
		||||
        IGovernor.ProposalState state = governor.state(proposalId);
 | 
			
		||||
        assertEq(uint256(state), uint256(IGovernor.ProposalState.Succeeded));
 | 
			
		||||
 | 
			
		||||
        // Queue proposal
 | 
			
		||||
        governor.queue(targets, values, calldatas, keccak256(bytes("Proposal description")));
 | 
			
		||||
        vm.warp(governor.proposalEta(proposalId) + 1);
 | 
			
		||||
 | 
			
		||||
        governor.execute(targets, values, calldatas, keccak256("Proposal description"));
 | 
			
		||||
        state = governor.state(proposalId);
 | 
			
		||||
        assertEq(uint256(state), uint256(IGovernor.ProposalState.Executed));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testSecurityCouncilShouldBeAbleToExecuteRollback() public {
 | 
			
		||||
        // Create a proposal
 | 
			
		||||
        address[] memory targets = new address[](1);
 | 
			
		||||
        targets[0] = address(zeroExMock);
 | 
			
		||||
 | 
			
		||||
        uint256[] memory values = new uint256[](1);
 | 
			
		||||
        values[0] = 0;
 | 
			
		||||
 | 
			
		||||
        bytes[] memory calldatas = new bytes[](1);
 | 
			
		||||
        bytes4 testFunctionSig = 0xc853c969;
 | 
			
		||||
        address testFunctionImpl = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f;
 | 
			
		||||
        calldatas[0] = abi.encodeWithSignature("rollback(bytes4,address)", testFunctionSig, testFunctionImpl);
 | 
			
		||||
 | 
			
		||||
        // Security council adds the batch of rollbacks to the queue
 | 
			
		||||
        vm.startPrank(securityCouncil);
 | 
			
		||||
 | 
			
		||||
        bytes32 proposalId = timelock.hashOperationBatch(
 | 
			
		||||
            targets,
 | 
			
		||||
            values,
 | 
			
		||||
            calldatas,
 | 
			
		||||
            0,
 | 
			
		||||
            keccak256(bytes("Emergency rollback"))
 | 
			
		||||
        );
 | 
			
		||||
        vm.expectEmit(true, true, true, true);
 | 
			
		||||
        emit CallExecuted(proposalId, 0, targets[0], values[0], calldatas[0]);
 | 
			
		||||
 | 
			
		||||
        // This functionality is currently not enabled
 | 
			
		||||
        // Leaving this test for potential future use.
 | 
			
		||||
        // vm.expectEmit(true, false, false, false);
 | 
			
		||||
        // emit SecurityCouncilEjected();
 | 
			
		||||
 | 
			
		||||
        protocolGovernor.executeRollback(targets, values, calldatas, keccak256(bytes("Emergency rollback")));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testSecurityCouncilShouldNotBeAbleToExecuteArbitraryFunctions() public {
 | 
			
		||||
        // Create a proposal
 | 
			
		||||
        address[] memory targets = new address[](1);
 | 
			
		||||
        targets[0] = address(callReceiverMock);
 | 
			
		||||
 | 
			
		||||
        uint256[] memory values = new uint256[](1);
 | 
			
		||||
        values[0] = 0;
 | 
			
		||||
 | 
			
		||||
        bytes[] memory calldatas = new bytes[](1);
 | 
			
		||||
        calldatas[0] = abi.encodeWithSignature("mockFunction()");
 | 
			
		||||
 | 
			
		||||
        vm.startPrank(securityCouncil);
 | 
			
		||||
        vm.expectRevert("ZeroExTimelock: not rollback");
 | 
			
		||||
        protocolGovernor.executeRollback(targets, values, calldatas, keccak256(bytes("Proposal description")));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testRollbackShouldNotBeExecutableByNonSecurityCouncilAccounts() public {
 | 
			
		||||
        // Create a proposal
 | 
			
		||||
        address[] memory targets = new address[](1);
 | 
			
		||||
        targets[0] = address(zeroExMock);
 | 
			
		||||
 | 
			
		||||
        uint256[] memory values = new uint256[](1);
 | 
			
		||||
        values[0] = 0;
 | 
			
		||||
 | 
			
		||||
        bytes[] memory calldatas = new bytes[](1);
 | 
			
		||||
        bytes4 testFunctionSig = 0xc853c969;
 | 
			
		||||
        address testFunctionImpl = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f;
 | 
			
		||||
        calldatas[0] = abi.encodeWithSignature("rollback(bytes4,address)", testFunctionSig, testFunctionImpl);
 | 
			
		||||
 | 
			
		||||
        vm.startPrank(account2);
 | 
			
		||||
        vm.expectRevert("SecurityCouncil: only security council allowed");
 | 
			
		||||
        protocolGovernor.executeRollback(targets, values, calldatas, keccak256(bytes("Emergency rollback")));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user