Compare commits
	
		
			5 Commits
		
	
	
		
			@0x/protoc
			...
			@0x/contra
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					2a6d66cc2a | ||
| 
						 | 
					b02992a373 | ||
| 
						 | 
					92ad924965 | ||
| 
						 | 
					138383e95c | ||
| 
						 | 
					0487cb7d39 | 
@@ -1,204 +1,93 @@
 | 
			
		||||
version: 2.1
 | 
			
		||||
 | 
			
		||||
parameters:
 | 
			
		||||
    cache_version:
 | 
			
		||||
        type: string
 | 
			
		||||
        default: v5
 | 
			
		||||
version: 2
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
    build:
 | 
			
		||||
        resource_class: xlarge
 | 
			
		||||
        resource_class: medium+
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs10
 | 
			
		||||
        environment:
 | 
			
		||||
            NODE_OPTIONS: '--max-old-space-size=16384'
 | 
			
		||||
            CONTRACTS_COMMIT_HASH: '9ed05f5'
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        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
 | 
			
		||||
                  command: npm install --force --global yarn@1.17.0
 | 
			
		||||
            - run:
 | 
			
		||||
                  name: yarn
 | 
			
		||||
                  command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install
 | 
			
		||||
            - setup_remote_docker
 | 
			
		||||
            - run: yarn build:ci
 | 
			
		||||
            - run: yarn build:ts
 | 
			
		||||
            - save_cache:
 | 
			
		||||
                  key: cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
                  key: repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
                  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
 | 
			
		||||
                      - ~/repo
 | 
			
		||||
            - 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
 | 
			
		||||
        resource_class: medium+
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs10
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        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
 | 
			
		||||
                      - repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - run: yarn wsrun test:circleci @0x/contracts-exchange
 | 
			
		||||
    test-integrations-ganache:
 | 
			
		||||
        resource_class: xlarge
 | 
			
		||||
        resource_class: medium+
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs10
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        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
 | 
			
		||||
                      - repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - run: yarn wsrun test:circleci @0x/contracts-integrations
 | 
			
		||||
    test-contracts-staking-ganache:
 | 
			
		||||
        resource_class: xlarge
 | 
			
		||||
        resource_class: medium+
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs10
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        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
 | 
			
		||||
                      - repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - run: yarn wsrun test:circleci @0x/contracts-staking
 | 
			
		||||
    test-contracts-extra-ganache:
 | 
			
		||||
        resource_class: xlarge
 | 
			
		||||
        resource_class: medium+
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs10
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        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
 | 
			
		||||
                      - repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - run: yarn wsrun test:circleci @0x/contracts-exchange-forwarder @0x/contracts-coordinator
 | 
			
		||||
    test-contracts-rest-ganache:
 | 
			
		||||
        resource_class: xlarge
 | 
			
		||||
        resource_class: medium+
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs10
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        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
 | 
			
		||||
                      - repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-asset-proxy @0x/contracts-broker @0x/contracts-zero-ex
 | 
			
		||||
    test-publish:
 | 
			
		||||
        resource_class: large
 | 
			
		||||
        environment:
 | 
			
		||||
            NODE_OPTIONS: '--max-old-space-size=6442'
 | 
			
		||||
        resource_class: medium+
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs10
 | 
			
		||||
            - image: 0xorg/verdaccio
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        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 >>
 | 
			
		||||
                      - repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - run:
 | 
			
		||||
                  command: yarn test:publish:circleci
 | 
			
		||||
                  no_output_timeout: 1800
 | 
			
		||||
@@ -206,87 +95,71 @@ jobs:
 | 
			
		||||
                  path: ~/.npm/_logs
 | 
			
		||||
    test-doc-generation:
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs10
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        steps:
 | 
			
		||||
            - checkout
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
                      - repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - run:
 | 
			
		||||
                  command: yarn test:generate_docs:circleci
 | 
			
		||||
                  no_output_timeout: 1200
 | 
			
		||||
    test-rest:
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
        environment:
 | 
			
		||||
            RUST_ROUTER: 'true'
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs10
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        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
 | 
			
		||||
                      - repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - run: yarn wsrun test:circleci @0x/contracts-test-utils
 | 
			
		||||
            - run: yarn wsrun test:circleci @0x/contract-artifacts
 | 
			
		||||
            - run: yarn wsrun test:circleci @0x/contract-wrappers-test
 | 
			
		||||
            - run: yarn wsrun test:circleci @0x/migrations
 | 
			
		||||
            - run: yarn wsrun test:circleci @0x/order-utils
 | 
			
		||||
            - run: yarn wsrun test:circleci @0x/asset-swapper
 | 
			
		||||
            - save_cache:
 | 
			
		||||
                  key: coverage-contract-wrappers-test-{{ checksum "yarn.lock" }}
 | 
			
		||||
                  key: coverage-contract-wrappers-test-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
                  paths:
 | 
			
		||||
                      - ~/repo/packages/contract-wrappers-test/coverage/lcov.info
 | 
			
		||||
            - save_cache:
 | 
			
		||||
                  key: coverage-order-utils-{{ checksum "yarn.lock" }}
 | 
			
		||||
                  key: coverage-order-utils-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
                  paths:
 | 
			
		||||
                      - ~/repo/packages/order-utils/coverage/lcov.info
 | 
			
		||||
            - save_cache:
 | 
			
		||||
                  key: coverage-web3-wrapper-{{ checksum "yarn.lock" }}
 | 
			
		||||
                  key: coverage-web3-wrapper-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
                  paths:
 | 
			
		||||
                      - ~/repo/packages/web3-wrapper/coverage/lcov.info
 | 
			
		||||
    static-tests:
 | 
			
		||||
        resource_class: large
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs10
 | 
			
		||||
        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
 | 
			
		||||
                      - repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - run: yarn lerna run lint
 | 
			
		||||
            - run: yarn prettier:ci
 | 
			
		||||
            - run: yarn deps_versions:ci
 | 
			
		||||
            - run: yarn diff_md_docs:ci
 | 
			
		||||
    submit-coverage:
 | 
			
		||||
        docker:
 | 
			
		||||
            - image: node:16
 | 
			
		||||
            - image: nikolaik/python-nodejs:python3.7-nodejs10
 | 
			
		||||
        working_directory: ~/repo
 | 
			
		||||
        steps:
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - cache-{{ checksum "yarn.lock" }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
                      - repo-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - lib-{{ .Environment.CIRCLE_SHA1 }}-<< pipeline.parameters.cache_version >>
 | 
			
		||||
                      - coverage-contract-wrappers-test-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - coverage-contract-wrappers-test-{{ checksum "yarn.lock" }}
 | 
			
		||||
                      - coverage-order-utils-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - coverage-order-utils-{{ checksum "yarn.lock" }}
 | 
			
		||||
            - restore_cache:
 | 
			
		||||
                  keys:
 | 
			
		||||
                      - coverage-contracts-{{ checksum "yarn.lock" }}
 | 
			
		||||
                      - coverage-contracts-{{ .Environment.CIRCLE_SHA1 }}
 | 
			
		||||
            - run: yarn report_coverage
 | 
			
		||||
workflows:
 | 
			
		||||
    version: 2
 | 
			
		||||
@@ -306,9 +179,6 @@ workflows:
 | 
			
		||||
            # - test-contracts-extra-ganache:
 | 
			
		||||
            #       requires:
 | 
			
		||||
            #           - build
 | 
			
		||||
            - test-foundry:
 | 
			
		||||
                  requires:
 | 
			
		||||
                      - build
 | 
			
		||||
            - test-contracts-rest-ganache:
 | 
			
		||||
                  requires:
 | 
			
		||||
                      - build
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								.github/autolabeler.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/autolabeler.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,6 +1,7 @@
 | 
			
		||||
python: ['python-packages']
 | 
			
		||||
contracts: ['contracts']
 | 
			
		||||
@0x/contract-addresses: ['packages/contract-addresses']
 | 
			
		||||
@0x/migrations: ['packages/migrations']
 | 
			
		||||
@0x/order-utils: ['packages/order-utils']
 | 
			
		||||
@0x/contract-artifacts: ['packages/contract-artifacts']
 | 
			
		||||
@0x/contract-wrappers: ['packages/contract-wrappers']
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								.github/workflows/publish.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/publish.yml
									
									
									
									
										vendored
									
									
								
							@@ -28,7 +28,7 @@ jobs:
 | 
			
		||||
                fetch-depth: 0
 | 
			
		||||
            - uses: actions/setup-node@v1
 | 
			
		||||
              with:
 | 
			
		||||
                node-version: 16
 | 
			
		||||
                node-version: 10
 | 
			
		||||
            - uses: actions/setup-python@v2
 | 
			
		||||
            - name: 'configure git'
 | 
			
		||||
              run: |
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -75,9 +75,8 @@ generated_docs/
 | 
			
		||||
 | 
			
		||||
TODO.md
 | 
			
		||||
 | 
			
		||||
# IDE file
 | 
			
		||||
# VSCode file
 | 
			
		||||
.vscode
 | 
			
		||||
.idea
 | 
			
		||||
 | 
			
		||||
# generated contract artifacts/
 | 
			
		||||
contracts/broker/generated-artifacts/
 | 
			
		||||
@@ -173,15 +172,6 @@ contracts/zero-ex/test/generated-wrappers/
 | 
			
		||||
contracts/treasury/generated-wrappers/
 | 
			
		||||
contracts/treasury/test/generated-wrappers/
 | 
			
		||||
 | 
			
		||||
# foundry artifacts
 | 
			
		||||
contracts/zero-ex/foundry-artifacts/
 | 
			
		||||
 | 
			
		||||
# foundry cache 
 | 
			
		||||
contracts/zero-ex/foundry-cache/
 | 
			
		||||
 | 
			
		||||
# typechain wrappers
 | 
			
		||||
contracts/zero-ex/typechain-wrappers/
 | 
			
		||||
 | 
			
		||||
# Doc README copy
 | 
			
		||||
packages/*/docs/README.md
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +0,0 @@
 | 
			
		||||
[submodule "contracts/zero-ex/contracts/deps/forge-std"]
 | 
			
		||||
	path = contracts/zero-ex/contracts/deps/forge-std
 | 
			
		||||
	url = https://github.com/foundry-rs/forge-std
 | 
			
		||||
@@ -60,7 +60,6 @@ lib
 | 
			
		||||
/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
 | 
			
		||||
@@ -81,8 +80,11 @@ lib
 | 
			
		||||
/contracts/erc1155/build/
 | 
			
		||||
/contracts/extensions/build/
 | 
			
		||||
/contracts/exchange-forwarder/build/
 | 
			
		||||
/packages/asset-swapper/
 | 
			
		||||
/packages/contract-wrappers/src/generated-wrappers/
 | 
			
		||||
/packages/asset-swapper/generated-artifacts
 | 
			
		||||
/packages/asset-swapper/generated-wrappers
 | 
			
		||||
/packages/asset-swapper/test/generated-artifacts
 | 
			
		||||
/packages/asset-swapper/test/generated-wrappers
 | 
			
		||||
package.json
 | 
			
		||||
packages/*/docs
 | 
			
		||||
docs/
 | 
			
		||||
*.sol
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								.prettierrc
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								.prettierrc
									
									
									
									
									
								
							@@ -3,18 +3,5 @@
 | 
			
		||||
    "tabWidth": 4,
 | 
			
		||||
    "singleQuote": true,
 | 
			
		||||
    "trailingComma": "all",
 | 
			
		||||
    "bracketSpacing": true,
 | 
			
		||||
    "arrowParens": "avoid",
 | 
			
		||||
    "overrides": [
 | 
			
		||||
        {
 | 
			
		||||
          "files": "**/*.sol",
 | 
			
		||||
          "options": {
 | 
			
		||||
            "printWidth": 120,
 | 
			
		||||
            "tabWidth": 4,
 | 
			
		||||
            "useTabs": false,
 | 
			
		||||
            "singleQuote": false,
 | 
			
		||||
            "bracketSpacing": false
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      ]
 | 
			
		||||
    "bracketSpacing": true
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								CODEOWNERS
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								CODEOWNERS
									
									
									
									
									
								
							@@ -1,20 +1,18 @@
 | 
			
		||||
# See https://help.github.com/articles/about-codeowners/
 | 
			
		||||
 | 
			
		||||
# for more info about CODEOWNERS file
 | 
			
		||||
 | 
			
		||||
# It uses the same pattern rule for gitignore file
 | 
			
		||||
 | 
			
		||||
# https://git-scm.com/docs/gitignore#_pattern_format
 | 
			
		||||
 | 
			
		||||
packages/asset-swapper/ @dekz @dextracker @kyu-c
 | 
			
		||||
# Website
 | 
			
		||||
packages/asset-swapper/  @BMillman19 @fragosti @dave4506
 | 
			
		||||
packages/instant/  @BMillman19 @fragosti @dave4506
 | 
			
		||||
 | 
			
		||||
# Dev tools & setup
 | 
			
		||||
 | 
			
		||||
.circleci/ @dekz
 | 
			
		||||
packages/contract-addresses/ @dekz @dextracker @kyu-c
 | 
			
		||||
packages/contract-artifacts/ @dekz
 | 
			
		||||
packages/protocol-utils/ @dekz
 | 
			
		||||
.circleci/ @dorothy-zbornak
 | 
			
		||||
packages/contract-addresses/ @abandeali1
 | 
			
		||||
packages/contract-artifacts/ @abandeali1
 | 
			
		||||
packages/order-utils/ @dorothy-zbornak 
 | 
			
		||||
 | 
			
		||||
# Protocol/smart contracts
 | 
			
		||||
 | 
			
		||||
contracts/ @dekz @dextracker
 | 
			
		||||
contracts/ @abandeali1 @hysz @dorothy-zbornak @mzhu25
 | 
			
		||||
 
 | 
			
		||||
@@ -49,6 +49,7 @@
 | 
			
		||||
| Package | Version |
 | 
			
		||||
| ------: | :------ |
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<!-- For example:
 | 
			
		||||
|             `0x.js` | 2.0.4   |
 | 
			
		||||
| `Exchange Contract` | v2      |
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										41
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								README.md
									
									
									
									
									
								
							@@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
[0x][website-url] is an open protocol that facilitates trustless, low friction exchange of Ethereum-based assets. For more information on how it works, check out the [0x protocol specification](https://protocol.0x.org/).
 | 
			
		||||
[0x][website-url] is an open protocol that facilitates trustless, low friction exchange of Ethereum-based assets. For more information on how it works, check out the [0x protocol specification](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md).
 | 
			
		||||
 | 
			
		||||
This repository is a monorepo including the 0x protocol smart contracts and numerous developer tools. Each public sub-package is independently published to NPM.
 | 
			
		||||
 | 
			
		||||
@@ -15,18 +15,28 @@ This repository is a monorepo including the 0x protocol smart contracts and nume
 | 
			
		||||
 | 
			
		||||
## Packages
 | 
			
		||||
 | 
			
		||||
Visit our [developer portal](https://0x.org/docs/) for a comprehensive list of core & community maintained packages. All packages maintained with this monorepo are listed below.
 | 
			
		||||
Visit our [developer portal](https://0x.org/docs/tools/order-utils) for a comprehensive list of core & community maintained packages. All packages maintained with this monorepo are listed below.
 | 
			
		||||
 | 
			
		||||
### Solidity Packages
 | 
			
		||||
 | 
			
		||||
These packages are all under development. See [/contracts/README.md](/contracts/README.md) for a list of deployed packages.
 | 
			
		||||
 | 
			
		||||
| Package                                             | Version                                                                                                                     | Description                                                          |
 | 
			
		||||
| --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
 | 
			
		||||
| [`@0x/contracts-zero-ex`](/contracts/zero-ex)       | [](https://www.npmjs.com/package/@0x/contracts-zero-ex)       | The contracts used for settling trades within the protocol           |
 | 
			
		||||
| [`@0x/contracts-erc20`](/contracts/erc20)           | [](https://www.npmjs.com/package/@0x/contracts-erc20)           | Implementations of various ERC20 tokens                              |
 | 
			
		||||
| [`@0x/contracts-test-utils`](/contracts/test-utils) | [](https://www.npmjs.com/package/@0x/contracts-test-utils) | TypeScript/Javascript shared utilities used for testing contracts    |
 | 
			
		||||
| [`@0x/contracts-utils`](/contracts/utils)           | [](https://www.npmjs.com/package/@0x/contracts-utils)           | Generic libraries and utilities used throughout all of the contracts |
 | 
			
		||||
| Package                                                             | Version                                                                                                                                     | Description                                                                                                                                                                                                                                           |
 | 
			
		||||
| ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
 | 
			
		||||
| [`@0x/contracts-asset-proxy`](/contracts/asset-proxy)               | [](https://www.npmjs.com/package/@0x/contracts-asset-proxy)               | [`AssetProxy`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxy) contracts used within the protocol                                                                                               |
 | 
			
		||||
| [`@0x/contracts-erc20`](/contracts/erc20)                           | [](https://www.npmjs.com/package/@0x/contracts-erc20)                           | Implementations of various ERC20 tokens                                                                                                                                                                                                               |
 | 
			
		||||
| [`@0x/contracts-erc721`](/contracts/erc721)                         | [](https://www.npmjs.com/package/@0x/contracts-erc721)                         | Implementations of various ERC721 tokens                                                                                                                                                                                                              |
 | 
			
		||||
| [`@0x/contracts-erc1155`](/contracts/erc1155)                       | [](https://www.npmjs.com/package/@0x/contracts-erc1155)                       | Implementations of various ERC1155 tokens                                                                                                                                                                                                             |
 | 
			
		||||
| [`@0x/contracts-exchange`](/contracts/exchange)                     | [](https://www.npmjs.com/package/@0x/contracts-exchange)                     | The [`Exchange`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#exchange) contract used for settling trades within the protocol                                                                            |
 | 
			
		||||
| [`@0x/contracts-exchange-forwarder`](/contracts/exchange-forwarder) | [](https://www.npmjs.com/package/@0x/contracts-exchange-forwarder) | A [`Forwarder`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/forwarder-specification.md) contract used to simplify UX for interacting with the protocol                                                                      |
 | 
			
		||||
| [`@0x/contracts-exchange-libs`](/contracts/exchange-libs)           | [](https://www.npmjs.com/package/@0x/contracts-exchange-libs)           | Protocol specific libraries used within the [`Exchange`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#exchange) contract                                                                                 |
 | 
			
		||||
| [`@0x/contracts-extensions`](/contracts/extensions)                 | [](https://www.npmjs.com/package/@0x/contracts-extensions)                 | Contracts that interact with and extend the functionality of the core protocol                                                                                                                                                                        |
 | 
			
		||||
| [`@0x/contracts-multisig`](/contracts/multisig)                     | [](https://www.npmjs.com/package/@0x/contracts-multisig)                     | Various implementations of multisignature wallets, including the [`AssetProxyOwner`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxyowner) contract that has permissions to upgrade the protocol |
 | 
			
		||||
| [`@0x/contracts-test-utils`](/contracts/test-utils)                 | [](https://www.npmjs.com/package/@0x/contracts-test-utils)                 | TypeScript/Javascript shared utilities used for testing contracts                                                                                                                                                                                     |
 | 
			
		||||
| [`@0x/contracts-utils`](/contracts/utils)                           | [](https://www.npmjs.com/package/@0x/contracts-utils)                           | Generic libraries and utilities used throughout all of the contracts                                                                                                                                                                                  |
 | 
			
		||||
| [`@0x/contracts-coordinator`](/contracts/coordinator)               | [](https://www.npmjs.com/package/@0x/contracts-coordinator)               | A contract that allows users to execute 0x transactions with permission from a Coordinator                                                                                                                                                            |
 | 
			
		||||
| [`@0x/contracts-dev-utils`](/contracts/dev-utils)                   | [](https://www.npmjs.com/package/@0x/contracts-dev-utils)                   | A contract contains utility functions for developers (such as validating many orders using a single eth_call)                                                                                                                                         |
 | 
			
		||||
| [`@0x/contracts-staking`](/contracts/staking)                       | [](https://www.npmjs.com/package/@0x/contracts-staking)                       | Implements the stake-based liquidity incentives defined by [`ZEIP-31`](https://github.com/0xProject/ZEIPs/issues/31)                                                                                                                                  |
 | 
			
		||||
 | 
			
		||||
### TypeScript/Javascript Packages
 | 
			
		||||
 | 
			
		||||
@@ -34,9 +44,10 @@ These packages are all under development. See [/contracts/README.md](/contracts/
 | 
			
		||||
 | 
			
		||||
| Package                                                  | Version                                                                                                                 | Description                                                                                    |
 | 
			
		||||
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
 | 
			
		||||
| [`@0x/protocol-utils`](/packages/protocol-utils)         | [](https://www.npmjs.com/package/@0x/protocol-utils)         | A set of utilities for generating, parsing, signing and validating 0x orders                   |
 | 
			
		||||
| [`@0x/contract-addresses`](/packages/contract-addresses) | [](https://www.npmjs.com/package/@0x/contract-addresses) | A tiny utility library for getting known deployed contract addresses for a particular network. |
 | 
			
		||||
| [`@0x/contract-wrappers`](/packages/contract-wrappers)   | [](https://www.npmjs.com/package/@0x/contract-wrappers)   | JS/TS wrappers for interacting with the 0x smart contracts                                     |
 | 
			
		||||
| [`@0x/order-utils`](/packages/order-utils)               | [](https://www.npmjs.com/package/@0x/order-utils)               | A set of utilities for generating, parsing, signing and validating 0x orders                   |
 | 
			
		||||
| [`@0x/migrations`](/packages/migrations)                 | [](https://www.npmjs.com/package/@0x/migrations)                 | Migration tool for deploying 0x smart contracts on private testnets                            |
 | 
			
		||||
| [`@0x/contract-artifacts`](/packages/contract-artifacts) | [](https://www.npmjs.com/package/@0x/contract-artifacts) | 0x smart contract compilation artifacts                                                        |  |
 | 
			
		||||
 | 
			
		||||
## Usage
 | 
			
		||||
@@ -81,7 +92,7 @@ yarn build
 | 
			
		||||
To build a specific package:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
PKG=@0x/protocol-utils yarn build
 | 
			
		||||
PKG=@0x/contract-wrappers yarn build
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
To build all contracts packages:
 | 
			
		||||
@@ -104,7 +115,7 @@ To watch a specific package and all it's dependent packages:
 | 
			
		||||
PKG=[NPM_PACKAGE_NAME] yarn watch
 | 
			
		||||
 | 
			
		||||
e.g
 | 
			
		||||
PKG=@0x/protocol-utils yarn watch
 | 
			
		||||
PKG=@0x/contract-wrappers yarn watch
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Clean
 | 
			
		||||
@@ -118,7 +129,7 @@ yarn clean
 | 
			
		||||
Clean a specific package
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
PKG=@0x/protocol-utils yarn clean
 | 
			
		||||
PKG=0x.js yarn clean
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Rebuild
 | 
			
		||||
@@ -132,7 +143,7 @@ yarn rebuild
 | 
			
		||||
To re-build (clean & build) a specific package & it's deps:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
PKG=@0x/protocol-utils yarn rebuild
 | 
			
		||||
PKG=@0x/contract-wrappers yarn rebuild
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Lint
 | 
			
		||||
@@ -146,7 +157,7 @@ yarn lint
 | 
			
		||||
Lint a specific package:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
PKG=@0x/protocol-utils yarn lint
 | 
			
		||||
PKG=@0x/contract-wrappers yarn lint
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Run Tests
 | 
			
		||||
@@ -160,7 +171,7 @@ yarn test
 | 
			
		||||
Run a specific package's test:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
PKG=@0x/protocol-utils yarn test
 | 
			
		||||
PKG=@0x/contract-wrappers yarn test
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Run all contracts packages tests:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								contracts/.solhint.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								contracts/.solhint.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
{
 | 
			
		||||
    "extends": "default",
 | 
			
		||||
    "rules": {
 | 
			
		||||
        "avoid-low-level-calls": false,
 | 
			
		||||
        "avoid-tx-origin": "warn",
 | 
			
		||||
        "bracket-align": false,
 | 
			
		||||
        "code-complexity": false,
 | 
			
		||||
        "compiler-fixed": false,
 | 
			
		||||
        "const-name-snakecase": "error",
 | 
			
		||||
        "expression-indent": "error",
 | 
			
		||||
        "function-max-lines": false,
 | 
			
		||||
        "func-order": "error",
 | 
			
		||||
        "indent": ["error", 4],
 | 
			
		||||
        "max-line-length": ["warn", 160],
 | 
			
		||||
        "no-inline-assembly": false,
 | 
			
		||||
        "quotes": ["error", "double"],
 | 
			
		||||
        "separate-by-one-line-in-contract": "error",
 | 
			
		||||
        "space-after-comma": "error",
 | 
			
		||||
        "statement-indent": "error",
 | 
			
		||||
        "no-empty-blocks": false
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,3 +1,16 @@
 | 
			
		||||
#### Deployed Contract Packages
 | 
			
		||||
 | 
			
		||||
| Contract        | Package                                                             | Version                                                                          | Git Tag                                                                                                                                |
 | 
			
		||||
| --------------- | ------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
 | 
			
		||||
| AssetProxyOwner | [`@0x/contracts-multisig`](/contracts/multisig)                     | [v1.0.2](https://www.npmjs.com/package/@0x/contracts-multisig/v/1.0.2)           | [@0x/contracts-multisig@1.0.2](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-multisig@1.0.2)                     |
 | 
			
		||||
| ERC20Proxy      | [`@0x/contracts-asset-proxy`](/contracts/asset-proxy)               | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-asset-proxy/v/1.0.1)        | [@0x/contracts-asset-proxy@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-asset-proxy@1.0.1)               |
 | 
			
		||||
| ERC721Proxy     | [`@0x/contracts-asset-proxy`](/contracts/asset-proxy)               | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-asset-proxy/v/1.0.1)        | [@0x/contracts-asset-proxy@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-asset-proxy@1.0.1)               |
 | 
			
		||||
| Exchange        | [`@0x/contracts-exchange`](/contracts/exchange)                     | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-exchange/v/1.0.1)           | [@0x/contracts-exchange@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-exchange@1.0.1)                     |
 | 
			
		||||
| DutchAuction    | [`@0x/contracts-extensions`](/contracts/extensions)                 | [v1.0.2](https://www.npmjs.com/package/@0x/contracts-extensions/v/1.0.2)         | [@0x/contracts-extensions@1.0.2](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-extensions@1.0.2)                 |
 | 
			
		||||
| Forwarder       | [`@0x/contracts-exchange-forwarder`](/contracts/exchange-forwarder) | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-exchange-forwarder/v/1.0.1) | [@0x/contracts-exchange-forwarder@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-exchange-forwarder@1.0.1) |
 | 
			
		||||
| MultiAssetProxy | [`@0x/contracts-asset-proxy`](/contracts/asset-proxy)               | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-asset-proxy/v/1.0.1)        | [@0x/contracts-asset-proxy@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-asset-proxy@1.0.1)               |
 | 
			
		||||
| ZRXToken        | [`@0x/contracts-erc20`](/contracts/erc20)                           | [v1.0.1](https://www.npmjs.com/package/@0x/contracts-erc20/v/1.0.1)              | [@0x/contracts-erc20@1.0.1](https://github.com/0xProject/0x-monorepo/releases/tag/@0x/contracts-erc20@1.0.1)                           |
 | 
			
		||||
 | 
			
		||||
#### Development
 | 
			
		||||
 | 
			
		||||
Building solidity files will update the contract artifact in `{package-name}/generated-artifacts/{contract}.json`, but does not automatically update the `contract-artifacts` or `contract-wrappers` packages, which are generated from the artifact JSON. See `contract-artifacts/README.md` for instructions on updating these packages.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										48
									
								
								contracts/TESTING.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								contracts/TESTING.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
# Contracts testing options
 | 
			
		||||
 | 
			
		||||
## Revert stack traces
 | 
			
		||||
 | 
			
		||||
If you want to see helpful stack traces (incl. line number, code snippet) for smart contract reverts, run the tests with:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
yarn test:trace
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Note:** This currently slows down the test runs and is therefore not enabled by default.
 | 
			
		||||
 | 
			
		||||
## Backing Ethereum node
 | 
			
		||||
 | 
			
		||||
By default, our tests run against an in-process [Ganache](https://github.com/trufflesuite/ganache-core) instance. In order to run the tests against [Geth](https://github.com/ethereum/go-ethereum), first follow the instructions in the README for the devnet package to start the devnet Geth node. Then run:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
TEST_PROVIDER=geth yarn test
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Code coverage
 | 
			
		||||
 | 
			
		||||
In order to see the Solidity code coverage output generated by `@0x/sol-coverage`, run:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
yarn test:coverage
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Gas profiler
 | 
			
		||||
 | 
			
		||||
In order to profile the gas costs for a specific smart contract call/transaction, you can run the tests in `profiler` mode.
 | 
			
		||||
 | 
			
		||||
**Note:** Traces emitted by ganache have incorrect gas costs so we recommend using Geth for profiling.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
TEST_PROVIDER=geth yarn test:profiler
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
You'll see a warning that you need to explicitly enable and disable the profiler before and after the block of code you want to profile.
 | 
			
		||||
 | 
			
		||||
```typescript
 | 
			
		||||
import { profiler } from './utils/profiler';
 | 
			
		||||
profiler.start();
 | 
			
		||||
// Some call to a smart contract
 | 
			
		||||
profiler.stop();
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Without explicitly starting and stopping the profiler, the profiler output will be too busy, and therefore unusable.
 | 
			
		||||
							
								
								
									
										10
									
								
								contracts/asset-proxy/.npmignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								contracts/asset-proxy/.npmignore
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
# Blacklist all files
 | 
			
		||||
.*
 | 
			
		||||
*
 | 
			
		||||
# Whitelist lib
 | 
			
		||||
!lib/**/*
 | 
			
		||||
# Whitelist Solidity contracts
 | 
			
		||||
!contracts/src/**/*
 | 
			
		||||
# Blacklist tests in lib
 | 
			
		||||
/lib/test/*
 | 
			
		||||
# Package specific ignore
 | 
			
		||||
							
								
								
									
										2
									
								
								contracts/asset-proxy/.solhintignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								contracts/asset-proxy/.solhintignore
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
# solhint can't parse `abi.decode` syntax.
 | 
			
		||||
contracts/src/ERC1155Proxy.sol
 | 
			
		||||
							
								
								
									
										805
									
								
								contracts/asset-proxy/CHANGELOG.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										805
									
								
								contracts/asset-proxy/CHANGELOG.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,805 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1615932869,
 | 
			
		||||
        "version": "3.7.8-multiplex.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1614141718,
 | 
			
		||||
        "version": "3.7.7",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1612950500,
 | 
			
		||||
        "version": "3.7.6",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1611648096,
 | 
			
		||||
        "version": "3.7.5",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1610510890,
 | 
			
		||||
        "version": "3.7.4",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1609802516,
 | 
			
		||||
        "version": "3.7.3",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1608692071,
 | 
			
		||||
        "version": "3.7.2",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1608245516,
 | 
			
		||||
        "version": "3.7.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "3.7.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Fix Bancor support of ETH",
 | 
			
		||||
                "pr": 88
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1608105788
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1607485227,
 | 
			
		||||
        "version": "3.6.9",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1607381756,
 | 
			
		||||
        "version": "3.6.8",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1606961263,
 | 
			
		||||
        "version": "3.6.7",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1605763885,
 | 
			
		||||
        "version": "3.6.6",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1605302002,
 | 
			
		||||
        "version": "3.6.5",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1604385937,
 | 
			
		||||
        "version": "3.6.4",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1604376968,
 | 
			
		||||
        "version": "3.6.3",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1604355662,
 | 
			
		||||
        "version": "3.6.2",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1603851023,
 | 
			
		||||
        "version": "3.6.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "3.6.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add `SwerveBridge` and `SnowSwapBridge` (duplicate of `CurveBridge`)",
 | 
			
		||||
                "pr": 2707
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1603833198
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "3.5.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Update `CurveBridge` to support more varied curves",
 | 
			
		||||
                "pr": 2633
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Export DexForwarderBridgeContract",
 | 
			
		||||
                "pr": 2656
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add BancorBridge and IBancorNetwork, ",
 | 
			
		||||
                "pr": 2650
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Added `MStableBridge`",
 | 
			
		||||
                "pr": 2662
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Added `MooniswapBridge`",
 | 
			
		||||
                "pr": 2675
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Reworked `KyberBridge`",
 | 
			
		||||
                "pr": 2683
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Added `CreamBridge`",
 | 
			
		||||
                "pr": 2715
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Added `ShellBridge`",
 | 
			
		||||
                "pr": 2722
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Added `DODOBridge`",
 | 
			
		||||
                "pr": 2701
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1603265572
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "3.4.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Fix instability with DFB.",
 | 
			
		||||
                "pr": 2616
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add `BalancerBridge`",
 | 
			
		||||
                "pr": 2613
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1594788383
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "3.3.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Use `LibERC20Token.approveIfBelow()` in DEX bridges for for approvals.",
 | 
			
		||||
                "pr": 2512
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Emit `ERC20BridgeTransfer` events in bridges.",
 | 
			
		||||
                "pr": 2512
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Change names of `ERC20BridgeTransfer` args to be less ambiguous.",
 | 
			
		||||
                "pr": 2524
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Added `MixinGasToken` allowing Gas Tokens to be freed",
 | 
			
		||||
                "pr": 2523
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add `DexForwaderBridge` bridge contract.",
 | 
			
		||||
                "pr": 2525
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add `UniswapV2Bridge` bridge contract.",
 | 
			
		||||
                "pr": 2590
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add Gas Token freeing to `DexForwarderBridge` contract.",
 | 
			
		||||
                "pr": 2536
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1592969527
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1583220306,
 | 
			
		||||
        "version": "3.2.5",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1582837861,
 | 
			
		||||
        "version": "3.2.4",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1582677073,
 | 
			
		||||
        "version": "3.2.3",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1582623685,
 | 
			
		||||
        "version": "3.2.2",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1581748629,
 | 
			
		||||
        "version": "3.2.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "3.2.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add more types and functions to `IDydx`",
 | 
			
		||||
                "pr": 2466
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Rename `DydxBrigeAction.accountId` to `DydxBridgeAction.accountIdx`",
 | 
			
		||||
                "pr": 2466
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Fix broken tests.",
 | 
			
		||||
                "pr": 2462
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Remove dependency on `@0x/contracts-dev-utils`",
 | 
			
		||||
                "pr": 2462
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add asset data decoding functions",
 | 
			
		||||
                "pr": 2462
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add `setOperators()` to `IDydx`",
 | 
			
		||||
                "pr": 2462
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1581204851
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1580988106,
 | 
			
		||||
        "version": "3.1.3",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1580811564,
 | 
			
		||||
        "version": "3.1.2",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1579682890,
 | 
			
		||||
        "version": "3.1.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "3.1.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Integration tests for DydxBridge with ERC20BridgeProxy.",
 | 
			
		||||
                "pr": 2401
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Fix `UniswapBridge` token -> token transfer call.",
 | 
			
		||||
                "pr": 2412
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Fix `KyberBridge` incorrect `minConversionRate` calculation.",
 | 
			
		||||
                "pr": 2412
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1578272714
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1576540892,
 | 
			
		||||
        "version": "3.0.2",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1575931811,
 | 
			
		||||
        "version": "3.0.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "3.0.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Implement `KyberBridge`.",
 | 
			
		||||
                "pr": 2352
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils",
 | 
			
		||||
                "pr": 2330
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract",
 | 
			
		||||
                "pr": 2034
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable",
 | 
			
		||||
                "pr": 2019
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Remove `LibAssetProxyIds` contract",
 | 
			
		||||
                "pr": 2055
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Compile and export all contracts, artifacts, and wrappers by default",
 | 
			
		||||
                "pr": 2055
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Remove unused dependency on IAuthorizable in IAssetProxy",
 | 
			
		||||
                "pr": 1910
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add `ERC20BridgeProxy`",
 | 
			
		||||
                "pr": 2220
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add `Eth2DaiBridge`",
 | 
			
		||||
                "pr": 2221
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add `UniswapBridge`",
 | 
			
		||||
                "pr": 2233
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Replaced `SafeMath` with `LibSafeMath`",
 | 
			
		||||
                "pr": 2254
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1575296764
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "2.3.0-beta.4",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Implement `KyberBridge`.",
 | 
			
		||||
                "pr": 2352
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Implement `DydxBridge`.",
 | 
			
		||||
                "pr": 2365
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1575290197
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "2.3.0-beta.3",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1574238768
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "2.3.0-beta.2",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils",
 | 
			
		||||
                "pr": 2330
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1574030254
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "2.3.0-beta.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract",
 | 
			
		||||
                "pr": 2034
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1573159180
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "2.3.0-beta.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable",
 | 
			
		||||
                "pr": 2019
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Remove `LibAssetProxyIds` contract",
 | 
			
		||||
                "pr": 2055
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Compile and export all contracts, artifacts, and wrappers by default",
 | 
			
		||||
                "pr": 2055
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Remove unused dependency on IAuthorizable in IAssetProxy",
 | 
			
		||||
                "pr": 1910
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add `ERC20BridgeProxy`",
 | 
			
		||||
                "pr": 2220
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add `Eth2DaiBridge`",
 | 
			
		||||
                "pr": 2221
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add `UniswapBridge`",
 | 
			
		||||
                "pr": 2233
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Replaced `SafeMath` with `LibSafeMath`",
 | 
			
		||||
                "pr": 2254
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1570135330
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1568744790,
 | 
			
		||||
        "version": "2.2.8",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1567521715,
 | 
			
		||||
        "version": "2.2.7",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1566446343,
 | 
			
		||||
        "version": "2.2.6",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1565296576,
 | 
			
		||||
        "version": "2.2.5",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "2.2.4",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Updated calls to <contract wrapper>.deployFrom0xArtifactAsync to include artifact dependencies.",
 | 
			
		||||
                "pr": 1995
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1564607468
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1563957393,
 | 
			
		||||
        "version": "2.2.3",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1563193019,
 | 
			
		||||
        "version": "2.2.2",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1563047529,
 | 
			
		||||
        "version": "2.2.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "2.2.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add `LibAssetProxyIds` contract",
 | 
			
		||||
                "pr": 1835
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Updated ERC1155 Asset Proxy. Less optimization. More explicit handling of edge cases.",
 | 
			
		||||
                "pr": 1852
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Implement StaticCallProxy",
 | 
			
		||||
                "pr": 1863
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1563006338
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1558712885,
 | 
			
		||||
        "version": "2.1.5",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1557961111,
 | 
			
		||||
        "version": "2.1.4",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1557799313,
 | 
			
		||||
        "version": "2.1.3",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "2.1.2",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Update tests to use contract-built-in `awaitTransactionSuccessAsync`",
 | 
			
		||||
                "pr": 1797
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Make `ERC721Wrapper.setApprovalForAll()` take an owner address instead of a token ID",
 | 
			
		||||
                "pr": 1819
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Automatically set unlimited proxy allowances in `ERC721.setBalancesAndAllowancesAsync()`",
 | 
			
		||||
                "pr": 1819
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add `setProxyAllowanceForAllAsync()` to `ERC1155ProxyWrapper`.",
 | 
			
		||||
                "pr": 1819
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1557507213
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "2.1.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1554997931
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "2.1.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Run Web3ProviderEngine without excess block polling",
 | 
			
		||||
                "pr": 1695
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1553183790
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "2.0.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Do not reexport external dependencies",
 | 
			
		||||
                "pr": 1682
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add ERC1155Proxy",
 | 
			
		||||
                "pr": 1661
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Bumped solidity version to ^0.5.5",
 | 
			
		||||
                "pr": 1701
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Integration testing for ERC1155Proxy",
 | 
			
		||||
                "pr": 1673
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1553091633
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1551479279,
 | 
			
		||||
        "version": "1.0.9",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1551299797,
 | 
			
		||||
        "version": "1.0.8",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1551220833,
 | 
			
		||||
        "version": "1.0.7",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1551130135,
 | 
			
		||||
        "version": "1.0.6",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1549733923,
 | 
			
		||||
        "version": "1.0.5",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "1.0.4",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1549547375
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "1.0.3",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Fake publish to enable pinning"
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "timestamp": 1549504360
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1549452781,
 | 
			
		||||
        "version": "1.0.2",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "timestamp": 1549373905,
 | 
			
		||||
        "version": "1.0.1",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Dependencies updated"
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "version": "1.0.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Move all AssetProxy contracts out of contracts-protocol to new package",
 | 
			
		||||
                "pr": 1539
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    }
 | 
			
		||||
]
 | 
			
		||||
							
								
								
									
										318
									
								
								contracts/asset-proxy/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										318
									
								
								contracts/asset-proxy/CHANGELOG.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,318 @@
 | 
			
		||||
<!--
 | 
			
		||||
changelogUtils.file is auto-generated using the monorepo-scripts package. Don't edit directly.
 | 
			
		||||
Edit the package's CHANGELOG.json file only.
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
CHANGELOG
 | 
			
		||||
 | 
			
		||||
## v3.7.8-multiplex.0 - _March 16, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.7.7 - _February 24, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.7.6 - _February 10, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.7.5 - _January 26, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.7.4 - _January 13, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.7.3 - _January 4, 2021_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.7.2 - _December 23, 2020_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.7.1 - _December 17, 2020_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.7.0 - _December 16, 2020_
 | 
			
		||||
 | 
			
		||||
    * Fix Bancor support of ETH (#88)
 | 
			
		||||
 | 
			
		||||
## v3.6.9 - _December 9, 2020_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.6.8 - _December 7, 2020_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.6.7 - _December 3, 2020_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.6.6 - _November 19, 2020_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.6.5 - _November 13, 2020_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.6.4 - _November 3, 2020_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.6.3 - _November 3, 2020_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.6.2 - _November 2, 2020_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.6.1 - _October 28, 2020_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.6.0 - _October 27, 2020_
 | 
			
		||||
 | 
			
		||||
    * Add `SwerveBridge` and `SnowSwapBridge` (duplicate of `CurveBridge`) (#2707)
 | 
			
		||||
 | 
			
		||||
## v3.5.0 - _October 21, 2020_
 | 
			
		||||
 | 
			
		||||
    * Update `CurveBridge` to support more varied curves (#2633)
 | 
			
		||||
    * Export DexForwarderBridgeContract (#2656)
 | 
			
		||||
    * Add BancorBridge and IBancorNetwork,  (#2650)
 | 
			
		||||
    * Added `MStableBridge` (#2662)
 | 
			
		||||
    * Added `MooniswapBridge` (#2675)
 | 
			
		||||
    * Reworked `KyberBridge` (#2683)
 | 
			
		||||
    * Added `CreamBridge` (#2715)
 | 
			
		||||
    * Added `ShellBridge` (#2722)
 | 
			
		||||
    * Added `DODOBridge` (#2701)
 | 
			
		||||
 | 
			
		||||
## v3.4.0 - _July 15, 2020_
 | 
			
		||||
 | 
			
		||||
    * Fix instability with DFB. (#2616)
 | 
			
		||||
    * Add `BalancerBridge` (#2613)
 | 
			
		||||
 | 
			
		||||
## v3.3.0 - _June 24, 2020_
 | 
			
		||||
 | 
			
		||||
    * Use `LibERC20Token.approveIfBelow()` in DEX bridges for for approvals. (#2512)
 | 
			
		||||
    * Emit `ERC20BridgeTransfer` events in bridges. (#2512)
 | 
			
		||||
    * Change names of `ERC20BridgeTransfer` args to be less ambiguous. (#2524)
 | 
			
		||||
    * Added `MixinGasToken` allowing Gas Tokens to be freed (#2523)
 | 
			
		||||
    * Add `DexForwaderBridge` bridge contract. (#2525)
 | 
			
		||||
    * Add `UniswapV2Bridge` bridge contract. (#2590)
 | 
			
		||||
    * Add Gas Token freeing to `DexForwarderBridge` contract. (#2536)
 | 
			
		||||
 | 
			
		||||
## v3.2.5 - _March 3, 2020_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.2.4 - _February 27, 2020_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.2.3 - _February 26, 2020_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.2.2 - _February 25, 2020_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.2.1 - _February 15, 2020_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.2.0 - _February 8, 2020_
 | 
			
		||||
 | 
			
		||||
    * Add more types and functions to `IDydx` (#2466)
 | 
			
		||||
    * Rename `DydxBrigeAction.accountId` to `DydxBridgeAction.accountIdx` (#2466)
 | 
			
		||||
    * Fix broken tests. (#2462)
 | 
			
		||||
    * Remove dependency on `@0x/contracts-dev-utils` (#2462)
 | 
			
		||||
    * Add asset data decoding functions (#2462)
 | 
			
		||||
    * Add `setOperators()` to `IDydx` (#2462)
 | 
			
		||||
 | 
			
		||||
## v3.1.3 - _February 6, 2020_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.1.2 - _February 4, 2020_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.1.1 - _January 22, 2020_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.1.0 - _January 6, 2020_
 | 
			
		||||
 | 
			
		||||
    * Integration tests for DydxBridge with ERC20BridgeProxy. (#2401)
 | 
			
		||||
    * Fix `UniswapBridge` token -> token transfer call. (#2412)
 | 
			
		||||
    * Fix `KyberBridge` incorrect `minConversionRate` calculation. (#2412)
 | 
			
		||||
 | 
			
		||||
## v3.0.2 - _December 17, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.0.1 - _December 9, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v3.0.0 - _December 2, 2019_
 | 
			
		||||
 | 
			
		||||
    * Implement `KyberBridge`. (#2352)
 | 
			
		||||
    * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)
 | 
			
		||||
    * ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract (#2034)
 | 
			
		||||
    * Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable (#2019)
 | 
			
		||||
    * Remove `LibAssetProxyIds` contract (#2055)
 | 
			
		||||
    * Compile and export all contracts, artifacts, and wrappers by default (#2055)
 | 
			
		||||
    * Remove unused dependency on IAuthorizable in IAssetProxy (#1910)
 | 
			
		||||
    * Add `ERC20BridgeProxy` (#2220)
 | 
			
		||||
    * Add `Eth2DaiBridge` (#2221)
 | 
			
		||||
    * Add `UniswapBridge` (#2233)
 | 
			
		||||
    * Replaced `SafeMath` with `LibSafeMath` (#2254)
 | 
			
		||||
 | 
			
		||||
## v2.3.0-beta.4 - _December 2, 2019_
 | 
			
		||||
 | 
			
		||||
    * Implement `KyberBridge`. (#2352)
 | 
			
		||||
    * Implement `DydxBridge`. (#2365)
 | 
			
		||||
 | 
			
		||||
## v2.3.0-beta.3 - _November 20, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.3.0-beta.2 - _November 17, 2019_
 | 
			
		||||
 | 
			
		||||
    * Drastically reduced bundle size by adding .npmignore, only exporting specific artifacts/wrappers/utils (#2330)
 | 
			
		||||
 | 
			
		||||
## v2.3.0-beta.1 - _November 7, 2019_
 | 
			
		||||
 | 
			
		||||
    * ERC20Wrapper and ERC1155ProxyWrapper constructors now require an instance of DevUtilsContract (#2034)
 | 
			
		||||
 | 
			
		||||
## v2.3.0-beta.0 - _October 3, 2019_
 | 
			
		||||
 | 
			
		||||
    * Disallow the zero address from being made an authorized address in MixinAuthorizable, and created an archive directory that includes an old version of Ownable (#2019)
 | 
			
		||||
    * Remove `LibAssetProxyIds` contract (#2055)
 | 
			
		||||
    * Compile and export all contracts, artifacts, and wrappers by default (#2055)
 | 
			
		||||
    * Remove unused dependency on IAuthorizable in IAssetProxy (#1910)
 | 
			
		||||
    * Add `ERC20BridgeProxy` (#2220)
 | 
			
		||||
    * Add `Eth2DaiBridge` (#2221)
 | 
			
		||||
    * Add `UniswapBridge` (#2233)
 | 
			
		||||
    * Replaced `SafeMath` with `LibSafeMath` (#2254)
 | 
			
		||||
 | 
			
		||||
## v2.2.8 - _September 17, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.2.7 - _September 3, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.2.6 - _August 22, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.2.5 - _August 8, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.2.4 - _July 31, 2019_
 | 
			
		||||
 | 
			
		||||
    * Updated calls to <contract wrapper>.deployFrom0xArtifactAsync to include artifact dependencies. (#1995)
 | 
			
		||||
 | 
			
		||||
## v2.2.3 - _July 24, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.2.2 - _July 15, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.2.1 - _July 13, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.2.0 - _July 13, 2019_
 | 
			
		||||
 | 
			
		||||
    * Add `LibAssetProxyIds` contract (#1835)
 | 
			
		||||
    * Updated ERC1155 Asset Proxy. Less optimization. More explicit handling of edge cases. (#1852)
 | 
			
		||||
    * Implement StaticCallProxy (#1863)
 | 
			
		||||
 | 
			
		||||
## v2.1.5 - _May 24, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.1.4 - _May 15, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.1.3 - _May 14, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.1.2 - _May 10, 2019_
 | 
			
		||||
 | 
			
		||||
    * Update tests to use contract-built-in `awaitTransactionSuccessAsync` (#1797)
 | 
			
		||||
    * Make `ERC721Wrapper.setApprovalForAll()` take an owner address instead of a token ID (#1819)
 | 
			
		||||
    * Automatically set unlimited proxy allowances in `ERC721.setBalancesAndAllowancesAsync()` (#1819)
 | 
			
		||||
    * Add `setProxyAllowanceForAllAsync()` to `ERC1155ProxyWrapper`. (#1819)
 | 
			
		||||
 | 
			
		||||
## v2.1.1 - _April 11, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v2.1.0 - _March 21, 2019_
 | 
			
		||||
 | 
			
		||||
    * Run Web3ProviderEngine without excess block polling (#1695)
 | 
			
		||||
 | 
			
		||||
## v2.0.0 - _March 20, 2019_
 | 
			
		||||
 | 
			
		||||
    * Do not reexport external dependencies (#1682)
 | 
			
		||||
    * Add ERC1155Proxy (#1661)
 | 
			
		||||
    * Bumped solidity version to ^0.5.5 (#1701)
 | 
			
		||||
    * Integration testing for ERC1155Proxy (#1673)
 | 
			
		||||
 | 
			
		||||
## v1.0.9 - _March 1, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.0.8 - _February 27, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.0.7 - _February 26, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.0.6 - _February 25, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.0.5 - _February 9, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.0.4 - _February 7, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.0.3 - _February 7, 2019_
 | 
			
		||||
 | 
			
		||||
    * Fake publish to enable pinning
 | 
			
		||||
 | 
			
		||||
## v1.0.2 - _February 6, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.0.1 - _February 5, 2019_
 | 
			
		||||
 | 
			
		||||
    * Dependencies updated
 | 
			
		||||
 | 
			
		||||
## v1.0.0 - _Invalid date_
 | 
			
		||||
 | 
			
		||||
    * Move all AssetProxy contracts out of contracts-protocol to new package (#1539)
 | 
			
		||||
							
								
								
									
										47
									
								
								contracts/asset-proxy/DEPLOYS.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								contracts/asset-proxy/DEPLOYS.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "name": "MultiAssetProxy",
 | 
			
		||||
        "version": "1.0.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "Add MultiAssetProxy implementation",
 | 
			
		||||
                "pr": 1224,
 | 
			
		||||
                "networks": {
 | 
			
		||||
                    "3": "0xab8fbd189c569ccdee3a4d929bb7f557be4028f6",
 | 
			
		||||
                    "4": "0xb34cde0ad3a83d04abebc0b66e75196f22216621",
 | 
			
		||||
                    "42": "0xf6313a772c222f51c28f2304c0703b8cf5428fd8"
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "name": "ERC20Proxy",
 | 
			
		||||
        "version": "1.0.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "protocol v2 deploy",
 | 
			
		||||
                "networks": {
 | 
			
		||||
                    "1": "0x2240dab907db71e64d3e0dba4800c83b5c502d4e",
 | 
			
		||||
                    "3": "0xb1408f4c245a23c31b98d2c626777d4c0d766caa",
 | 
			
		||||
                    "4": "0x3e809c563c15a295e832e37053798ddc8d6c8dab",
 | 
			
		||||
                    "42": "0xf1ec01d6236d3cd881a0bf0130ea25fe4234003e"
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        "name": "ERC721Proxy",
 | 
			
		||||
        "version": "1.0.0",
 | 
			
		||||
        "changes": [
 | 
			
		||||
            {
 | 
			
		||||
                "note": "protocol v2 deploy",
 | 
			
		||||
                "networks": {
 | 
			
		||||
                    "1": "0x208e41fb445f1bb1b6780d58356e81405f3e6127",
 | 
			
		||||
                    "3": "0xe654aac058bfbf9f83fcaee7793311dd82f6ddb4",
 | 
			
		||||
                    "4": "0x8e1ff02637cb5e39f2fa36c14706aa348b065b09",
 | 
			
		||||
                    "42": "0x2a9127c745688a165106c11cd4d647d2220af821"
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    }
 | 
			
		||||
]
 | 
			
		||||
							
								
								
									
										73
									
								
								contracts/asset-proxy/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								contracts/asset-proxy/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
## AssetProxy
 | 
			
		||||
 | 
			
		||||
This package contains the implementations of all of the [`AssetProxy`](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/v2-specification.md#assetproxy) contracts available within the 0x protocol. These contracts are responsible for decoding the `assetData` sent to them and performing the actual transfer of assets. Addresses of the deployed contracts can be found in this 0x [guide](https://0x.org/docs/guides/0x-cheat-sheet) or the [DEPLOYS](./DEPLOYS.json) file within this package.
 | 
			
		||||
 | 
			
		||||
## Installation
 | 
			
		||||
 | 
			
		||||
**Install**
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
npm install @0x/contracts-asset-proxy --save
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Bug bounty
 | 
			
		||||
 | 
			
		||||
A bug bounty for the 2.0.0 contracts is ongoing! Instructions can be found [here](https://0x.org/docs/guides/bug-bounty-program).
 | 
			
		||||
 | 
			
		||||
## Contributing
 | 
			
		||||
 | 
			
		||||
We strongly recommend that the community help us make improvements and determine the future direction of the protocol. To report bugs within this package, please create an issue in this repository.
 | 
			
		||||
 | 
			
		||||
For proposals regarding the 0x protocol's smart contract architecture, message format, or additional functionality, go to the [0x Improvement Proposals (ZEIPs)](https://github.com/0xProject/ZEIPs) repository and follow the contribution guidelines provided therein.
 | 
			
		||||
 | 
			
		||||
Please read our [contribution guidelines](../../CONTRIBUTING.md) before getting started.
 | 
			
		||||
 | 
			
		||||
### Install Dependencies
 | 
			
		||||
 | 
			
		||||
If you don't have yarn workspaces enabled (Yarn < v1.0) - enable them:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
yarn config set workspaces-experimental true
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Then install dependencies
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
yarn install
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Build
 | 
			
		||||
 | 
			
		||||
To build this package and all other monorepo packages that it depends on, run the following from the monorepo root directory:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
PKG=@0x/contracts-asset-proxy yarn build
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Or continuously rebuild on change:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
PKG=@0x/contracts-asset-proxy yarn watch
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Clean
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
yarn clean
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Lint
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
yarn lint
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Run Tests
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
yarn test
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Testing options
 | 
			
		||||
 | 
			
		||||
Contracts testing options like coverage, profiling, revert traces or backing node choosing - are described [here](../TESTING.md).
 | 
			
		||||
							
								
								
									
										27
									
								
								contracts/asset-proxy/compiler.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								contracts/asset-proxy/compiler.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
{
 | 
			
		||||
    "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"
 | 
			
		||||
                ]
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,172 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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 "../archive/Ownable.sol";
 | 
			
		||||
import "../src/interfaces/IAssetProxy.sol";
 | 
			
		||||
import "../src/interfaces/IAssetProxyDispatcher.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract MixinAssetProxyDispatcher is
 | 
			
		||||
    Ownable,
 | 
			
		||||
    IAssetProxyDispatcher
 | 
			
		||||
{
 | 
			
		||||
    // Mapping from Asset Proxy Id's to their respective Asset Proxy
 | 
			
		||||
    mapping (bytes4 => address) public assetProxies;
 | 
			
		||||
 | 
			
		||||
    /// @dev Registers an asset proxy to its asset proxy id.
 | 
			
		||||
    ///      Once an asset proxy is registered, it cannot be unregistered.
 | 
			
		||||
    /// @param assetProxy Address of new asset proxy to register.
 | 
			
		||||
    function registerAssetProxy(address assetProxy)
 | 
			
		||||
        external
 | 
			
		||||
        onlyOwner
 | 
			
		||||
    {
 | 
			
		||||
        // Ensure that no asset proxy exists with current id.
 | 
			
		||||
        bytes4 assetProxyId = IAssetProxy(assetProxy).getProxyId();
 | 
			
		||||
        address currentAssetProxy = assetProxies[assetProxyId];
 | 
			
		||||
        require(
 | 
			
		||||
            currentAssetProxy == address(0),
 | 
			
		||||
            "ASSET_PROXY_ALREADY_EXISTS"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Add asset proxy and log registration.
 | 
			
		||||
        assetProxies[assetProxyId] = assetProxy;
 | 
			
		||||
        emit AssetProxyRegistered(
 | 
			
		||||
            assetProxyId,
 | 
			
		||||
            assetProxy
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets an asset proxy.
 | 
			
		||||
    /// @param assetProxyId Id of the asset proxy.
 | 
			
		||||
    /// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered.
 | 
			
		||||
    function getAssetProxy(bytes4 assetProxyId)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (address)
 | 
			
		||||
    {
 | 
			
		||||
        return assetProxies[assetProxyId];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Forwards arguments to assetProxy and calls `transferFrom`. Either succeeds or throws.
 | 
			
		||||
    /// @param assetData Byte array encoded for the asset.
 | 
			
		||||
    /// @param from Address to transfer token from.
 | 
			
		||||
    /// @param to Address to transfer token to.
 | 
			
		||||
    /// @param amount Amount of token to transfer.
 | 
			
		||||
    function _dispatchTransferFrom(
 | 
			
		||||
        bytes memory assetData,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
    {
 | 
			
		||||
        // Do nothing if no amount should be transferred.
 | 
			
		||||
        if (amount > 0 && from != to) {
 | 
			
		||||
            // Ensure assetData length is valid
 | 
			
		||||
            require(
 | 
			
		||||
                assetData.length > 3,
 | 
			
		||||
                "LENGTH_GREATER_THAN_3_REQUIRED"
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // Lookup assetProxy. We do not use `LibBytes.readBytes4` for gas efficiency reasons.
 | 
			
		||||
            bytes4 assetProxyId;
 | 
			
		||||
            assembly {
 | 
			
		||||
                assetProxyId := and(mload(
 | 
			
		||||
                    add(assetData, 32)),
 | 
			
		||||
                    0xFFFFFFFF00000000000000000000000000000000000000000000000000000000
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            address assetProxy = assetProxies[assetProxyId];
 | 
			
		||||
 | 
			
		||||
            // Ensure that assetProxy exists
 | 
			
		||||
            require(
 | 
			
		||||
                assetProxy != address(0),
 | 
			
		||||
                "ASSET_PROXY_DOES_NOT_EXIST"
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // We construct calldata for the `assetProxy.transferFrom` ABI.
 | 
			
		||||
            // The layout of this calldata is in the table below.
 | 
			
		||||
            //
 | 
			
		||||
            // | Area     | Offset | Length  | Contents                                    |
 | 
			
		||||
            // | -------- |--------|---------|-------------------------------------------- |
 | 
			
		||||
            // | Header   | 0      | 4       | function selector                           |
 | 
			
		||||
            // | Params   |        | 4 * 32  | function parameters:                        |
 | 
			
		||||
            // |          | 4      |         |   1. offset to assetData (*)                |
 | 
			
		||||
            // |          | 36     |         |   2. from                                   |
 | 
			
		||||
            // |          | 68     |         |   3. to                                     |
 | 
			
		||||
            // |          | 100    |         |   4. amount                                 |
 | 
			
		||||
            // | Data     |        |         | assetData:                                  |
 | 
			
		||||
            // |          | 132    | 32      | assetData Length                            |
 | 
			
		||||
            // |          | 164    | **      | assetData Contents                          |
 | 
			
		||||
 | 
			
		||||
            assembly {
 | 
			
		||||
                /////// Setup State ///////
 | 
			
		||||
                // `cdStart` is the start of the calldata for `assetProxy.transferFrom` (equal to free memory ptr).
 | 
			
		||||
                let cdStart := mload(64)
 | 
			
		||||
                // `dataAreaLength` is the total number of words needed to store `assetData`
 | 
			
		||||
                //  As-per the ABI spec, this value is padded up to the nearest multiple of 32,
 | 
			
		||||
                //  and includes 32-bytes for length.
 | 
			
		||||
                let dataAreaLength := and(add(mload(assetData), 63), 0xFFFFFFFFFFFE0)
 | 
			
		||||
                // `cdEnd` is the end of the calldata for `assetProxy.transferFrom`.
 | 
			
		||||
                let cdEnd := add(cdStart, add(132, dataAreaLength))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                /////// Setup Header Area ///////
 | 
			
		||||
                // This area holds the 4-byte `transferFromSelector`.
 | 
			
		||||
                // bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
 | 
			
		||||
                mstore(cdStart, 0xa85e59e400000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
 | 
			
		||||
                /////// Setup Params Area ///////
 | 
			
		||||
                // Each parameter is padded to 32-bytes. The entire Params Area is 128 bytes.
 | 
			
		||||
                // Notes:
 | 
			
		||||
                //   1. The offset to `assetData` is the length of the Params Area (128 bytes).
 | 
			
		||||
                //   2. A 20-byte mask is applied to addresses to zero-out the unused bytes.
 | 
			
		||||
                mstore(add(cdStart, 4), 128)
 | 
			
		||||
                mstore(add(cdStart, 36), and(from, 0xffffffffffffffffffffffffffffffffffffffff))
 | 
			
		||||
                mstore(add(cdStart, 68), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
 | 
			
		||||
                mstore(add(cdStart, 100), amount)
 | 
			
		||||
 | 
			
		||||
                /////// Setup Data Area ///////
 | 
			
		||||
                // This area holds `assetData`.
 | 
			
		||||
                let dataArea := add(cdStart, 132)
 | 
			
		||||
                // solhint-disable-next-line no-empty-blocks
 | 
			
		||||
                for {} lt(dataArea, cdEnd) {} {
 | 
			
		||||
                    mstore(dataArea, mload(assetData))
 | 
			
		||||
                    dataArea := add(dataArea, 32)
 | 
			
		||||
                    assetData := add(assetData, 32)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                /////// Call `assetProxy.transferFrom` using the constructed calldata ///////
 | 
			
		||||
                let success := call(
 | 
			
		||||
                    gas,                    // forward all gas
 | 
			
		||||
                    assetProxy,             // call address of asset proxy
 | 
			
		||||
                    0,                      // don't send any ETH
 | 
			
		||||
                    cdStart,                // pointer to start of input
 | 
			
		||||
                    sub(cdEnd, cdStart),    // length of input
 | 
			
		||||
                    cdStart,                // write output over input
 | 
			
		||||
                    512                     // reserve 512 bytes for output
 | 
			
		||||
                )
 | 
			
		||||
                if iszero(success) {
 | 
			
		||||
                    revert(cdStart, returndatasize())
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										117
									
								
								contracts/asset-proxy/contracts/archive/MixinAuthorizable.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								contracts/asset-proxy/contracts/archive/MixinAuthorizable.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,117 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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 "../archive/Ownable.sol";
 | 
			
		||||
import "../src/interfaces/IAuthorizable.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract MixinAuthorizable is
 | 
			
		||||
    Ownable,
 | 
			
		||||
    IAuthorizable
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Only authorized addresses can invoke functions with this modifier.
 | 
			
		||||
    modifier onlyAuthorized {
 | 
			
		||||
        require(
 | 
			
		||||
            authorized[msg.sender],
 | 
			
		||||
            "SENDER_NOT_AUTHORIZED"
 | 
			
		||||
        );
 | 
			
		||||
        _;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    mapping (address => bool) public authorized;
 | 
			
		||||
    address[] public authorities;
 | 
			
		||||
 | 
			
		||||
    /// @dev Authorizes an address.
 | 
			
		||||
    /// @param target Address to authorize.
 | 
			
		||||
    function addAuthorizedAddress(address target)
 | 
			
		||||
        external
 | 
			
		||||
        onlyOwner
 | 
			
		||||
    {
 | 
			
		||||
        require(
 | 
			
		||||
            !authorized[target],
 | 
			
		||||
            "TARGET_ALREADY_AUTHORIZED"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        authorized[target] = true;
 | 
			
		||||
        authorities.push(target);
 | 
			
		||||
        emit AuthorizedAddressAdded(target, msg.sender);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Removes authorizion of an address.
 | 
			
		||||
    /// @param target Address to remove authorization from.
 | 
			
		||||
    function removeAuthorizedAddress(address target)
 | 
			
		||||
        external
 | 
			
		||||
        onlyOwner
 | 
			
		||||
    {
 | 
			
		||||
        require(
 | 
			
		||||
            authorized[target],
 | 
			
		||||
            "TARGET_NOT_AUTHORIZED"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        delete authorized[target];
 | 
			
		||||
        for (uint256 i = 0; i < authorities.length; i++) {
 | 
			
		||||
            if (authorities[i] == target) {
 | 
			
		||||
                authorities[i] = authorities[authorities.length - 1];
 | 
			
		||||
                authorities.length -= 1;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        emit AuthorizedAddressRemoved(target, msg.sender);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Removes authorizion of an address.
 | 
			
		||||
    /// @param target Address to remove authorization from.
 | 
			
		||||
    /// @param index Index of target in authorities array.
 | 
			
		||||
    function removeAuthorizedAddressAtIndex(
 | 
			
		||||
        address target,
 | 
			
		||||
        uint256 index
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        onlyOwner
 | 
			
		||||
    {
 | 
			
		||||
        require(
 | 
			
		||||
            authorized[target],
 | 
			
		||||
            "TARGET_NOT_AUTHORIZED"
 | 
			
		||||
        );
 | 
			
		||||
        require(
 | 
			
		||||
            index < authorities.length,
 | 
			
		||||
            "INDEX_OUT_OF_BOUNDS"
 | 
			
		||||
        );
 | 
			
		||||
        require(
 | 
			
		||||
            authorities[index] == target,
 | 
			
		||||
            "AUTHORIZED_ADDRESS_MISMATCH"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        delete authorized[target];
 | 
			
		||||
        authorities[index] = authorities[authorities.length - 1];
 | 
			
		||||
        authorities.length -= 1;
 | 
			
		||||
        emit AuthorizedAddressRemoved(target, msg.sender);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets all authorized addresses.
 | 
			
		||||
    /// @return Array of authorized addresses.
 | 
			
		||||
    function getAuthorizedAddresses()
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (address[] memory)
 | 
			
		||||
    {
 | 
			
		||||
        return authorities;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								contracts/asset-proxy/contracts/archive/Ownable.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								contracts/asset-proxy/contracts/archive/Ownable.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
pragma solidity ^0.5.9;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/interfaces/IOwnable.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract Ownable is
 | 
			
		||||
    IOwnable
 | 
			
		||||
{
 | 
			
		||||
    address public owner;
 | 
			
		||||
 | 
			
		||||
    constructor ()
 | 
			
		||||
        public
 | 
			
		||||
    {
 | 
			
		||||
        owner = msg.sender;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    modifier onlyOwner() {
 | 
			
		||||
        require(
 | 
			
		||||
            msg.sender == owner,
 | 
			
		||||
            "ONLY_CONTRACT_OWNER"
 | 
			
		||||
        );
 | 
			
		||||
        _;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function transferOwnership(address newOwner)
 | 
			
		||||
        public
 | 
			
		||||
        onlyOwner
 | 
			
		||||
    {
 | 
			
		||||
        if (newOwner != address(0)) {
 | 
			
		||||
            owner = newOwner;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										97
									
								
								contracts/asset-proxy/contracts/src/ERC1155Proxy.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								contracts/asset-proxy/contracts/src/ERC1155Proxy.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,97 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 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/LibBytes.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
 | 
			
		||||
import "@0x/contracts-erc1155/contracts/src/interfaces/IERC1155.sol";
 | 
			
		||||
import "../archive/MixinAuthorizable.sol";
 | 
			
		||||
import "./interfaces/IAssetProxy.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract ERC1155Proxy is
 | 
			
		||||
    MixinAuthorizable,
 | 
			
		||||
    IAssetProxy
 | 
			
		||||
{
 | 
			
		||||
    using LibBytes for bytes;
 | 
			
		||||
    using LibSafeMath for uint256;
 | 
			
		||||
 | 
			
		||||
    // Id of this proxy.
 | 
			
		||||
    bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC1155Assets(address,uint256[],uint256[],bytes)"));
 | 
			
		||||
 | 
			
		||||
    /// @dev Transfers batch of ERC1155 assets. Either succeeds or throws.
 | 
			
		||||
    /// @param assetData Byte array encoded with ERC1155 token address, array of ids, array of values, and callback data.
 | 
			
		||||
    /// @param from Address to transfer assets from.
 | 
			
		||||
    /// @param to Address to transfer assets to.
 | 
			
		||||
    /// @param amount Amount that will be multiplied with each element of `assetData.values` to scale the
 | 
			
		||||
    ///        values that will be transferred.
 | 
			
		||||
    function transferFrom(
 | 
			
		||||
        bytes calldata assetData,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        onlyAuthorized
 | 
			
		||||
    {
 | 
			
		||||
        // Decode params from `assetData`
 | 
			
		||||
        // solhint-disable indent
 | 
			
		||||
        (
 | 
			
		||||
            address erc1155TokenAddress,
 | 
			
		||||
            uint256[] memory ids,
 | 
			
		||||
            uint256[] memory values,
 | 
			
		||||
            bytes memory data
 | 
			
		||||
        ) = abi.decode(
 | 
			
		||||
            assetData.sliceDestructive(4, assetData.length),
 | 
			
		||||
            (address, uint256[], uint256[], bytes)
 | 
			
		||||
        );
 | 
			
		||||
        // solhint-enable indent
 | 
			
		||||
 | 
			
		||||
        // Scale values up by `amount`
 | 
			
		||||
        uint256 length = values.length;
 | 
			
		||||
        uint256[] memory scaledValues = new uint256[](length);
 | 
			
		||||
        for (uint256 i = 0; i != length; i++) {
 | 
			
		||||
            // We write the scaled values to an unused location in memory in order
 | 
			
		||||
            // to avoid copying over `ids` or `data`. This is possible if they are
 | 
			
		||||
            // identical to `values` and the offsets for each are pointing to the
 | 
			
		||||
            // same location in the ABI encoded calldata.
 | 
			
		||||
            scaledValues[i] = values[i].safeMul(amount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Execute `safeBatchTransferFrom` call
 | 
			
		||||
        // Either succeeds or throws
 | 
			
		||||
        IERC1155(erc1155TokenAddress).safeBatchTransferFrom(
 | 
			
		||||
            from,
 | 
			
		||||
            to,
 | 
			
		||||
            ids,
 | 
			
		||||
            scaledValues,
 | 
			
		||||
            data
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets the proxy id associated with the proxy address.
 | 
			
		||||
    /// @return Proxy id.
 | 
			
		||||
    function getProxyId()
 | 
			
		||||
        external
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes4)
 | 
			
		||||
    {
 | 
			
		||||
        return PROXY_ID;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										126
									
								
								contracts/asset-proxy/contracts/src/ERC20BridgeProxy.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								contracts/asset-proxy/contracts/src/ERC20BridgeProxy.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,126 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/Authorizable.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "./interfaces/IAssetProxy.sol";
 | 
			
		||||
import "./interfaces/IERC20Bridge.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract ERC20BridgeProxy is
 | 
			
		||||
    IAssetProxy,
 | 
			
		||||
    Authorizable
 | 
			
		||||
{
 | 
			
		||||
    using LibBytes for bytes;
 | 
			
		||||
    using LibSafeMath for uint256;
 | 
			
		||||
 | 
			
		||||
    // @dev Id of this proxy. Also the result of a successful bridge call.
 | 
			
		||||
    //      bytes4(keccak256("ERC20Bridge(address,address,bytes)"))
 | 
			
		||||
    bytes4 constant private PROXY_ID = 0xdc1600f3;
 | 
			
		||||
 | 
			
		||||
    /// @dev Calls a bridge contract to transfer `amount` of ERC20 from `from`
 | 
			
		||||
    ///      to `to`. Asserts that the balance of `to` has increased by `amount`.
 | 
			
		||||
    /// @param assetData Abi-encoded data for this asset proxy encoded as:
 | 
			
		||||
    ///          abi.encodeWithSelector(
 | 
			
		||||
    ///             bytes4 PROXY_ID,
 | 
			
		||||
    ///             address tokenAddress,
 | 
			
		||||
    ///             address bridgeAddress,
 | 
			
		||||
    ///             bytes bridgeData
 | 
			
		||||
    ///          )
 | 
			
		||||
    /// @param from Address to transfer asset from.
 | 
			
		||||
    /// @param to Address to transfer asset to.
 | 
			
		||||
    /// @param amount Amount of asset to transfer.
 | 
			
		||||
    function transferFrom(
 | 
			
		||||
        bytes calldata assetData,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        onlyAuthorized
 | 
			
		||||
    {
 | 
			
		||||
        // Extract asset data fields.
 | 
			
		||||
        (
 | 
			
		||||
            address tokenAddress,
 | 
			
		||||
            address bridgeAddress,
 | 
			
		||||
            bytes memory bridgeData
 | 
			
		||||
        ) = abi.decode(
 | 
			
		||||
            assetData.sliceDestructive(4, assetData.length),
 | 
			
		||||
            (address, address, bytes)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Remember the balance of `to` before calling the bridge.
 | 
			
		||||
        uint256 balanceBefore = balanceOf(tokenAddress, to);
 | 
			
		||||
        // Call the bridge, who should transfer `amount` of `tokenAddress` to
 | 
			
		||||
        // `to`.
 | 
			
		||||
        bytes4 success = IERC20Bridge(bridgeAddress).bridgeTransferFrom(
 | 
			
		||||
            tokenAddress,
 | 
			
		||||
            from,
 | 
			
		||||
            to,
 | 
			
		||||
            amount,
 | 
			
		||||
            bridgeData
 | 
			
		||||
        );
 | 
			
		||||
        // Bridge must return the proxy ID to indicate success.
 | 
			
		||||
        require(success == PROXY_ID, "BRIDGE_FAILED");
 | 
			
		||||
        // Ensure that the balance of `to` has increased by at least `amount`.
 | 
			
		||||
        require(
 | 
			
		||||
            balanceBefore.safeAdd(amount) <= balanceOf(tokenAddress, to),
 | 
			
		||||
            "BRIDGE_UNDERPAY"
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets the proxy id associated with this asset proxy.
 | 
			
		||||
    /// @return proxyId The proxy id.
 | 
			
		||||
    function getProxyId()
 | 
			
		||||
        external
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes4 proxyId)
 | 
			
		||||
    {
 | 
			
		||||
        return PROXY_ID;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Retrieves the balance of `owner` for this asset.
 | 
			
		||||
    /// @return balance The balance of the ERC20 token being transferred by this
 | 
			
		||||
    ///         asset proxy.
 | 
			
		||||
    function balanceOf(bytes calldata assetData, address owner)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 balance)
 | 
			
		||||
    {
 | 
			
		||||
        (address tokenAddress) = abi.decode(
 | 
			
		||||
            assetData.sliceDestructive(4, assetData.length),
 | 
			
		||||
            (address)
 | 
			
		||||
        );
 | 
			
		||||
        return balanceOf(tokenAddress, owner);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Retrieves the balance of `owner` given an ERC20 address.
 | 
			
		||||
    /// @return balance The balance of the ERC20 token for `owner`.
 | 
			
		||||
    function balanceOf(address tokenAddress, address owner)
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 balance)
 | 
			
		||||
    {
 | 
			
		||||
        return IERC20Token(tokenAddress).balanceOf(owner);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										184
									
								
								contracts/asset-proxy/contracts/src/ERC20Proxy.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								contracts/asset-proxy/contracts/src/ERC20Proxy.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,184 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 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 "../archive/MixinAuthorizable.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract ERC20Proxy is
 | 
			
		||||
    MixinAuthorizable
 | 
			
		||||
{
 | 
			
		||||
    // Id of this proxy.
 | 
			
		||||
    bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC20Token(address)"));
 | 
			
		||||
 | 
			
		||||
    // solhint-disable-next-line payable-fallback
 | 
			
		||||
    function ()
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        assembly {
 | 
			
		||||
            // The first 4 bytes of calldata holds the function selector
 | 
			
		||||
            let selector := and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
 | 
			
		||||
            // `transferFrom` will be called with the following parameters:
 | 
			
		||||
            // assetData Encoded byte array.
 | 
			
		||||
            // from Address to transfer asset from.
 | 
			
		||||
            // to Address to transfer asset to.
 | 
			
		||||
            // amount Amount of asset to transfer.
 | 
			
		||||
            // bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
 | 
			
		||||
            if eq(selector, 0xa85e59e400000000000000000000000000000000000000000000000000000000) {
 | 
			
		||||
 | 
			
		||||
                // To lookup a value in a mapping, we load from the storage location keccak256(k, p),
 | 
			
		||||
                // where k is the key left padded to 32 bytes and p is the storage slot
 | 
			
		||||
                let start := mload(64)
 | 
			
		||||
                mstore(start, and(caller, 0xffffffffffffffffffffffffffffffffffffffff))
 | 
			
		||||
                mstore(add(start, 32), authorized_slot)
 | 
			
		||||
 | 
			
		||||
                // Revert if authorized[msg.sender] == false
 | 
			
		||||
                if iszero(sload(keccak256(start, 64))) {
 | 
			
		||||
                    // Revert with `Error("SENDER_NOT_AUTHORIZED")`
 | 
			
		||||
                    mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                    mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                    mstore(64, 0x0000001553454e4445525f4e4f545f415554484f52495a454400000000000000)
 | 
			
		||||
                    mstore(96, 0)
 | 
			
		||||
                    revert(0, 100)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // `transferFrom`.
 | 
			
		||||
                // The function is marked `external`, so no abi decodeding is done for
 | 
			
		||||
                // us. Instead, we expect the `calldata` memory to contain the
 | 
			
		||||
                // following:
 | 
			
		||||
                //
 | 
			
		||||
                // | Area     | Offset | Length  | Contents                            |
 | 
			
		||||
                // |----------|--------|---------|-------------------------------------|
 | 
			
		||||
                // | Header   | 0      | 4       | function selector                   |
 | 
			
		||||
                // | Params   |        | 4 * 32  | function parameters:                |
 | 
			
		||||
                // |          | 4      |         |   1. offset to assetData (*)        |
 | 
			
		||||
                // |          | 36     |         |   2. from                           |
 | 
			
		||||
                // |          | 68     |         |   3. to                             |
 | 
			
		||||
                // |          | 100    |         |   4. amount                         |
 | 
			
		||||
                // | Data     |        |         | assetData:                          |
 | 
			
		||||
                // |          | 132    | 32      | assetData Length                    |
 | 
			
		||||
                // |          | 164    | **      | assetData Contents                  |
 | 
			
		||||
                //
 | 
			
		||||
                // (*): offset is computed from start of function parameters, so offset
 | 
			
		||||
                //      by an additional 4 bytes in the calldata.
 | 
			
		||||
                //
 | 
			
		||||
                // (**): see table below to compute length of assetData Contents
 | 
			
		||||
                //
 | 
			
		||||
                // WARNING: The ABIv2 specification allows additional padding between
 | 
			
		||||
                //          the Params and Data section. This will result in a larger
 | 
			
		||||
                //          offset to assetData.
 | 
			
		||||
 | 
			
		||||
                // Asset data itself is encoded as follows:
 | 
			
		||||
                //
 | 
			
		||||
                // | Area     | Offset | Length  | Contents                            |
 | 
			
		||||
                // |----------|--------|---------|-------------------------------------|
 | 
			
		||||
                // | Header   | 0      | 4       | function selector                   |
 | 
			
		||||
                // | Params   |        | 1 * 32  | function parameters:                |
 | 
			
		||||
                // |          | 4      | 12 + 20 |   1. token address                  |
 | 
			
		||||
 | 
			
		||||
                // We construct calldata for the `token.transferFrom` ABI.
 | 
			
		||||
                // The layout of this calldata is in the table below.
 | 
			
		||||
                //
 | 
			
		||||
                // | Area     | Offset | Length  | Contents                            |
 | 
			
		||||
                // |----------|--------|---------|-------------------------------------|
 | 
			
		||||
                // | Header   | 0      | 4       | function selector                   |
 | 
			
		||||
                // | Params   |        | 3 * 32  | function parameters:                |
 | 
			
		||||
                // |          | 4      |         |   1. from                           |
 | 
			
		||||
                // |          | 36     |         |   2. to                             |
 | 
			
		||||
                // |          | 68     |         |   3. amount                         |
 | 
			
		||||
 | 
			
		||||
                /////// Read token address from calldata ///////
 | 
			
		||||
                // * The token address is stored in `assetData`.
 | 
			
		||||
                //
 | 
			
		||||
                // * The "offset to assetData" is stored at offset 4 in the calldata (table 1).
 | 
			
		||||
                //   [assetDataOffsetFromParams = calldataload(4)]
 | 
			
		||||
                //
 | 
			
		||||
                // * Notes that the "offset to assetData" is relative to the "Params" area of calldata;
 | 
			
		||||
                //   add 4 bytes to account for the length of the "Header" area (table 1).
 | 
			
		||||
                //   [assetDataOffsetFromHeader = assetDataOffsetFromParams + 4]
 | 
			
		||||
                //
 | 
			
		||||
                // * The "token address" is offset 32+4=36 bytes into "assetData" (tables 1 & 2).
 | 
			
		||||
                //   [tokenOffset = assetDataOffsetFromHeader + 36 = calldataload(4) + 4 + 36]
 | 
			
		||||
                let token := calldataload(add(calldataload(4), 40))
 | 
			
		||||
 | 
			
		||||
                /////// Setup Header Area ///////
 | 
			
		||||
                // This area holds the 4-byte `transferFrom` selector.
 | 
			
		||||
                // Any trailing data in transferFromSelector will be
 | 
			
		||||
                // overwritten in the next `mstore` call.
 | 
			
		||||
                mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
 | 
			
		||||
                /////// Setup Params Area ///////
 | 
			
		||||
                // We copy the fields `from`, `to` and `amount` in bulk
 | 
			
		||||
                // from our own calldata to the new calldata.
 | 
			
		||||
                calldatacopy(4, 36, 96)
 | 
			
		||||
 | 
			
		||||
                /////// Call `token.transferFrom` using the calldata ///////
 | 
			
		||||
                let success := call(
 | 
			
		||||
                    gas,            // forward all gas
 | 
			
		||||
                    token,          // call address of token contract
 | 
			
		||||
                    0,              // don't send any ETH
 | 
			
		||||
                    0,              // pointer to start of input
 | 
			
		||||
                    100,            // length of input
 | 
			
		||||
                    0,              // write output over input
 | 
			
		||||
                    32              // output size should be 32 bytes
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                /////// Check return data. ///////
 | 
			
		||||
                // If there is no return data, we assume the token incorrectly
 | 
			
		||||
                // does not return a bool. In this case we expect it to revert
 | 
			
		||||
                // on failure, which was handled above.
 | 
			
		||||
                // If the token does return data, we require that it is a single
 | 
			
		||||
                // nonzero 32 bytes value.
 | 
			
		||||
                // So the transfer succeeded if the call succeeded and either
 | 
			
		||||
                // returned nothing, or returned a non-zero 32 byte value.
 | 
			
		||||
                success := and(success, or(
 | 
			
		||||
                    iszero(returndatasize),
 | 
			
		||||
                    and(
 | 
			
		||||
                        eq(returndatasize, 32),
 | 
			
		||||
                        gt(mload(0), 0)
 | 
			
		||||
                    )
 | 
			
		||||
                ))
 | 
			
		||||
                if success {
 | 
			
		||||
                    return(0, 0)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Revert with `Error("TRANSFER_FAILED")`
 | 
			
		||||
                mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                mstore(64, 0x0000000f5452414e534645525f4641494c454400000000000000000000000000)
 | 
			
		||||
                mstore(96, 0)
 | 
			
		||||
                revert(0, 100)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Revert if undefined function is called
 | 
			
		||||
            revert(0, 0)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets the proxy id associated with the proxy address.
 | 
			
		||||
    /// @return Proxy id.
 | 
			
		||||
    function getProxyId()
 | 
			
		||||
        external
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes4)
 | 
			
		||||
    {
 | 
			
		||||
        return PROXY_ID;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										171
									
								
								contracts/asset-proxy/contracts/src/ERC721Proxy.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								contracts/asset-proxy/contracts/src/ERC721Proxy.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,171 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 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 "../archive/MixinAuthorizable.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract ERC721Proxy is
 | 
			
		||||
    MixinAuthorizable
 | 
			
		||||
{
 | 
			
		||||
    // Id of this proxy.
 | 
			
		||||
    bytes4 constant internal PROXY_ID = bytes4(keccak256("ERC721Token(address,uint256)"));
 | 
			
		||||
 | 
			
		||||
    // solhint-disable-next-line payable-fallback
 | 
			
		||||
    function ()
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        assembly {
 | 
			
		||||
            // The first 4 bytes of calldata holds the function selector
 | 
			
		||||
            let selector := and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
 | 
			
		||||
            // `transferFrom` will be called with the following parameters:
 | 
			
		||||
            // assetData Encoded byte array.
 | 
			
		||||
            // from Address to transfer asset from.
 | 
			
		||||
            // to Address to transfer asset to.
 | 
			
		||||
            // amount Amount of asset to transfer.
 | 
			
		||||
            // bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
 | 
			
		||||
            if eq(selector, 0xa85e59e400000000000000000000000000000000000000000000000000000000) {
 | 
			
		||||
 | 
			
		||||
                // To lookup a value in a mapping, we load from the storage location keccak256(k, p),
 | 
			
		||||
                // where k is the key left padded to 32 bytes and p is the storage slot
 | 
			
		||||
                let start := mload(64)
 | 
			
		||||
                mstore(start, and(caller, 0xffffffffffffffffffffffffffffffffffffffff))
 | 
			
		||||
                mstore(add(start, 32), authorized_slot)
 | 
			
		||||
 | 
			
		||||
                // Revert if authorized[msg.sender] == false
 | 
			
		||||
                if iszero(sload(keccak256(start, 64))) {
 | 
			
		||||
                    // Revert with `Error("SENDER_NOT_AUTHORIZED")`
 | 
			
		||||
                    mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                    mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                    mstore(64, 0x0000001553454e4445525f4e4f545f415554484f52495a454400000000000000)
 | 
			
		||||
                    mstore(96, 0)
 | 
			
		||||
                    revert(0, 100)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // `transferFrom`.
 | 
			
		||||
                // The function is marked `external`, so no abi decodeding is done for
 | 
			
		||||
                // us. Instead, we expect the `calldata` memory to contain the
 | 
			
		||||
                // following:
 | 
			
		||||
                //
 | 
			
		||||
                // | Area     | Offset | Length  | Contents                            |
 | 
			
		||||
                // |----------|--------|---------|-------------------------------------|
 | 
			
		||||
                // | Header   | 0      | 4       | function selector                   |
 | 
			
		||||
                // | Params   |        | 4 * 32  | function parameters:                |
 | 
			
		||||
                // |          | 4      |         |   1. offset to assetData (*)        |
 | 
			
		||||
                // |          | 36     |         |   2. from                           |
 | 
			
		||||
                // |          | 68     |         |   3. to                             |
 | 
			
		||||
                // |          | 100    |         |   4. amount                         |
 | 
			
		||||
                // | Data     |        |         | assetData:                          |
 | 
			
		||||
                // |          | 132    | 32      | assetData Length                    |
 | 
			
		||||
                // |          | 164    | **      | assetData Contents                  |
 | 
			
		||||
                //
 | 
			
		||||
                // (*): offset is computed from start of function parameters, so offset
 | 
			
		||||
                //      by an additional 4 bytes in the calldata.
 | 
			
		||||
                //
 | 
			
		||||
                // (**): see table below to compute length of assetData Contents
 | 
			
		||||
                //
 | 
			
		||||
                // WARNING: The ABIv2 specification allows additional padding between
 | 
			
		||||
                //          the Params and Data section. This will result in a larger
 | 
			
		||||
                //          offset to assetData.
 | 
			
		||||
 | 
			
		||||
                // Asset data itself is encoded as follows:
 | 
			
		||||
                //
 | 
			
		||||
                // | Area     | Offset | Length  | Contents                            |
 | 
			
		||||
                // |----------|--------|---------|-------------------------------------|
 | 
			
		||||
                // | Header   | 0      | 4       | function selector                   |
 | 
			
		||||
                // | Params   |        | 2 * 32  | function parameters:                |
 | 
			
		||||
                // |          | 4      | 12 + 20 |   1. token address                  |
 | 
			
		||||
                // |          | 36     |         |   2. tokenId                        |
 | 
			
		||||
 | 
			
		||||
                // We construct calldata for the `token.transferFrom` ABI.
 | 
			
		||||
                // The layout of this calldata is in the table below.
 | 
			
		||||
                //
 | 
			
		||||
                // | Area     | Offset | Length  | Contents                            |
 | 
			
		||||
                // |----------|--------|---------|-------------------------------------|
 | 
			
		||||
                // | Header   | 0      | 4       | function selector                   |
 | 
			
		||||
                // | Params   |        | 3 * 32  | function parameters:                |
 | 
			
		||||
                // |          | 4      |         |   1. from                           |
 | 
			
		||||
                // |          | 36     |         |   2. to                             |
 | 
			
		||||
                // |          | 68     |         |   3. tokenId                        |
 | 
			
		||||
 | 
			
		||||
                // There exists only 1 of each token.
 | 
			
		||||
                // require(amount == 1, "INVALID_AMOUNT")
 | 
			
		||||
                if sub(calldataload(100), 1) {
 | 
			
		||||
                    // Revert with `Error("INVALID_AMOUNT")`
 | 
			
		||||
                    mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                    mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                    mstore(64, 0x0000000e494e56414c49445f414d4f554e540000000000000000000000000000)
 | 
			
		||||
                    mstore(96, 0)
 | 
			
		||||
                    revert(0, 100)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                /////// Setup Header Area ///////
 | 
			
		||||
                // This area holds the 4-byte `transferFrom` selector.
 | 
			
		||||
                // Any trailing data in transferFromSelector will be
 | 
			
		||||
                // overwritten in the next `mstore` call.
 | 
			
		||||
                mstore(0, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
 | 
			
		||||
                /////// Setup Params Area ///////
 | 
			
		||||
                // We copy the fields `from` and `to` in bulk
 | 
			
		||||
                // from our own calldata to the new calldata.
 | 
			
		||||
                calldatacopy(4, 36, 64)
 | 
			
		||||
 | 
			
		||||
                // Copy `tokenId` field from our own calldata to the new calldata.
 | 
			
		||||
                let assetDataOffset := calldataload(4)
 | 
			
		||||
                calldatacopy(68, add(assetDataOffset, 72), 32)
 | 
			
		||||
 | 
			
		||||
                /////// Call `token.transferFrom` using the calldata ///////
 | 
			
		||||
                let token := calldataload(add(assetDataOffset, 40))
 | 
			
		||||
                let success := call(
 | 
			
		||||
                    gas,            // forward all gas
 | 
			
		||||
                    token,          // call address of token contract
 | 
			
		||||
                    0,              // don't send any ETH
 | 
			
		||||
                    0,              // pointer to start of input
 | 
			
		||||
                    100,            // length of input
 | 
			
		||||
                    0,              // write output to null
 | 
			
		||||
                    0               // output size is 0 bytes
 | 
			
		||||
                )
 | 
			
		||||
                if success {
 | 
			
		||||
                    return(0, 0)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Revert with `Error("TRANSFER_FAILED")`
 | 
			
		||||
                mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                mstore(64, 0x0000000f5452414e534645525f4641494c454400000000000000000000000000)
 | 
			
		||||
                mstore(96, 0)
 | 
			
		||||
                revert(0, 100)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Revert if undefined function is called
 | 
			
		||||
            revert(0, 0)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets the proxy id associated with the proxy address.
 | 
			
		||||
    /// @return Proxy id.
 | 
			
		||||
    function getProxyId()
 | 
			
		||||
        external
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes4)
 | 
			
		||||
    {
 | 
			
		||||
        return PROXY_ID;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										335
									
								
								contracts/asset-proxy/contracts/src/MultiAssetProxy.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										335
									
								
								contracts/asset-proxy/contracts/src/MultiAssetProxy.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,335 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 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 "../archive/MixinAssetProxyDispatcher.sol";
 | 
			
		||||
import "../archive/MixinAuthorizable.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract MultiAssetProxy is
 | 
			
		||||
    MixinAssetProxyDispatcher,
 | 
			
		||||
    MixinAuthorizable
 | 
			
		||||
{
 | 
			
		||||
    // Id of this proxy.
 | 
			
		||||
    bytes4 constant internal PROXY_ID = bytes4(keccak256("MultiAsset(uint256[],bytes[])"));
 | 
			
		||||
 | 
			
		||||
    // solhint-disable-next-line payable-fallback
 | 
			
		||||
    function ()
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        // NOTE: The below assembly assumes that clients do some input validation and that the input is properly encoded according to the AbiV2 specification.
 | 
			
		||||
        // It is technically possible for inputs with very large lengths and offsets to cause overflows. However, this would make the calldata prohibitively
 | 
			
		||||
        // expensive and we therefore do not check for overflows in these scenarios.
 | 
			
		||||
        assembly {
 | 
			
		||||
            // The first 4 bytes of calldata holds the function selector
 | 
			
		||||
            let selector := and(calldataload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
 | 
			
		||||
            // `transferFrom` will be called with the following parameters:
 | 
			
		||||
            // assetData Encoded byte array.
 | 
			
		||||
            // from Address to transfer asset from.
 | 
			
		||||
            // to Address to transfer asset to.
 | 
			
		||||
            // amount Amount of asset to transfer.
 | 
			
		||||
            // bytes4(keccak256("transferFrom(bytes,address,address,uint256)")) = 0xa85e59e4
 | 
			
		||||
            if eq(selector, 0xa85e59e400000000000000000000000000000000000000000000000000000000) {
 | 
			
		||||
 | 
			
		||||
                // To lookup a value in a mapping, we load from the storage location keccak256(k, p),
 | 
			
		||||
                // where k is the key left padded to 32 bytes and p is the storage slot
 | 
			
		||||
                mstore(0, caller)
 | 
			
		||||
                mstore(32, authorized_slot)
 | 
			
		||||
 | 
			
		||||
                // Revert if authorized[msg.sender] == false
 | 
			
		||||
                if iszero(sload(keccak256(0, 64))) {
 | 
			
		||||
                    // Revert with `Error("SENDER_NOT_AUTHORIZED")`
 | 
			
		||||
                    mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                    mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                    mstore(64, 0x0000001553454e4445525f4e4f545f415554484f52495a454400000000000000)
 | 
			
		||||
                    mstore(96, 0)
 | 
			
		||||
                    revert(0, 100)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // `transferFrom`.
 | 
			
		||||
                // The function is marked `external`, so no abi decoding is done for
 | 
			
		||||
                // us. Instead, we expect the `calldata` memory to contain the
 | 
			
		||||
                // following:
 | 
			
		||||
                //
 | 
			
		||||
                // | Area     | Offset | Length  | Contents                            |
 | 
			
		||||
                // |----------|--------|---------|-------------------------------------|
 | 
			
		||||
                // | Header   | 0      | 4       | function selector                   |
 | 
			
		||||
                // | Params   |        | 4 * 32  | function parameters:                |
 | 
			
		||||
                // |          | 4      |         |   1. offset to assetData (*)        |
 | 
			
		||||
                // |          | 36     |         |   2. from                           |
 | 
			
		||||
                // |          | 68     |         |   3. to                             |
 | 
			
		||||
                // |          | 100    |         |   4. amount                         |
 | 
			
		||||
                // | Data     |        |         | assetData:                          |
 | 
			
		||||
                // |          | 132    | 32      | assetData Length                    |
 | 
			
		||||
                // |          | 164    | **      | assetData Contents                  |
 | 
			
		||||
                //
 | 
			
		||||
                // (*): offset is computed from start of function parameters, so offset
 | 
			
		||||
                //      by an additional 4 bytes in the calldata.
 | 
			
		||||
                //
 | 
			
		||||
                // (**): see table below to compute length of assetData Contents
 | 
			
		||||
                //
 | 
			
		||||
                // WARNING: The ABIv2 specification allows additional padding between
 | 
			
		||||
                //          the Params and Data section. This will result in a larger
 | 
			
		||||
                //          offset to assetData.
 | 
			
		||||
 | 
			
		||||
                // Load offset to `assetData`
 | 
			
		||||
                let assetDataOffset := add(calldataload(4), 4)
 | 
			
		||||
 | 
			
		||||
                // Load length in bytes of `assetData`
 | 
			
		||||
                let assetDataLength := calldataload(assetDataOffset)
 | 
			
		||||
 | 
			
		||||
                // Asset data itself is encoded as follows:
 | 
			
		||||
                //
 | 
			
		||||
                // | Area     | Offset      | Length  | Contents                            |
 | 
			
		||||
                // |----------|-------------|---------|-------------------------------------|
 | 
			
		||||
                // | Header   | 0           | 4       | assetProxyId                        |
 | 
			
		||||
                // | Params   |             | 2 * 32  | function parameters:                |
 | 
			
		||||
                // |          | 4           |         |   1. offset to amounts (*)          |
 | 
			
		||||
                // |          | 36          |         |   2. offset to nestedAssetData (*)  |
 | 
			
		||||
                // | Data     |             |         | amounts:                            |
 | 
			
		||||
                // |          | 68          | 32      | amounts Length                      |
 | 
			
		||||
                // |          | 100         | a       | amounts Contents                    |
 | 
			
		||||
                // |          |             |         | nestedAssetData:                    |
 | 
			
		||||
                // |          | 100 + a     | 32      | nestedAssetData Length              |
 | 
			
		||||
                // |          | 132 + a     | b       | nestedAssetData Contents (offsets)  |
 | 
			
		||||
                // |          | 132 + a + b |         | nestedAssetData[0, ..., len]        |
 | 
			
		||||
 | 
			
		||||
                // Assert that the length of asset data:
 | 
			
		||||
                // 1. Must be at least 68 bytes (see table above)
 | 
			
		||||
                // 2. Must be a multiple of 32 (excluding the 4-byte selector)
 | 
			
		||||
                if or(lt(assetDataLength, 68), mod(sub(assetDataLength, 4), 32)) {
 | 
			
		||||
                    // Revert with `Error("INVALID_ASSET_DATA_LENGTH")`
 | 
			
		||||
                    mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                    mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                    mstore(64, 0x00000019494e56414c49445f41535345545f444154415f4c454e475448000000)
 | 
			
		||||
                    mstore(96, 0)
 | 
			
		||||
                    revert(0, 100)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // End of asset data in calldata
 | 
			
		||||
                // assetDataOffset
 | 
			
		||||
                // + 32 (assetData len)
 | 
			
		||||
                let assetDataEnd := add(assetDataOffset, add(assetDataLength, 32))
 | 
			
		||||
                if gt(assetDataEnd, calldatasize()) {
 | 
			
		||||
                    // Revert with `Error("INVALID_ASSET_DATA_END")`
 | 
			
		||||
                    mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                    mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                    mstore(64, 0x00000016494e56414c49445f41535345545f444154415f454e44000000000000)
 | 
			
		||||
                    mstore(96, 0)
 | 
			
		||||
                    revert(0, 100)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // In order to find the offset to `amounts`, we must add:
 | 
			
		||||
                // assetDataOffset
 | 
			
		||||
                // + 32 (assetData len)
 | 
			
		||||
                // + 4 (assetProxyId)
 | 
			
		||||
                let amountsOffset := calldataload(add(assetDataOffset, 36))
 | 
			
		||||
 | 
			
		||||
                // In order to find the offset to `nestedAssetData`, we must add:
 | 
			
		||||
                // assetDataOffset
 | 
			
		||||
                // + 32 (assetData len)
 | 
			
		||||
                // + 4 (assetProxyId)
 | 
			
		||||
                // + 32 (amounts offset)
 | 
			
		||||
                let nestedAssetDataOffset := calldataload(add(assetDataOffset, 68))
 | 
			
		||||
 | 
			
		||||
                // In order to find the start of the `amounts` contents, we must add:
 | 
			
		||||
                // assetDataOffset
 | 
			
		||||
                // + 32 (assetData len)
 | 
			
		||||
                // + 4 (assetProxyId)
 | 
			
		||||
                // + amountsOffset
 | 
			
		||||
                // + 32 (amounts len)
 | 
			
		||||
                let amountsContentsStart := add(assetDataOffset, add(amountsOffset, 68))
 | 
			
		||||
 | 
			
		||||
                // Load number of elements in `amounts`
 | 
			
		||||
                let amountsLen := calldataload(sub(amountsContentsStart, 32))
 | 
			
		||||
 | 
			
		||||
                // In order to find the start of the `nestedAssetData` contents, we must add:
 | 
			
		||||
                // assetDataOffset
 | 
			
		||||
                // + 32 (assetData len)
 | 
			
		||||
                // + 4 (assetProxyId)
 | 
			
		||||
                // + nestedAssetDataOffset
 | 
			
		||||
                // + 32 (nestedAssetData len)
 | 
			
		||||
                let nestedAssetDataContentsStart := add(assetDataOffset, add(nestedAssetDataOffset, 68))
 | 
			
		||||
 | 
			
		||||
                // Load number of elements in `nestedAssetData`
 | 
			
		||||
                let nestedAssetDataLen := calldataload(sub(nestedAssetDataContentsStart, 32))
 | 
			
		||||
 | 
			
		||||
                // Revert if number of elements in `amounts` differs from number of elements in `nestedAssetData`
 | 
			
		||||
                if sub(amountsLen, nestedAssetDataLen) {
 | 
			
		||||
                    // Revert with `Error("LENGTH_MISMATCH")`
 | 
			
		||||
                    mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                    mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                    mstore(64, 0x0000000f4c454e4754485f4d49534d4154434800000000000000000000000000)
 | 
			
		||||
                    mstore(96, 0)
 | 
			
		||||
                    revert(0, 100)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Copy `transferFrom` selector, offset to `assetData`, `from`, and `to` from calldata to memory
 | 
			
		||||
                calldatacopy(
 | 
			
		||||
                    0,   // memory can safely be overwritten from beginning
 | 
			
		||||
                    0,   // start of calldata
 | 
			
		||||
                    100  // length of selector (4) and 3 params (32 * 3)
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                // Overwrite existing offset to `assetData` with our own
 | 
			
		||||
                mstore(4, 128)
 | 
			
		||||
 | 
			
		||||
                // Load `amount`
 | 
			
		||||
                let amount := calldataload(100)
 | 
			
		||||
 | 
			
		||||
                // Calculate number of bytes in `amounts` contents
 | 
			
		||||
                let amountsByteLen := mul(amountsLen, 32)
 | 
			
		||||
 | 
			
		||||
                // Initialize `assetProxyId` and `assetProxy` to 0
 | 
			
		||||
                let assetProxyId := 0
 | 
			
		||||
                let assetProxy := 0
 | 
			
		||||
 | 
			
		||||
                // Loop through `amounts` and `nestedAssetData`, calling `transferFrom` for each respective element
 | 
			
		||||
                for {let i := 0} lt(i, amountsByteLen) {i := add(i, 32)} {
 | 
			
		||||
 | 
			
		||||
                    // Calculate the total amount
 | 
			
		||||
                    let amountsElement := calldataload(add(amountsContentsStart, i))
 | 
			
		||||
                    let totalAmount := mul(amountsElement, amount)
 | 
			
		||||
 | 
			
		||||
                    // Revert if `amount` != 0 and multiplication resulted in an overflow
 | 
			
		||||
                    if iszero(or(
 | 
			
		||||
                        iszero(amount),
 | 
			
		||||
                        eq(div(totalAmount, amount), amountsElement)
 | 
			
		||||
                    )) {
 | 
			
		||||
                        // Revert with `Error("UINT256_OVERFLOW")`
 | 
			
		||||
                        mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                        mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                        mstore(64, 0x0000001055494e543235365f4f564552464c4f57000000000000000000000000)
 | 
			
		||||
                        mstore(96, 0)
 | 
			
		||||
                        revert(0, 100)
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Write `totalAmount` to memory
 | 
			
		||||
                    mstore(100, totalAmount)
 | 
			
		||||
 | 
			
		||||
                    // Load offset to `nestedAssetData[i]`
 | 
			
		||||
                    let nestedAssetDataElementOffset := calldataload(add(nestedAssetDataContentsStart, i))
 | 
			
		||||
 | 
			
		||||
                    // In order to find the start of the `nestedAssetData[i]` contents, we must add:
 | 
			
		||||
                    // assetDataOffset
 | 
			
		||||
                    // + 32 (assetData len)
 | 
			
		||||
                    // + 4 (assetProxyId)
 | 
			
		||||
                    // + nestedAssetDataOffset
 | 
			
		||||
                    // + 32 (nestedAssetData len)
 | 
			
		||||
                    // + nestedAssetDataElementOffset
 | 
			
		||||
                    // + 32 (nestedAssetDataElement len)
 | 
			
		||||
                    let nestedAssetDataElementContentsStart := add(
 | 
			
		||||
                        assetDataOffset,
 | 
			
		||||
                        add(
 | 
			
		||||
                            nestedAssetDataOffset,
 | 
			
		||||
                            add(nestedAssetDataElementOffset, 100)
 | 
			
		||||
                        )
 | 
			
		||||
                    )
 | 
			
		||||
 | 
			
		||||
                    // Load length of `nestedAssetData[i]`
 | 
			
		||||
                    let nestedAssetDataElementLenStart := sub(nestedAssetDataElementContentsStart, 32)
 | 
			
		||||
                    let nestedAssetDataElementLen := calldataload(nestedAssetDataElementLenStart)
 | 
			
		||||
 | 
			
		||||
                    // Revert if the `nestedAssetData` does not contain a 4 byte `assetProxyId`
 | 
			
		||||
                    if lt(nestedAssetDataElementLen, 4) {
 | 
			
		||||
                        // Revert with `Error("LENGTH_GREATER_THAN_3_REQUIRED")`
 | 
			
		||||
                        mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                        mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                        mstore(64, 0x0000001e4c454e4754485f475245415445525f5448414e5f335f524551554952)
 | 
			
		||||
                        mstore(96, 0x4544000000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                        revert(0, 100)
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Load AssetProxy id
 | 
			
		||||
                    let currentAssetProxyId := and(
 | 
			
		||||
                        calldataload(nestedAssetDataElementContentsStart),
 | 
			
		||||
                        0xffffffff00000000000000000000000000000000000000000000000000000000
 | 
			
		||||
                    )
 | 
			
		||||
 | 
			
		||||
                    // Only load `assetProxy` if `currentAssetProxyId` does not equal `assetProxyId`
 | 
			
		||||
                    // We do not need to check if `currentAssetProxyId` is 0 since `assetProxy` is also initialized to 0
 | 
			
		||||
                    if sub(currentAssetProxyId, assetProxyId) {
 | 
			
		||||
                        // Update `assetProxyId`
 | 
			
		||||
                        assetProxyId := currentAssetProxyId
 | 
			
		||||
                        // To lookup a value in a mapping, we load from the storage location keccak256(k, p),
 | 
			
		||||
                        // where k is the key left padded to 32 bytes and p is the storage slot
 | 
			
		||||
                        mstore(132, assetProxyId)
 | 
			
		||||
                        mstore(164, assetProxies_slot)
 | 
			
		||||
                        assetProxy := sload(keccak256(132, 64))
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Revert if AssetProxy with given id does not exist
 | 
			
		||||
                    if iszero(assetProxy) {
 | 
			
		||||
                        // Revert with `Error("ASSET_PROXY_DOES_NOT_EXIST")`
 | 
			
		||||
                        mstore(0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                        mstore(32, 0x0000002000000000000000000000000000000000000000000000000000000000)
 | 
			
		||||
                        mstore(64, 0x0000001a41535345545f50524f58595f444f45535f4e4f545f45584953540000)
 | 
			
		||||
                        mstore(96, 0)
 | 
			
		||||
                        revert(0, 100)
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Copy `nestedAssetData[i]` from calldata to memory
 | 
			
		||||
                    calldatacopy(
 | 
			
		||||
                        132,                                // memory slot after `amounts[i]`
 | 
			
		||||
                        nestedAssetDataElementLenStart,     // location of `nestedAssetData[i]` in calldata
 | 
			
		||||
                        add(nestedAssetDataElementLen, 32)  // `nestedAssetData[i].length` plus 32 byte length
 | 
			
		||||
                    )
 | 
			
		||||
 | 
			
		||||
                    // call `assetProxy.transferFrom`
 | 
			
		||||
                    let success := call(
 | 
			
		||||
                        gas,                                    // forward all gas
 | 
			
		||||
                        assetProxy,                             // call address of asset proxy
 | 
			
		||||
                        0,                                      // don't send any ETH
 | 
			
		||||
                        0,                                      // pointer to start of input
 | 
			
		||||
                        add(164, nestedAssetDataElementLen),    // length of input
 | 
			
		||||
                        0,                                      // write output over memory that won't be reused
 | 
			
		||||
                        0                                       // don't copy output to memory
 | 
			
		||||
                    )
 | 
			
		||||
 | 
			
		||||
                    // Revert with reason given by AssetProxy if `transferFrom` call failed
 | 
			
		||||
                    if iszero(success) {
 | 
			
		||||
                        returndatacopy(
 | 
			
		||||
                            0,                // copy to memory at 0
 | 
			
		||||
                            0,                // copy from return data at 0
 | 
			
		||||
                            returndatasize()  // copy all return data
 | 
			
		||||
                        )
 | 
			
		||||
                        revert(0, returndatasize())
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Return if no `transferFrom` calls reverted
 | 
			
		||||
                return(0, 0)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Revert if undefined function is called
 | 
			
		||||
            revert(0, 0)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets the proxy id associated with the proxy address.
 | 
			
		||||
    /// @return Proxy id.
 | 
			
		||||
    function getProxyId()
 | 
			
		||||
        external
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes4)
 | 
			
		||||
    {
 | 
			
		||||
        return PROXY_ID;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										83
									
								
								contracts/asset-proxy/contracts/src/StaticCallProxy.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								contracts/asset-proxy/contracts/src/StaticCallProxy.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 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/LibBytes.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable no-unused-vars
 | 
			
		||||
contract StaticCallProxy {
 | 
			
		||||
 | 
			
		||||
    using LibBytes for bytes;
 | 
			
		||||
 | 
			
		||||
    // Id of this proxy.
 | 
			
		||||
    bytes4 constant internal PROXY_ID = bytes4(keccak256("StaticCall(address,bytes,bytes32)"));
 | 
			
		||||
 | 
			
		||||
    /// @dev Makes a staticcall to a target address and verifies that the data returned matches the expected return data.
 | 
			
		||||
    /// @param assetData Byte array encoded with staticCallTarget, staticCallData, and expectedCallResultHash
 | 
			
		||||
    /// @param from This value is ignored.
 | 
			
		||||
    /// @param to This value is ignored.
 | 
			
		||||
    /// @param amount This value is ignored.
 | 
			
		||||
    function transferFrom(
 | 
			
		||||
        bytes calldata assetData,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
    {
 | 
			
		||||
        // Decode params from `assetData`
 | 
			
		||||
        (
 | 
			
		||||
            address staticCallTarget,
 | 
			
		||||
            bytes memory staticCallData,
 | 
			
		||||
            bytes32 expectedReturnDataHash
 | 
			
		||||
        ) = abi.decode(
 | 
			
		||||
            assetData.sliceDestructive(4, assetData.length),
 | 
			
		||||
            (address, bytes, bytes32)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Execute staticcall
 | 
			
		||||
        (bool success, bytes memory returnData) = staticCallTarget.staticcall(staticCallData);
 | 
			
		||||
 | 
			
		||||
        // Revert with returned data if staticcall is unsuccessful
 | 
			
		||||
        if (!success) {
 | 
			
		||||
            assembly {
 | 
			
		||||
                revert(add(returnData, 32), mload(returnData))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Revert if hash of return data is not as expected
 | 
			
		||||
        bytes32 returnDataHash = keccak256(returnData);
 | 
			
		||||
        require(
 | 
			
		||||
            expectedReturnDataHash == returnDataHash,
 | 
			
		||||
            "UNEXPECTED_STATIC_CALL_RESULT"
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets the proxy id associated with the proxy address.
 | 
			
		||||
    /// @return Proxy id.
 | 
			
		||||
    function getProxyId()
 | 
			
		||||
        external
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes4)
 | 
			
		||||
    {
 | 
			
		||||
        return PROXY_ID;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										103
									
								
								contracts/asset-proxy/contracts/src/bridges/BalancerBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								contracts/asset-proxy/contracts/src/bridges/BalancerBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,103 @@
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.5.9;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
			
		||||
import "../interfaces/IERC20Bridge.sol";
 | 
			
		||||
import "../interfaces/IBalancerPool.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract BalancerBridge is
 | 
			
		||||
    IERC20Bridge,
 | 
			
		||||
    IWallet,
 | 
			
		||||
    DeploymentConstants
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
 | 
			
		||||
    ///      `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
 | 
			
		||||
    ///      token encoded in the bridge data, then transfers the bought
 | 
			
		||||
    ///      tokens to `to`.
 | 
			
		||||
    /// @param toTokenAddress The token to buy and transfer to `to`.
 | 
			
		||||
    /// @param from The maker (this contract).
 | 
			
		||||
    /// @param to The recipient of the bought tokens.
 | 
			
		||||
    /// @param amount Minimum amount of `toTokenAddress` tokens to buy.
 | 
			
		||||
    /// @param bridgeData The abi-encoded addresses of the "from" token and Balancer pool.
 | 
			
		||||
    /// @return success The magic bytes if successful.
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address toTokenAddress,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        // Decode the bridge data.
 | 
			
		||||
        (address fromTokenAddress, address poolAddress) = abi.decode(
 | 
			
		||||
            bridgeData,
 | 
			
		||||
            (address, address)
 | 
			
		||||
        );
 | 
			
		||||
        require(toTokenAddress != fromTokenAddress, "BalancerBridge/INVALID_PAIR");
 | 
			
		||||
 | 
			
		||||
        uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
 | 
			
		||||
        // Grant an allowance to the exchange to spend `fromTokenAddress` token.
 | 
			
		||||
        LibERC20Token.approveIfBelow(fromTokenAddress, poolAddress, fromTokenBalance);
 | 
			
		||||
 | 
			
		||||
        // Sell all of this contract's `fromTokenAddress` token balance.
 | 
			
		||||
        (uint256 boughtAmount,) = IBalancerPool(poolAddress).swapExactAmountIn(
 | 
			
		||||
            fromTokenAddress, // tokenIn
 | 
			
		||||
            fromTokenBalance, // tokenAmountIn
 | 
			
		||||
            toTokenAddress,   // tokenOut
 | 
			
		||||
            amount,           // minAmountOut
 | 
			
		||||
            uint256(-1)       // maxPrice
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Transfer the converted `toToken`s to `to`.
 | 
			
		||||
        LibERC20Token.transfer(toTokenAddress, to, boughtAmount);
 | 
			
		||||
 | 
			
		||||
        emit ERC20BridgeTransfer(
 | 
			
		||||
            fromTokenAddress,
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            fromTokenBalance,
 | 
			
		||||
            boughtAmount,
 | 
			
		||||
            from,
 | 
			
		||||
            to
 | 
			
		||||
        );
 | 
			
		||||
        return BRIDGE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
 | 
			
		||||
    ///      and sign for itself in orders. Always succeeds.
 | 
			
		||||
    /// @return magicValue Magic success bytes, always.
 | 
			
		||||
    function isValidSignature(
 | 
			
		||||
        bytes32,
 | 
			
		||||
        bytes calldata
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes4 magicValue)
 | 
			
		||||
    {
 | 
			
		||||
        return LEGACY_WALLET_MAGIC_VALUE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										144
									
								
								contracts/asset-proxy/contracts/src/bridges/BancorBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								contracts/asset-proxy/contracts/src/bridges/BancorBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,144 @@
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.5.9;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
			
		||||
import "../interfaces/IERC20Bridge.sol";
 | 
			
		||||
import "../interfaces/IBancorNetwork.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract BancorBridge is
 | 
			
		||||
    IERC20Bridge,
 | 
			
		||||
    IWallet,
 | 
			
		||||
    DeploymentConstants
 | 
			
		||||
{
 | 
			
		||||
    struct TransferState {
 | 
			
		||||
        address bancorNetworkAddress;
 | 
			
		||||
        address[] path;
 | 
			
		||||
        IEtherToken weth;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Bancor ETH pseudo-address.
 | 
			
		||||
    address constant public BANCOR_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
 | 
			
		||||
 | 
			
		||||
    // solhint-disable no-empty-blocks
 | 
			
		||||
    /// @dev Payable fallback to receive ETH from Bancor/WETH.
 | 
			
		||||
    function ()
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
    {
 | 
			
		||||
        // Poor man's receive in 0.5.9
 | 
			
		||||
        require(msg.data.length == 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
 | 
			
		||||
    ///      `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
 | 
			
		||||
    ///      token encoded in the bridge data, then transfers the bought
 | 
			
		||||
    ///      tokens to `to`.
 | 
			
		||||
    /// @param toTokenAddress The token to buy and transfer to `to`.
 | 
			
		||||
    /// @param from The maker (this contract).
 | 
			
		||||
    /// @param to The recipient of the bought tokens.
 | 
			
		||||
    /// @param amount Minimum amount of `toTokenAddress` tokens to buy.
 | 
			
		||||
    /// @param bridgeData The abi-encoded conversion path addresses and Bancor network address
 | 
			
		||||
    /// @return success The magic bytes if successful.
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address toTokenAddress,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        // hold variables to get around stack depth limitations
 | 
			
		||||
        TransferState memory state;
 | 
			
		||||
        // Decode the bridge data.
 | 
			
		||||
        (
 | 
			
		||||
            state.path,
 | 
			
		||||
            state.bancorNetworkAddress
 | 
			
		||||
        // solhint-disable indent
 | 
			
		||||
        ) = abi.decode(bridgeData, (address[], address));
 | 
			
		||||
        // solhint-enable indent
 | 
			
		||||
        state.weth = IEtherToken(_getWethAddress());
 | 
			
		||||
 | 
			
		||||
        require(state.path.length >= 2, "BancorBridge/PATH_LENGTH_MUST_BE_GREATER_THAN_TWO");
 | 
			
		||||
 | 
			
		||||
        // Grant an allowance to the Bancor Network to spend `fromTokenAddress` token.
 | 
			
		||||
        uint256 fromTokenBalance;
 | 
			
		||||
        uint256 payableAmount = 0;
 | 
			
		||||
        // If it's ETH in the path then withdraw from WETH
 | 
			
		||||
        // The Bancor path will have ETH as the 0xeee address
 | 
			
		||||
        // Bancor expects to be paid in ETH not WETH
 | 
			
		||||
        if (state.path[0] == BANCOR_ETH_ADDRESS) {
 | 
			
		||||
            fromTokenBalance = state.weth.balanceOf(address(this));
 | 
			
		||||
            state.weth.withdraw(fromTokenBalance);
 | 
			
		||||
            payableAmount = fromTokenBalance;
 | 
			
		||||
        } else {
 | 
			
		||||
            fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this));
 | 
			
		||||
            LibERC20Token.approveIfBelow(state.path[0], state.bancorNetworkAddress, fromTokenBalance);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Convert the tokens
 | 
			
		||||
        uint256 boughtAmount = IBancorNetwork(state.bancorNetworkAddress).convertByPath.value(payableAmount)(
 | 
			
		||||
            state.path, // path originating with source token and terminating in destination token
 | 
			
		||||
            fromTokenBalance, // amount of source token to trade
 | 
			
		||||
            amount, // minimum amount of destination token expected to receive
 | 
			
		||||
            state.path[state.path.length-1] == BANCOR_ETH_ADDRESS ? address(this) : to, // beneficiary
 | 
			
		||||
            address(0), // affiliateAccount; no fee paid
 | 
			
		||||
            0 // affiliateFee; no fee paid
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        if (state.path[state.path.length-1] == BANCOR_ETH_ADDRESS) {
 | 
			
		||||
            state.weth.deposit.value(boughtAmount)();
 | 
			
		||||
            state.weth.transfer(to, boughtAmount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        emit ERC20BridgeTransfer(
 | 
			
		||||
            state.path[0] == BANCOR_ETH_ADDRESS ? address(state.weth) : state.path[0],
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            fromTokenBalance,
 | 
			
		||||
            boughtAmount,
 | 
			
		||||
            from,
 | 
			
		||||
            to
 | 
			
		||||
        );
 | 
			
		||||
        return BRIDGE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
 | 
			
		||||
    ///      and sign for itself in orders. Always succeeds.
 | 
			
		||||
    /// @return magicValue Magic success bytes, always.
 | 
			
		||||
    function isValidSignature(
 | 
			
		||||
        bytes32,
 | 
			
		||||
        bytes calldata
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes4 magicValue)
 | 
			
		||||
    {
 | 
			
		||||
        return LEGACY_WALLET_MAGIC_VALUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										75
									
								
								contracts/asset-proxy/contracts/src/bridges/ChaiBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								contracts/asset-proxy/contracts/src/bridges/ChaiBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "../interfaces/IERC20Bridge.sol";
 | 
			
		||||
import "../interfaces/IChai.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable space-after-comma
 | 
			
		||||
contract ChaiBridge is
 | 
			
		||||
    IERC20Bridge,
 | 
			
		||||
    DeploymentConstants
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Withdraws `amount` of `from` address's Dai from the Chai contract.
 | 
			
		||||
    ///      Transfers `amount` of Dai to `to` address.
 | 
			
		||||
    /// @param from Address to transfer asset from.
 | 
			
		||||
    /// @param to Address to transfer asset to.
 | 
			
		||||
    /// @param amount Amount of asset to transfer.
 | 
			
		||||
    /// @return success The magic bytes `0xdc1600f3` if successful.
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address /* tokenAddress */,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata /* bridgeData */
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        // Ensure that only the `ERC20BridgeProxy` can call this function.
 | 
			
		||||
        require(
 | 
			
		||||
            msg.sender == _getERC20BridgeProxyAddress(),
 | 
			
		||||
            "ChaiBridge/ONLY_CALLABLE_BY_ERC20_BRIDGE_PROXY"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Withdraw `from` address's Dai.
 | 
			
		||||
        // NOTE: This contract must be approved to spend Chai on behalf of `from`.
 | 
			
		||||
        bytes memory drawCalldata = abi.encodeWithSelector(
 | 
			
		||||
            IChai(address(0)).draw.selector,
 | 
			
		||||
            from,
 | 
			
		||||
            amount
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        (bool success,) = _getChaiAddress().call(drawCalldata);
 | 
			
		||||
        require(
 | 
			
		||||
            success,
 | 
			
		||||
            "ChaiBridge/DRAW_DAI_FAILED"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Transfer Dai to `to`
 | 
			
		||||
        // This will never fail if the `draw` call was successful
 | 
			
		||||
        IERC20Token(_getDaiAddress()).transfer(to, amount);
 | 
			
		||||
 | 
			
		||||
        return BRIDGE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										103
									
								
								contracts/asset-proxy/contracts/src/bridges/CreamBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								contracts/asset-proxy/contracts/src/bridges/CreamBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,103 @@
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.5.9;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
			
		||||
import "../interfaces/IERC20Bridge.sol";
 | 
			
		||||
import "../interfaces/IBalancerPool.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract CreamBridge is
 | 
			
		||||
    IERC20Bridge,
 | 
			
		||||
    IWallet,
 | 
			
		||||
    DeploymentConstants
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
 | 
			
		||||
    ///      `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
 | 
			
		||||
    ///      token encoded in the bridge data, then transfers the bought
 | 
			
		||||
    ///      tokens to `to`.
 | 
			
		||||
    /// @param toTokenAddress The token to buy and transfer to `to`.
 | 
			
		||||
    /// @param from The maker (this contract).
 | 
			
		||||
    /// @param to The recipient of the bought tokens.
 | 
			
		||||
    /// @param amount Minimum amount of `toTokenAddress` tokens to buy.
 | 
			
		||||
    /// @param bridgeData The abi-encoded addresses of the "from" token and Balancer pool.
 | 
			
		||||
    /// @return success The magic bytes if successful.
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address toTokenAddress,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        // Decode the bridge data.
 | 
			
		||||
        (address fromTokenAddress, address poolAddress) = abi.decode(
 | 
			
		||||
            bridgeData,
 | 
			
		||||
            (address, address)
 | 
			
		||||
        );
 | 
			
		||||
        require(toTokenAddress != fromTokenAddress, "CreamBridge/INVALID_PAIR");
 | 
			
		||||
 | 
			
		||||
        uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
 | 
			
		||||
        // Grant an allowance to the exchange to spend `fromTokenAddress` token.
 | 
			
		||||
        LibERC20Token.approveIfBelow(fromTokenAddress, poolAddress, fromTokenBalance);
 | 
			
		||||
 | 
			
		||||
        // Sell all of this contract's `fromTokenAddress` token balance.
 | 
			
		||||
        (uint256 boughtAmount,) = IBalancerPool(poolAddress).swapExactAmountIn(
 | 
			
		||||
            fromTokenAddress, // tokenIn
 | 
			
		||||
            fromTokenBalance, // tokenAmountIn
 | 
			
		||||
            toTokenAddress,   // tokenOut
 | 
			
		||||
            amount,           // minAmountOut
 | 
			
		||||
            uint256(-1)       // maxPrice
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Transfer the converted `toToken`s to `to`.
 | 
			
		||||
        LibERC20Token.transfer(toTokenAddress, to, boughtAmount);
 | 
			
		||||
 | 
			
		||||
        emit ERC20BridgeTransfer(
 | 
			
		||||
            fromTokenAddress,
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            fromTokenBalance,
 | 
			
		||||
            boughtAmount,
 | 
			
		||||
            from,
 | 
			
		||||
            to
 | 
			
		||||
        );
 | 
			
		||||
        return BRIDGE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
 | 
			
		||||
    ///      and sign for itself in orders. Always succeeds.
 | 
			
		||||
    /// @return magicValue Magic success bytes, always.
 | 
			
		||||
    function isValidSignature(
 | 
			
		||||
        bytes32,
 | 
			
		||||
        bytes calldata
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes4 magicValue)
 | 
			
		||||
    {
 | 
			
		||||
        return LEGACY_WALLET_MAGIC_VALUE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										136
									
								
								contracts/asset-proxy/contracts/src/bridges/CryptoComBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								contracts/asset-proxy/contracts/src/bridges/CryptoComBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,136 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.5.9;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
			
		||||
import "../interfaces/IUniswapV2Router01.sol";
 | 
			
		||||
import "../interfaces/IERC20Bridge.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable space-after-comma
 | 
			
		||||
// solhint-disable not-rely-on-time
 | 
			
		||||
contract CryptoComBridge is
 | 
			
		||||
    IERC20Bridge,
 | 
			
		||||
    IWallet,
 | 
			
		||||
    DeploymentConstants
 | 
			
		||||
{
 | 
			
		||||
    struct TransferState {
 | 
			
		||||
        address[] path;
 | 
			
		||||
        address router;
 | 
			
		||||
        uint256 fromTokenBalance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
 | 
			
		||||
    ///      `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
 | 
			
		||||
    ///      token encoded in the bridge data.
 | 
			
		||||
    /// @param toTokenAddress The token to buy and transfer to `to`.
 | 
			
		||||
    /// @param from The maker (this contract).
 | 
			
		||||
    /// @param to The recipient of the bought tokens.
 | 
			
		||||
    /// @param amount Minimum amount of `toTokenAddress` tokens to buy.
 | 
			
		||||
    /// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress
 | 
			
		||||
    /// @return success The magic bytes if successful.
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address toTokenAddress,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        // hold variables to get around stack depth limitations
 | 
			
		||||
        TransferState memory state;
 | 
			
		||||
 | 
			
		||||
        // Decode the bridge data to get the `fromTokenAddress`.
 | 
			
		||||
        // solhint-disable indent
 | 
			
		||||
        (state.path, state.router) = abi.decode(bridgeData, (address[], address));
 | 
			
		||||
        // solhint-enable indent
 | 
			
		||||
 | 
			
		||||
        require(state.path.length >= 2, "CryptoComBridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
 | 
			
		||||
        require(state.path[state.path.length - 1] == toTokenAddress, "CryptoComBridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN");
 | 
			
		||||
 | 
			
		||||
        // Just transfer the tokens if they're the same.
 | 
			
		||||
        if (state.path[0] == toTokenAddress) {
 | 
			
		||||
            LibERC20Token.transfer(state.path[0], to, amount);
 | 
			
		||||
            return BRIDGE_SUCCESS;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Get our balance of `fromTokenAddress` token.
 | 
			
		||||
        state.fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this));
 | 
			
		||||
 | 
			
		||||
        // Grant the SushiSwap router an allowance.
 | 
			
		||||
        LibERC20Token.approveIfBelow(
 | 
			
		||||
            state.path[0],
 | 
			
		||||
            state.router,
 | 
			
		||||
            state.fromTokenBalance
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Buy as much `toTokenAddress` token with `fromTokenAddress` token
 | 
			
		||||
        // and transfer it to `to`.
 | 
			
		||||
        IUniswapV2Router01 router = IUniswapV2Router01(state.router);
 | 
			
		||||
        uint[] memory amounts = router.swapExactTokensForTokens(
 | 
			
		||||
             // Sell all tokens we hold.
 | 
			
		||||
            state.fromTokenBalance,
 | 
			
		||||
             // Minimum buy amount.
 | 
			
		||||
            amount,
 | 
			
		||||
            // Convert `fromTokenAddress` to `toTokenAddress`.
 | 
			
		||||
            state.path,
 | 
			
		||||
            // Recipient is `to`.
 | 
			
		||||
            to,
 | 
			
		||||
            // Expires after this block.
 | 
			
		||||
            block.timestamp
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        emit ERC20BridgeTransfer(
 | 
			
		||||
            // input token
 | 
			
		||||
            state.path[0],
 | 
			
		||||
            // output token
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            // input token amount
 | 
			
		||||
            state.fromTokenBalance,
 | 
			
		||||
            // output token amount
 | 
			
		||||
            amounts[amounts.length - 1],
 | 
			
		||||
            from,
 | 
			
		||||
            to
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return BRIDGE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
 | 
			
		||||
    ///      and sign for itself in orders. Always succeeds.
 | 
			
		||||
    /// @return magicValue Success bytes, always.
 | 
			
		||||
    function isValidSignature(
 | 
			
		||||
        bytes32,
 | 
			
		||||
        bytes calldata
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes4 magicValue)
 | 
			
		||||
    {
 | 
			
		||||
        return LEGACY_WALLET_MAGIC_VALUE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										119
									
								
								contracts/asset-proxy/contracts/src/bridges/CurveBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								contracts/asset-proxy/contracts/src/bridges/CurveBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
			
		||||
import "../interfaces/IERC20Bridge.sol";
 | 
			
		||||
import "../interfaces/ICurve.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable not-rely-on-time
 | 
			
		||||
// solhint-disable space-after-comma
 | 
			
		||||
contract CurveBridge is
 | 
			
		||||
    IERC20Bridge,
 | 
			
		||||
    IWallet,
 | 
			
		||||
    DeploymentConstants
 | 
			
		||||
{
 | 
			
		||||
    struct CurveBridgeData {
 | 
			
		||||
        address curveAddress;
 | 
			
		||||
        bytes4 exchangeFunctionSelector;
 | 
			
		||||
        address fromTokenAddress;
 | 
			
		||||
        int128 fromCoinIdx;
 | 
			
		||||
        int128 toCoinIdx;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Callback for `ICurve`. Tries to buy `amount` of
 | 
			
		||||
    ///      `toTokenAddress` tokens by selling the entirety of the opposing asset
 | 
			
		||||
    ///      (DAI, USDC) to the Curve contract, then transfers the bought
 | 
			
		||||
    ///      tokens to `to`.
 | 
			
		||||
    /// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT).
 | 
			
		||||
    /// @param from The maker (this contract).
 | 
			
		||||
    /// @param to The recipient of the bought tokens.
 | 
			
		||||
    /// @param amount Minimum amount of `toTokenAddress` tokens to buy.
 | 
			
		||||
    /// @param bridgeData The abi-encoeded "from" token address.
 | 
			
		||||
    /// @return success The magic bytes if successful.
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address toTokenAddress,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        // Decode the bridge data to get the Curve metadata.
 | 
			
		||||
        CurveBridgeData memory data = abi.decode(bridgeData, (CurveBridgeData));
 | 
			
		||||
 | 
			
		||||
        require(toTokenAddress != data.fromTokenAddress, "CurveBridge/INVALID_PAIR");
 | 
			
		||||
        uint256 fromTokenBalance = IERC20Token(data.fromTokenAddress).balanceOf(address(this));
 | 
			
		||||
        // Grant an allowance to the exchange to spend `fromTokenAddress` token.
 | 
			
		||||
        LibERC20Token.approveIfBelow(data.fromTokenAddress, data.curveAddress, fromTokenBalance);
 | 
			
		||||
 | 
			
		||||
        // Try to sell all of this contract's `fromTokenAddress` token balance.
 | 
			
		||||
        {
 | 
			
		||||
            (bool didSucceed, bytes memory resultData) =
 | 
			
		||||
                data.curveAddress.call(abi.encodeWithSelector(
 | 
			
		||||
                    data.exchangeFunctionSelector,
 | 
			
		||||
                    data.fromCoinIdx,
 | 
			
		||||
                    data.toCoinIdx,
 | 
			
		||||
                    // dx
 | 
			
		||||
                    fromTokenBalance,
 | 
			
		||||
                    // min dy
 | 
			
		||||
                    amount
 | 
			
		||||
                ));
 | 
			
		||||
            if (!didSucceed) {
 | 
			
		||||
                assembly { revert(add(resultData, 32), mload(resultData)) }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this));
 | 
			
		||||
        // Transfer the converted `toToken`s to `to`.
 | 
			
		||||
        LibERC20Token.transfer(toTokenAddress, to, toTokenBalance);
 | 
			
		||||
 | 
			
		||||
        emit ERC20BridgeTransfer(
 | 
			
		||||
            data.fromTokenAddress,
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            fromTokenBalance,
 | 
			
		||||
            toTokenBalance,
 | 
			
		||||
            from,
 | 
			
		||||
            to
 | 
			
		||||
        );
 | 
			
		||||
        return BRIDGE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
 | 
			
		||||
    ///      and sign for itself in orders. Always succeeds.
 | 
			
		||||
    /// @return magicValue Magic success bytes, always.
 | 
			
		||||
    function isValidSignature(
 | 
			
		||||
        bytes32,
 | 
			
		||||
        bytes calldata
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes4 magicValue)
 | 
			
		||||
    {
 | 
			
		||||
        return LEGACY_WALLET_MAGIC_VALUE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										147
									
								
								contracts/asset-proxy/contracts/src/bridges/DODOBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								contracts/asset-proxy/contracts/src/bridges/DODOBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,147 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.5.9;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
			
		||||
import "../interfaces/IERC20Bridge.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IDODOHelper {
 | 
			
		||||
 | 
			
		||||
    function querySellQuoteToken(address dodo, uint256 amount) external view returns (uint256);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IDODO {
 | 
			
		||||
 | 
			
		||||
    function sellBaseToken(uint256 amount, uint256 minReceiveQuote, bytes calldata data) external returns (uint256);
 | 
			
		||||
 | 
			
		||||
    function buyBaseToken(uint256 amount, uint256 maxPayQuote, bytes calldata data) external returns (uint256);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract DODOBridge is
 | 
			
		||||
    IERC20Bridge,
 | 
			
		||||
    IWallet,
 | 
			
		||||
    DeploymentConstants
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    struct TransferState {
 | 
			
		||||
        address fromTokenAddress;
 | 
			
		||||
        uint256 fromTokenBalance;
 | 
			
		||||
        address pool;
 | 
			
		||||
        bool isSellBase;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
 | 
			
		||||
    ///      `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
 | 
			
		||||
    ///      token encoded in the bridge data.
 | 
			
		||||
    /// @param toTokenAddress The token to buy and transfer to `to`.
 | 
			
		||||
    /// @param from The maker (this contract).
 | 
			
		||||
    /// @param to The recipient of the bought tokens.
 | 
			
		||||
    /// @param amount Minimum amount of `toTokenAddress` tokens to buy.
 | 
			
		||||
    /// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress
 | 
			
		||||
    /// @return success The magic bytes if successful.
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address toTokenAddress,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        TransferState memory state;
 | 
			
		||||
        // Decode the bridge data to get the `fromTokenAddress`.
 | 
			
		||||
        (state.fromTokenAddress, state.pool, state.isSellBase) = abi.decode(bridgeData, (address, address, bool));
 | 
			
		||||
        require(state.pool != address(0), "DODOBridge/InvalidPool");
 | 
			
		||||
        IDODO exchange = IDODO(state.pool);
 | 
			
		||||
        // Get our balance of `fromTokenAddress` token.
 | 
			
		||||
        state.fromTokenBalance = IERC20Token(state.fromTokenAddress).balanceOf(address(this));
 | 
			
		||||
 | 
			
		||||
        // Grant the pool an allowance.
 | 
			
		||||
        LibERC20Token.approveIfBelow(
 | 
			
		||||
            state.fromTokenAddress,
 | 
			
		||||
            address(exchange),
 | 
			
		||||
            state.fromTokenBalance
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        uint256 boughtAmount;
 | 
			
		||||
        if (state.isSellBase) {
 | 
			
		||||
            boughtAmount = exchange.sellBaseToken(
 | 
			
		||||
                // amount to sell
 | 
			
		||||
                state.fromTokenBalance,
 | 
			
		||||
                // min receive amount
 | 
			
		||||
                1,
 | 
			
		||||
                new bytes(0)
 | 
			
		||||
            );
 | 
			
		||||
        } else {
 | 
			
		||||
            // Need to re-calculate the sell quote amount into buyBase
 | 
			
		||||
            boughtAmount = IDODOHelper(_getDODOHelperAddress()).querySellQuoteToken(
 | 
			
		||||
                address(exchange),
 | 
			
		||||
                state.fromTokenBalance
 | 
			
		||||
            );
 | 
			
		||||
            exchange.buyBaseToken(
 | 
			
		||||
                // amount to buy
 | 
			
		||||
                boughtAmount,
 | 
			
		||||
                // max pay amount
 | 
			
		||||
                state.fromTokenBalance,
 | 
			
		||||
                new bytes(0)
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        // Transfer funds to `to`
 | 
			
		||||
        IERC20Token(toTokenAddress).transfer(to, boughtAmount);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        emit ERC20BridgeTransfer(
 | 
			
		||||
            // input token
 | 
			
		||||
            state.fromTokenAddress,
 | 
			
		||||
            // output token
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            // input token amount
 | 
			
		||||
            state.fromTokenBalance,
 | 
			
		||||
            // output token amount
 | 
			
		||||
            boughtAmount,
 | 
			
		||||
            from,
 | 
			
		||||
            to
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return BRIDGE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
 | 
			
		||||
    ///      and sign for itself in orders. Always succeeds.
 | 
			
		||||
    /// @return magicValue Success bytes, always.
 | 
			
		||||
    function isValidSignature(
 | 
			
		||||
        bytes32,
 | 
			
		||||
        bytes calldata
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes4 magicValue)
 | 
			
		||||
    {
 | 
			
		||||
        return LEGACY_WALLET_MAGIC_VALUE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,200 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.5.9;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
 | 
			
		||||
import "../interfaces/IERC20Bridge.sol";
 | 
			
		||||
import "./MixinGasToken.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable space-after-comma, indent
 | 
			
		||||
contract DexForwarderBridge is
 | 
			
		||||
    IERC20Bridge,
 | 
			
		||||
    IWallet,
 | 
			
		||||
    DeploymentConstants,
 | 
			
		||||
    MixinGasToken
 | 
			
		||||
{
 | 
			
		||||
    using LibSafeMath for uint256;
 | 
			
		||||
 | 
			
		||||
    /// @dev Data needed to reconstruct a bridge call.
 | 
			
		||||
    struct BridgeCall {
 | 
			
		||||
        address target;
 | 
			
		||||
        uint256 inputTokenAmount;
 | 
			
		||||
        uint256 outputTokenAmount;
 | 
			
		||||
        bytes bridgeData;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Intermediate state variables used by `bridgeTransferFrom()`, in
 | 
			
		||||
    ///      struct form to get around stack limits.
 | 
			
		||||
    struct TransferFromState {
 | 
			
		||||
        address inputToken;
 | 
			
		||||
        uint256 initialInputTokenBalance;
 | 
			
		||||
        uint256 callInputTokenAmount;
 | 
			
		||||
        uint256 callOutputTokenAmount;
 | 
			
		||||
        uint256 totalInputTokenSold;
 | 
			
		||||
        BridgeCall[] calls;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Spends this contract's entire balance of input tokens by forwarding
 | 
			
		||||
    /// them to other bridges. Reverts if the entire balance is not spent.
 | 
			
		||||
    /// @param outputToken The token being bought.
 | 
			
		||||
    /// @param to The recipient of the bought tokens.
 | 
			
		||||
    /// @param bridgeData The abi-encoded input token address.
 | 
			
		||||
    /// @return success The magic bytes if successful.
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address outputToken,
 | 
			
		||||
        address /* from */,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 /* amount */,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        freesGasTokensFromCollector
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        require(
 | 
			
		||||
            msg.sender == _getERC20BridgeProxyAddress(),
 | 
			
		||||
            "DexForwarderBridge/SENDER_NOT_AUTHORIZED"
 | 
			
		||||
        );
 | 
			
		||||
        TransferFromState memory state;
 | 
			
		||||
        (
 | 
			
		||||
            state.inputToken,
 | 
			
		||||
            state.calls
 | 
			
		||||
        ) = abi.decode(bridgeData, (address, BridgeCall[]));
 | 
			
		||||
 | 
			
		||||
        state.initialInputTokenBalance =
 | 
			
		||||
            IERC20Token(state.inputToken).balanceOf(address(this));
 | 
			
		||||
 | 
			
		||||
        for (uint256 i = 0; i < state.calls.length; ++i) {
 | 
			
		||||
            // Stop if the we've sold all our input tokens.
 | 
			
		||||
            if (state.totalInputTokenSold >= state.initialInputTokenBalance) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Compute token amounts.
 | 
			
		||||
            state.callInputTokenAmount = LibSafeMath.min256(
 | 
			
		||||
                state.calls[i].inputTokenAmount,
 | 
			
		||||
                state.initialInputTokenBalance.safeSub(state.totalInputTokenSold)
 | 
			
		||||
            );
 | 
			
		||||
            state.callOutputTokenAmount = LibMath.getPartialAmountFloor(
 | 
			
		||||
                state.callInputTokenAmount,
 | 
			
		||||
                state.calls[i].inputTokenAmount,
 | 
			
		||||
                state.calls[i].outputTokenAmount
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // Execute the call in a new context so we can recoup transferred
 | 
			
		||||
            // funds by reverting.
 | 
			
		||||
            (bool didSucceed, ) = address(this)
 | 
			
		||||
                .call(abi.encodeWithSelector(
 | 
			
		||||
                    this.executeBridgeCall.selector,
 | 
			
		||||
                    state.calls[i].target,
 | 
			
		||||
                    to,
 | 
			
		||||
                    state.inputToken,
 | 
			
		||||
                    outputToken,
 | 
			
		||||
                    state.callInputTokenAmount,
 | 
			
		||||
                    state.callOutputTokenAmount,
 | 
			
		||||
                    state.calls[i].bridgeData
 | 
			
		||||
                ));
 | 
			
		||||
 | 
			
		||||
            if (didSucceed) {
 | 
			
		||||
                // Increase the amount of tokens sold.
 | 
			
		||||
                state.totalInputTokenSold = state.totalInputTokenSold.safeAdd(
 | 
			
		||||
                    state.callInputTokenAmount
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // Always succeed.
 | 
			
		||||
        return BRIDGE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Transfers `inputToken` token to a bridge contract then calls
 | 
			
		||||
    ///      its `bridgeTransferFrom()`. This is executed in separate context
 | 
			
		||||
    ///      so we can revert the transfer on error. This can only be called
 | 
			
		||||
    //       by this contract itself.
 | 
			
		||||
    /// @param bridge The bridge contract.
 | 
			
		||||
    /// @param to The recipient of `outputToken` tokens.
 | 
			
		||||
    /// @param inputToken The input token.
 | 
			
		||||
    /// @param outputToken The output token.
 | 
			
		||||
    /// @param inputTokenAmount The amount of input tokens to transfer to `bridge`.
 | 
			
		||||
    /// @param outputTokenAmount The amount of expected output tokens to be sent
 | 
			
		||||
    ///        to `to` by `bridge`.
 | 
			
		||||
    function executeBridgeCall(
 | 
			
		||||
        address bridge,
 | 
			
		||||
        address to,
 | 
			
		||||
        address inputToken,
 | 
			
		||||
        address outputToken,
 | 
			
		||||
        uint256 inputTokenAmount,
 | 
			
		||||
        uint256 outputTokenAmount,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        // Must be called through `bridgeTransferFrom()`.
 | 
			
		||||
        require(msg.sender == address(this), "DexForwarderBridge/ONLY_SELF");
 | 
			
		||||
        // `bridge` must not be this contract.
 | 
			
		||||
        require(bridge != address(this));
 | 
			
		||||
 | 
			
		||||
        // Get the starting balance of output tokens for `to`.
 | 
			
		||||
        uint256 initialRecipientBalance = IERC20Token(outputToken).balanceOf(to);
 | 
			
		||||
 | 
			
		||||
        // Transfer input tokens to the bridge.
 | 
			
		||||
        LibERC20Token.transfer(inputToken, bridge, inputTokenAmount);
 | 
			
		||||
 | 
			
		||||
        // Call the bridge.
 | 
			
		||||
        (bool didSucceed, bytes memory resultData) =
 | 
			
		||||
            bridge.call(abi.encodeWithSelector(
 | 
			
		||||
                IERC20Bridge(0).bridgeTransferFrom.selector,
 | 
			
		||||
                outputToken,
 | 
			
		||||
                bridge,
 | 
			
		||||
                to,
 | 
			
		||||
                outputTokenAmount,
 | 
			
		||||
                bridgeData
 | 
			
		||||
            ));
 | 
			
		||||
 | 
			
		||||
        // Revert if the call failed or not enough tokens were bought.
 | 
			
		||||
        // This will also undo the token transfer.
 | 
			
		||||
        require(
 | 
			
		||||
            didSucceed
 | 
			
		||||
            && resultData.length == 32
 | 
			
		||||
            && LibBytes.readBytes32(resultData, 0) == bytes32(BRIDGE_SUCCESS)
 | 
			
		||||
            && IERC20Token(outputToken).balanceOf(to).safeSub(initialRecipientBalance) >= outputTokenAmount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
 | 
			
		||||
    ///      and sign for itself in orders. Always succeeds.
 | 
			
		||||
    /// @return magicValue Magic success bytes, always.
 | 
			
		||||
    function isValidSignature(
 | 
			
		||||
        bytes32,
 | 
			
		||||
        bytes calldata
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes4 magicValue)
 | 
			
		||||
    {
 | 
			
		||||
        return LEGACY_WALLET_MAGIC_VALUE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										242
									
								
								contracts/asset-proxy/contracts/src/bridges/DydxBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										242
									
								
								contracts/asset-proxy/contracts/src/bridges/DydxBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,242 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/LibMath.sol";
 | 
			
		||||
import "../interfaces/IERC20Bridge.sol";
 | 
			
		||||
import "../interfaces/IDydxBridge.sol";
 | 
			
		||||
import "../interfaces/IDydx.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract DydxBridge is
 | 
			
		||||
    IERC20Bridge,
 | 
			
		||||
    IDydxBridge,
 | 
			
		||||
    DeploymentConstants
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    using LibSafeMath for uint256;
 | 
			
		||||
 | 
			
		||||
    /// @dev Callback for `IERC20Bridge`. Deposits or withdraws tokens from a dydx account.
 | 
			
		||||
    ///      Notes:
 | 
			
		||||
    ///         1. This bridge must be set as an operator of the input dydx account.
 | 
			
		||||
    ///         2. This function may only be called in the context of the 0x Exchange.
 | 
			
		||||
    ///         3. The maker or taker of the 0x order must be the dydx account owner.
 | 
			
		||||
    ///         4. Deposits into dydx are made from the `from` address.
 | 
			
		||||
    ///         5. Withdrawals from dydx are made to the `to` address.
 | 
			
		||||
    ///         6. Calling this function must always withdraw at least `amount`,
 | 
			
		||||
    ///            otherwise the `ERC20Bridge` will revert.
 | 
			
		||||
    /// @param from The sender of the tokens and owner of the dydx account.
 | 
			
		||||
    /// @param to The recipient of the tokens.
 | 
			
		||||
    /// @param amount Minimum amount of `toTokenAddress` tokens to deposit or withdraw.
 | 
			
		||||
    /// @param encodedBridgeData An abi-encoded `BridgeData` struct.
 | 
			
		||||
    /// @return success The magic bytes if successful.
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address, /* toTokenAddress */
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata encodedBridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        // Ensure that only the `ERC20BridgeProxy` can call this function.
 | 
			
		||||
        require(
 | 
			
		||||
            msg.sender == _getERC20BridgeProxyAddress(),
 | 
			
		||||
            "DydxBridge/ONLY_CALLABLE_BY_ERC20_BRIDGE_PROXY"
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Decode bridge data.
 | 
			
		||||
        (BridgeData memory bridgeData) = abi.decode(encodedBridgeData, (BridgeData));
 | 
			
		||||
 | 
			
		||||
        // The dydx accounts are owned by the `from` address.
 | 
			
		||||
        IDydx.AccountInfo[] memory accounts = _createAccounts(from, bridgeData);
 | 
			
		||||
 | 
			
		||||
        // Create dydx actions to run on the dydx accounts.
 | 
			
		||||
        IDydx.ActionArgs[] memory actions = _createActions(
 | 
			
		||||
            from,
 | 
			
		||||
            to,
 | 
			
		||||
            amount,
 | 
			
		||||
            bridgeData
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Run operation. This will revert on failure.
 | 
			
		||||
        IDydx(_getDydxAddress()).operate(accounts, actions);
 | 
			
		||||
 | 
			
		||||
        return BRIDGE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Creates an array of accounts for dydx to operate on.
 | 
			
		||||
    ///      All accounts must belong to the same owner.
 | 
			
		||||
    /// @param accountOwner Owner of the dydx account.
 | 
			
		||||
    /// @param bridgeData A `BridgeData` struct.
 | 
			
		||||
    function _createAccounts(
 | 
			
		||||
        address accountOwner,
 | 
			
		||||
        BridgeData memory bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
        returns (IDydx.AccountInfo[] memory accounts)
 | 
			
		||||
    {
 | 
			
		||||
        uint256[] memory accountNumbers = bridgeData.accountNumbers;
 | 
			
		||||
        uint256 nAccounts = accountNumbers.length;
 | 
			
		||||
        accounts = new IDydx.AccountInfo[](nAccounts);
 | 
			
		||||
        for (uint256 i = 0; i < nAccounts; ++i) {
 | 
			
		||||
            accounts[i] = IDydx.AccountInfo({
 | 
			
		||||
                owner: accountOwner,
 | 
			
		||||
                number: accountNumbers[i]
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Creates an array of actions to carry out on dydx.
 | 
			
		||||
    /// @param depositFrom Deposit value from this address (owner of the dydx account).
 | 
			
		||||
    /// @param withdrawTo Withdraw value to this address.
 | 
			
		||||
    /// @param amount The amount of value available to operate on.
 | 
			
		||||
    /// @param bridgeData A `BridgeData` struct.
 | 
			
		||||
    function _createActions(
 | 
			
		||||
        address depositFrom,
 | 
			
		||||
        address withdrawTo,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        BridgeData memory bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
        returns (IDydx.ActionArgs[] memory actions)
 | 
			
		||||
    {
 | 
			
		||||
        BridgeAction[] memory bridgeActions = bridgeData.actions;
 | 
			
		||||
        uint256 nBridgeActions = bridgeActions.length;
 | 
			
		||||
        actions = new IDydx.ActionArgs[](nBridgeActions);
 | 
			
		||||
        for (uint256 i = 0; i < nBridgeActions; ++i) {
 | 
			
		||||
            // Cache current bridge action.
 | 
			
		||||
            BridgeAction memory bridgeAction = bridgeActions[i];
 | 
			
		||||
 | 
			
		||||
            // Scale amount, if conversion rate is set.
 | 
			
		||||
            uint256 scaledAmount;
 | 
			
		||||
            if (bridgeAction.conversionRateDenominator > 0) {
 | 
			
		||||
                scaledAmount = LibMath.safeGetPartialAmountFloor(
 | 
			
		||||
                    bridgeAction.conversionRateNumerator,
 | 
			
		||||
                    bridgeAction.conversionRateDenominator,
 | 
			
		||||
                    amount
 | 
			
		||||
                );
 | 
			
		||||
            } else {
 | 
			
		||||
                scaledAmount = amount;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Construct dydx action.
 | 
			
		||||
            if (bridgeAction.actionType == BridgeActionType.Deposit) {
 | 
			
		||||
                // Deposit tokens from the account owner into their dydx account.
 | 
			
		||||
                actions[i] = _createDepositAction(
 | 
			
		||||
                    depositFrom,
 | 
			
		||||
                    scaledAmount,
 | 
			
		||||
                    bridgeAction
 | 
			
		||||
                );
 | 
			
		||||
            } else if (bridgeAction.actionType == BridgeActionType.Withdraw) {
 | 
			
		||||
                // Withdraw tokens from dydx to the `otherAccount`.
 | 
			
		||||
                actions[i] = _createWithdrawAction(
 | 
			
		||||
                    withdrawTo,
 | 
			
		||||
                    scaledAmount,
 | 
			
		||||
                    bridgeAction
 | 
			
		||||
                );
 | 
			
		||||
            } else {
 | 
			
		||||
                // If all values in the `Action` enum are handled then this
 | 
			
		||||
                // revert is unreachable: Solidity will revert when casting
 | 
			
		||||
                // from `uint8` to `Action`.
 | 
			
		||||
                revert("DydxBridge/UNRECOGNIZED_BRIDGE_ACTION");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Returns a dydx `DepositAction`.
 | 
			
		||||
    /// @param depositFrom Deposit tokens from this address who is also the account owner.
 | 
			
		||||
    /// @param amount of tokens to deposit.
 | 
			
		||||
    /// @param bridgeAction A `BridgeAction` struct.
 | 
			
		||||
    /// @return depositAction The encoded dydx action.
 | 
			
		||||
    function _createDepositAction(
 | 
			
		||||
        address depositFrom,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        BridgeAction memory bridgeAction
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
        pure
 | 
			
		||||
        returns (
 | 
			
		||||
            IDydx.ActionArgs memory depositAction
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        // Create dydx amount.
 | 
			
		||||
        IDydx.AssetAmount memory dydxAmount = IDydx.AssetAmount({
 | 
			
		||||
            sign: true,                                 // true if positive.
 | 
			
		||||
            denomination: IDydx.AssetDenomination.Wei,  // Wei => actual token amount held in account.
 | 
			
		||||
            ref: IDydx.AssetReference.Delta,                // Delta => a relative amount.
 | 
			
		||||
            value: amount                               // amount to deposit.
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Create dydx deposit action.
 | 
			
		||||
        depositAction = IDydx.ActionArgs({
 | 
			
		||||
            actionType: IDydx.ActionType.Deposit,           // deposit tokens.
 | 
			
		||||
            amount: dydxAmount,                             // amount to deposit.
 | 
			
		||||
            accountIdx: bridgeAction.accountIdx,             // index in the `accounts` when calling `operate`.
 | 
			
		||||
            primaryMarketId: bridgeAction.marketId,         // indicates which token to deposit.
 | 
			
		||||
            otherAddress: depositFrom,                      // deposit from the account owner.
 | 
			
		||||
            // unused parameters
 | 
			
		||||
            secondaryMarketId: 0,
 | 
			
		||||
            otherAccountIdx: 0,
 | 
			
		||||
            data: hex''
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Returns a dydx `WithdrawAction`.
 | 
			
		||||
    /// @param withdrawTo Withdraw tokens to this address.
 | 
			
		||||
    /// @param amount of tokens to withdraw.
 | 
			
		||||
    /// @param bridgeAction A `BridgeAction` struct.
 | 
			
		||||
    /// @return withdrawAction The encoded dydx action.
 | 
			
		||||
    function _createWithdrawAction(
 | 
			
		||||
        address withdrawTo,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        BridgeAction memory bridgeAction
 | 
			
		||||
    )
 | 
			
		||||
        internal
 | 
			
		||||
        pure
 | 
			
		||||
        returns (
 | 
			
		||||
            IDydx.ActionArgs memory withdrawAction
 | 
			
		||||
        )
 | 
			
		||||
    {
 | 
			
		||||
        // Create dydx amount.
 | 
			
		||||
        IDydx.AssetAmount memory amountToWithdraw = IDydx.AssetAmount({
 | 
			
		||||
            sign: false,                                    // false if negative.
 | 
			
		||||
            denomination: IDydx.AssetDenomination.Wei,      // Wei => actual token amount held in account.
 | 
			
		||||
            ref: IDydx.AssetReference.Delta,                // Delta => a relative amount.
 | 
			
		||||
            value: amount                                   // amount to withdraw.
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Create withdraw action.
 | 
			
		||||
        withdrawAction = IDydx.ActionArgs({
 | 
			
		||||
            actionType: IDydx.ActionType.Withdraw,          // withdraw tokens.
 | 
			
		||||
            amount: amountToWithdraw,                       // amount to withdraw.
 | 
			
		||||
            accountIdx: bridgeAction.accountIdx,            // index in the `accounts` when calling `operate`.
 | 
			
		||||
            primaryMarketId: bridgeAction.marketId,         // indicates which token to withdraw.
 | 
			
		||||
            otherAddress: withdrawTo,                       // withdraw tokens to this address.
 | 
			
		||||
            // unused parameters
 | 
			
		||||
            secondaryMarketId: 0,
 | 
			
		||||
            otherAccountIdx: 0,
 | 
			
		||||
            data: hex''
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,98 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
			
		||||
import "../interfaces/IERC20Bridge.sol";
 | 
			
		||||
import "../interfaces/IEth2Dai.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable space-after-comma
 | 
			
		||||
contract Eth2DaiBridge is
 | 
			
		||||
    IERC20Bridge,
 | 
			
		||||
    IWallet,
 | 
			
		||||
    DeploymentConstants
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
 | 
			
		||||
    ///      `toTokenAddress` tokens by selling the entirety of the opposing asset
 | 
			
		||||
    ///      (DAI or WETH) to the Eth2Dai contract, then transfers the bought
 | 
			
		||||
    ///      tokens to `to`.
 | 
			
		||||
    /// @param toTokenAddress The token to give to `to` (either DAI or WETH).
 | 
			
		||||
    /// @param from The maker (this contract).
 | 
			
		||||
    /// @param to The recipient of the bought tokens.
 | 
			
		||||
    /// @param amount Minimum amount of `toTokenAddress` tokens to buy.
 | 
			
		||||
    /// @param bridgeData The abi-encoeded "from" token address.
 | 
			
		||||
    /// @return success The magic bytes if successful.
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address toTokenAddress,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        // Decode the bridge data to get the `fromTokenAddress`.
 | 
			
		||||
        (address fromTokenAddress) = abi.decode(bridgeData, (address));
 | 
			
		||||
 | 
			
		||||
        IEth2Dai exchange = IEth2Dai(_getEth2DaiAddress());
 | 
			
		||||
        uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
 | 
			
		||||
        // Grant an allowance to the exchange to spend `fromTokenAddress` token.
 | 
			
		||||
        LibERC20Token.approveIfBelow(fromTokenAddress, address(exchange), fromTokenBalance);
 | 
			
		||||
 | 
			
		||||
        // Try to sell all of this contract's `fromTokenAddress` token balance.
 | 
			
		||||
        uint256 boughtAmount = exchange.sellAllAmount(
 | 
			
		||||
            fromTokenAddress,
 | 
			
		||||
            fromTokenBalance,
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            amount
 | 
			
		||||
        );
 | 
			
		||||
        // Transfer the converted `toToken`s to `to`.
 | 
			
		||||
        LibERC20Token.transfer(toTokenAddress, to, boughtAmount);
 | 
			
		||||
 | 
			
		||||
        emit ERC20BridgeTransfer(
 | 
			
		||||
            fromTokenAddress,
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            fromTokenBalance,
 | 
			
		||||
            boughtAmount,
 | 
			
		||||
            from,
 | 
			
		||||
            to
 | 
			
		||||
        );
 | 
			
		||||
        return BRIDGE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
 | 
			
		||||
    ///      and sign for itself in orders. Always succeeds.
 | 
			
		||||
    /// @return magicValue Magic success bytes, always.
 | 
			
		||||
    function isValidSignature(
 | 
			
		||||
        bytes32,
 | 
			
		||||
        bytes calldata
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes4 magicValue)
 | 
			
		||||
    {
 | 
			
		||||
        return LEGACY_WALLET_MAGIC_VALUE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										169
									
								
								contracts/asset-proxy/contracts/src/bridges/KyberBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								contracts/asset-proxy/contracts/src/bridges/KyberBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,169 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.5.9;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
 | 
			
		||||
import "../interfaces/IERC20Bridge.sol";
 | 
			
		||||
import "../interfaces/IKyberNetworkProxy.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable space-after-comma
 | 
			
		||||
contract KyberBridge is
 | 
			
		||||
    IERC20Bridge,
 | 
			
		||||
    IWallet,
 | 
			
		||||
    DeploymentConstants
 | 
			
		||||
{
 | 
			
		||||
    using LibSafeMath for uint256;
 | 
			
		||||
 | 
			
		||||
    // @dev Structure used internally to get around stack limits.
 | 
			
		||||
    struct TradeState {
 | 
			
		||||
        IKyberNetworkProxy kyber;
 | 
			
		||||
        IEtherToken weth;
 | 
			
		||||
        address fromTokenAddress;
 | 
			
		||||
        uint256 fromTokenBalance;
 | 
			
		||||
        uint256 payableAmount;
 | 
			
		||||
        uint256 conversionRate;
 | 
			
		||||
        bytes hint;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Kyber ETH pseudo-address.
 | 
			
		||||
    address constant public KYBER_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
 | 
			
		||||
    /// @dev `bridgeTransferFrom()` failure result.
 | 
			
		||||
    bytes4 constant private BRIDGE_FAILED = 0x0;
 | 
			
		||||
    /// @dev Precision of Kyber rates.
 | 
			
		||||
    uint256 constant private KYBER_RATE_BASE = 10 ** 18;
 | 
			
		||||
 | 
			
		||||
    // solhint-disable no-empty-blocks
 | 
			
		||||
    /// @dev Payable fallback to receive ETH from Kyber/WETH.
 | 
			
		||||
    function ()
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
    {
 | 
			
		||||
        // Poor man's receive in 0.5.9
 | 
			
		||||
        require(msg.data.length == 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Callback for `IKyberBridge`. Tries to buy `amount` of
 | 
			
		||||
    ///      `toTokenAddress` tokens by selling the entirety of the opposing asset
 | 
			
		||||
    ///      to the `KyberNetworkProxy` contract, then transfers the bought
 | 
			
		||||
    ///      tokens to `to`.
 | 
			
		||||
    /// @param toTokenAddress The token to give to `to`.
 | 
			
		||||
    /// @param from The maker (this contract).
 | 
			
		||||
    /// @param to The recipient of the bought tokens.
 | 
			
		||||
    /// @param amount Minimum amount of `toTokenAddress` tokens to buy.
 | 
			
		||||
    /// @param bridgeData The abi-encoeded "from" token address.
 | 
			
		||||
    /// @return success The magic bytes if successful.
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address toTokenAddress,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        TradeState memory state;
 | 
			
		||||
        state.kyber = IKyberNetworkProxy(_getKyberNetworkProxyAddress());
 | 
			
		||||
        state.weth = IEtherToken(_getWethAddress());
 | 
			
		||||
        // Decode the bridge data to get the `fromTokenAddress`.
 | 
			
		||||
        (state.fromTokenAddress, state.hint) = abi.decode(bridgeData, (address, bytes));
 | 
			
		||||
        // Query the balance of "from" tokens.
 | 
			
		||||
        state.fromTokenBalance = IERC20Token(state.fromTokenAddress).balanceOf(address(this));
 | 
			
		||||
        if (state.fromTokenBalance == 0) {
 | 
			
		||||
            // Return failure if no input tokens.
 | 
			
		||||
            return BRIDGE_FAILED;
 | 
			
		||||
        }
 | 
			
		||||
        if (state.fromTokenAddress == toTokenAddress) {
 | 
			
		||||
            // Just transfer the tokens if they're the same.
 | 
			
		||||
            LibERC20Token.transfer(state.fromTokenAddress, to, state.fromTokenBalance);
 | 
			
		||||
            return BRIDGE_SUCCESS;
 | 
			
		||||
        }
 | 
			
		||||
        if (state.fromTokenAddress == address(state.weth)) {
 | 
			
		||||
            // From WETH
 | 
			
		||||
            state.fromTokenAddress = KYBER_ETH_ADDRESS;
 | 
			
		||||
            state.payableAmount = state.fromTokenBalance;
 | 
			
		||||
            state.weth.withdraw(state.fromTokenBalance);
 | 
			
		||||
        } else {
 | 
			
		||||
            LibERC20Token.approveIfBelow(
 | 
			
		||||
                state.fromTokenAddress,
 | 
			
		||||
                address(state.kyber),
 | 
			
		||||
                state.fromTokenBalance
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        bool isToTokenWeth = toTokenAddress == address(state.weth);
 | 
			
		||||
 | 
			
		||||
        // Try to sell all of this contract's input token balance through
 | 
			
		||||
        // `KyberNetworkProxy.trade()`.
 | 
			
		||||
        uint256 boughtAmount = state.kyber.tradeWithHint.value(state.payableAmount)(
 | 
			
		||||
            // Input token.
 | 
			
		||||
            state.fromTokenAddress,
 | 
			
		||||
            // Sell amount.
 | 
			
		||||
            state.fromTokenBalance,
 | 
			
		||||
            // Output token.
 | 
			
		||||
            isToTokenWeth ? KYBER_ETH_ADDRESS : toTokenAddress,
 | 
			
		||||
            // Transfer to this contract if converting to ETH, otherwise
 | 
			
		||||
            // transfer directly to the recipient.
 | 
			
		||||
            isToTokenWeth ? address(uint160(address(this))) : address(uint160(to)),
 | 
			
		||||
            // Buy as much as possible.
 | 
			
		||||
            uint256(-1),
 | 
			
		||||
            // The minimum conversion rate
 | 
			
		||||
            1,
 | 
			
		||||
            // No affiliate address.
 | 
			
		||||
            address(0),
 | 
			
		||||
            state.hint
 | 
			
		||||
        );
 | 
			
		||||
        // Wrap ETH output and transfer to recipient.
 | 
			
		||||
        if (isToTokenWeth) {
 | 
			
		||||
            state.weth.deposit.value(boughtAmount)();
 | 
			
		||||
            state.weth.transfer(to, boughtAmount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        emit ERC20BridgeTransfer(
 | 
			
		||||
            state.fromTokenAddress == KYBER_ETH_ADDRESS ? address(state.weth) : state.fromTokenAddress,
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            state.fromTokenBalance,
 | 
			
		||||
            boughtAmount,
 | 
			
		||||
            from,
 | 
			
		||||
            to
 | 
			
		||||
        );
 | 
			
		||||
        return BRIDGE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
 | 
			
		||||
    ///      and sign for itself in orders. Always succeeds.
 | 
			
		||||
    /// @return magicValue Magic success bytes, always.
 | 
			
		||||
    function isValidSignature(
 | 
			
		||||
        bytes32,
 | 
			
		||||
        bytes calldata
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes4 magicValue)
 | 
			
		||||
    {
 | 
			
		||||
        return LEGACY_WALLET_MAGIC_VALUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,94 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
			
		||||
import "../interfaces/IERC20Bridge.sol";
 | 
			
		||||
import "../interfaces/IMStable.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract MStableBridge is
 | 
			
		||||
    IERC20Bridge,
 | 
			
		||||
    IWallet,
 | 
			
		||||
    DeploymentConstants
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /// @dev Swaps specified tokens against the mStable mUSD contract
 | 
			
		||||
    /// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT).
 | 
			
		||||
    /// @param from The maker (this contract).
 | 
			
		||||
    /// @param to The recipient of the bought tokens.
 | 
			
		||||
    /// @param amount Minimum amount of `toTokenAddress` tokens to buy.
 | 
			
		||||
    /// @param bridgeData The abi-encoded "from" token address.
 | 
			
		||||
    /// @return success The magic bytes if successful.
 | 
			
		||||
    // solhint-disable no-unused-vars
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address toTokenAddress,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        // Decode the bridge data to get the `fromTokenAddress`.
 | 
			
		||||
        (address fromTokenAddress) = abi.decode(bridgeData, (address));
 | 
			
		||||
 | 
			
		||||
        IMStable exchange = IMStable(_getMUsdAddress());
 | 
			
		||||
        uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
 | 
			
		||||
        // Grant an allowance to the exchange to spend `fromTokenAddress` token.
 | 
			
		||||
        LibERC20Token.approveIfBelow(fromTokenAddress, address(exchange), fromTokenBalance);
 | 
			
		||||
 | 
			
		||||
        // Try to sell all of this contract's `fromTokenAddress` token balance.
 | 
			
		||||
        uint256 boughtAmount = exchange.swap(
 | 
			
		||||
            fromTokenAddress,
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            fromTokenBalance,
 | 
			
		||||
            to
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        emit ERC20BridgeTransfer(
 | 
			
		||||
            fromTokenAddress,
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            fromTokenBalance,
 | 
			
		||||
            boughtAmount,
 | 
			
		||||
            from,
 | 
			
		||||
            to
 | 
			
		||||
        );
 | 
			
		||||
        return BRIDGE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
 | 
			
		||||
    ///      and sign for itself in orders. Always succeeds.
 | 
			
		||||
    /// @return magicValue Magic success bytes, always.
 | 
			
		||||
    function isValidSignature(
 | 
			
		||||
        bytes32,
 | 
			
		||||
        bytes calldata
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes4 magicValue)
 | 
			
		||||
    {
 | 
			
		||||
        return LEGACY_WALLET_MAGIC_VALUE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.16;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
			
		||||
import "../interfaces/IGasToken.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract MixinGasToken is
 | 
			
		||||
    DeploymentConstants
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /// @dev Frees gas tokens based on the amount of gas consumed in the function
 | 
			
		||||
    modifier freesGasTokens {
 | 
			
		||||
        uint256 gasBefore = gasleft();
 | 
			
		||||
        _;
 | 
			
		||||
        IGasToken gst = IGasToken(_getGstAddress());
 | 
			
		||||
        if (address(gst) != address(0)) {
 | 
			
		||||
            // (gasUsed + FREE_BASE) / (2 * REIMBURSE - FREE_TOKEN)
 | 
			
		||||
            //            14154             24000        6870
 | 
			
		||||
            uint256 value = (gasBefore - gasleft() + 14154) / 41130;
 | 
			
		||||
            gst.freeUpTo(value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Frees gas tokens using the balance of `from`. Amount freed is based
 | 
			
		||||
    ///     on the gas consumed in the function
 | 
			
		||||
    modifier freesGasTokensFromCollector() {
 | 
			
		||||
        uint256 gasBefore = gasleft();
 | 
			
		||||
        _;
 | 
			
		||||
        IGasToken gst = IGasToken(_getGstAddress());
 | 
			
		||||
        if (address(gst) != address(0)) {
 | 
			
		||||
            // (gasUsed + FREE_BASE) / (2 * REIMBURSE - FREE_TOKEN)
 | 
			
		||||
            //            14154             24000        6870
 | 
			
		||||
            uint256 value = (gasBefore - gasleft() + 14154) / 41130;
 | 
			
		||||
            gst.freeFromUpTo(_getGstCollectorAddress(), value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										148
									
								
								contracts/asset-proxy/contracts/src/bridges/MooniswapBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								contracts/asset-proxy/contracts/src/bridges/MooniswapBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,148 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.5.9;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
			
		||||
import "../interfaces/IERC20Bridge.sol";
 | 
			
		||||
import "../interfaces/IMooniswap.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable space-after-comma
 | 
			
		||||
// solhint-disable not-rely-on-time
 | 
			
		||||
contract MooniswapBridge is
 | 
			
		||||
    IERC20Bridge,
 | 
			
		||||
    IWallet,
 | 
			
		||||
    DeploymentConstants
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    struct TransferState {
 | 
			
		||||
        IMooniswap pool;
 | 
			
		||||
        uint256 fromTokenBalance;
 | 
			
		||||
        IEtherToken weth;
 | 
			
		||||
        uint256 boughtAmount;
 | 
			
		||||
        address fromTokenAddress;
 | 
			
		||||
        address toTokenAddress;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // solhint-disable no-empty-blocks
 | 
			
		||||
    /// @dev Payable fallback to receive ETH from uniswap.
 | 
			
		||||
    function ()
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
 | 
			
		||||
    ///      `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
 | 
			
		||||
    ///      token encoded in the bridge data.
 | 
			
		||||
    /// @param toTokenAddress The token to buy and transfer to `to`.
 | 
			
		||||
    /// @param from The maker (this contract).
 | 
			
		||||
    /// @param to The recipient of the bought tokens.
 | 
			
		||||
    /// @param amount Minimum amount of `toTokenAddress` tokens to buy.
 | 
			
		||||
    /// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress
 | 
			
		||||
    /// @return success The magic bytes if successful.
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address toTokenAddress,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        // State memory object to avoid stack overflows.
 | 
			
		||||
        TransferState memory state;
 | 
			
		||||
        // Decode the bridge data to get the `fromTokenAddress`.
 | 
			
		||||
        address fromTokenAddress = abi.decode(bridgeData, (address));
 | 
			
		||||
        // Get the weth contract.
 | 
			
		||||
        state.weth = IEtherToken(_getWethAddress());
 | 
			
		||||
        // Get our balance of `fromTokenAddress` token.
 | 
			
		||||
        state.fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
 | 
			
		||||
 | 
			
		||||
        state.fromTokenAddress = fromTokenAddress == address(state.weth) ? address(0) : fromTokenAddress;
 | 
			
		||||
        state.toTokenAddress = toTokenAddress == address(state.weth) ? address(0) : toTokenAddress;
 | 
			
		||||
        state.pool = IMooniswap(
 | 
			
		||||
            IMooniswapRegistry(_getMooniswapAddress()).pools(
 | 
			
		||||
                state.fromTokenAddress,
 | 
			
		||||
                state.toTokenAddress
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // withdraw WETH to ETH
 | 
			
		||||
        if (state.fromTokenAddress == address(0)) {
 | 
			
		||||
            state.weth.withdraw(state.fromTokenBalance);
 | 
			
		||||
        } else {
 | 
			
		||||
            // Grant the pool an allowance.
 | 
			
		||||
            LibERC20Token.approveIfBelow(
 | 
			
		||||
                state.fromTokenAddress,
 | 
			
		||||
                address(state.pool),
 | 
			
		||||
                state.fromTokenBalance
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        uint256 ethValue = state.fromTokenAddress == address(0) ? state.fromTokenBalance : 0;
 | 
			
		||||
        state.boughtAmount = state.pool.swap.value(ethValue)(
 | 
			
		||||
            state.fromTokenAddress,
 | 
			
		||||
            state.toTokenAddress,
 | 
			
		||||
            state.fromTokenBalance,
 | 
			
		||||
            amount,
 | 
			
		||||
            address(0)
 | 
			
		||||
        );
 | 
			
		||||
        // Deposit to WETH
 | 
			
		||||
        if (state.toTokenAddress == address(0)) {
 | 
			
		||||
            state.weth.deposit.value(state.boughtAmount)();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Transfer funds to `to`
 | 
			
		||||
        LibERC20Token.transfer(toTokenAddress, to, state.boughtAmount);
 | 
			
		||||
 | 
			
		||||
        emit ERC20BridgeTransfer(
 | 
			
		||||
            // input token
 | 
			
		||||
            fromTokenAddress,
 | 
			
		||||
            // output token
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            // input token amount
 | 
			
		||||
            state.fromTokenBalance,
 | 
			
		||||
            // output token amount
 | 
			
		||||
            state.boughtAmount,
 | 
			
		||||
            from,
 | 
			
		||||
            to
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return BRIDGE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
 | 
			
		||||
    ///      and sign for itself in orders. Always succeeds.
 | 
			
		||||
    /// @return magicValue Success bytes, always.
 | 
			
		||||
    function isValidSignature(
 | 
			
		||||
        bytes32,
 | 
			
		||||
        bytes calldata
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes4 magicValue)
 | 
			
		||||
    {
 | 
			
		||||
        return LEGACY_WALLET_MAGIC_VALUE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										95
									
								
								contracts/asset-proxy/contracts/src/bridges/ShellBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								contracts/asset-proxy/contracts/src/bridges/ShellBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,95 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
			
		||||
import "../interfaces/IERC20Bridge.sol";
 | 
			
		||||
import "../interfaces/IShell.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract ShellBridge is
 | 
			
		||||
    IERC20Bridge,
 | 
			
		||||
    IWallet,
 | 
			
		||||
    DeploymentConstants
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /// @dev Swaps specified tokens against the Shell contract
 | 
			
		||||
    /// @param toTokenAddress The token to give to `to`.
 | 
			
		||||
    /// @param from The maker (this contract).
 | 
			
		||||
    /// @param to The recipient of the bought tokens.
 | 
			
		||||
    /// @param amount Minimum amount of `toTokenAddress` tokens to buy.
 | 
			
		||||
    /// @param bridgeData The abi-encoded "from" token address.
 | 
			
		||||
    /// @return success The magic bytes if successful.
 | 
			
		||||
    // solhint-disable no-unused-vars
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address toTokenAddress,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        // Decode the bridge data to get the `fromTokenAddress` and `pool`.
 | 
			
		||||
        (address fromTokenAddress, address pool) = abi.decode(bridgeData, (address, address));
 | 
			
		||||
 | 
			
		||||
        uint256 fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
 | 
			
		||||
        // Grant an allowance to the exchange to spend `fromTokenAddress` token.
 | 
			
		||||
        LibERC20Token.approveIfBelow(fromTokenAddress, pool, fromTokenBalance);
 | 
			
		||||
 | 
			
		||||
        // Try to sell all of this contract's `fromTokenAddress` token balance.
 | 
			
		||||
        uint256 boughtAmount = IShell(pool).originSwap(
 | 
			
		||||
            fromTokenAddress,
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            fromTokenBalance,
 | 
			
		||||
            amount, // min amount
 | 
			
		||||
            block.timestamp + 1
 | 
			
		||||
        );
 | 
			
		||||
        LibERC20Token.transfer(toTokenAddress, to, boughtAmount);
 | 
			
		||||
 | 
			
		||||
        emit ERC20BridgeTransfer(
 | 
			
		||||
            fromTokenAddress,
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            fromTokenBalance,
 | 
			
		||||
            boughtAmount,
 | 
			
		||||
            from,
 | 
			
		||||
            to
 | 
			
		||||
        );
 | 
			
		||||
        return BRIDGE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
 | 
			
		||||
    ///      and sign for itself in orders. Always succeeds.
 | 
			
		||||
    /// @return magicValue Magic success bytes, always.
 | 
			
		||||
    function isValidSignature(
 | 
			
		||||
        bytes32,
 | 
			
		||||
        bytes calldata
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes4 magicValue)
 | 
			
		||||
    {
 | 
			
		||||
        return LEGACY_WALLET_MAGIC_VALUE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										119
									
								
								contracts/asset-proxy/contracts/src/bridges/SnowSwapBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								contracts/asset-proxy/contracts/src/bridges/SnowSwapBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
			
		||||
import "../interfaces/IERC20Bridge.sol";
 | 
			
		||||
import "../interfaces/ICurve.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable not-rely-on-time
 | 
			
		||||
// solhint-disable space-after-comma
 | 
			
		||||
contract SnowSwapBridge is
 | 
			
		||||
    IERC20Bridge,
 | 
			
		||||
    IWallet,
 | 
			
		||||
    DeploymentConstants
 | 
			
		||||
{
 | 
			
		||||
    struct SnowSwapBridgeData {
 | 
			
		||||
        address curveAddress;
 | 
			
		||||
        bytes4 exchangeFunctionSelector;
 | 
			
		||||
        address fromTokenAddress;
 | 
			
		||||
        int128 fromCoinIdx;
 | 
			
		||||
        int128 toCoinIdx;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Callback for `ICurve`. Tries to buy `amount` of
 | 
			
		||||
    ///      `toTokenAddress` tokens by selling the entirety of the opposing asset
 | 
			
		||||
    ///      (DAI, USDC) to the Curve contract, then transfers the bought
 | 
			
		||||
    ///      tokens to `to`.
 | 
			
		||||
    /// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT).
 | 
			
		||||
    /// @param from The maker (this contract).
 | 
			
		||||
    /// @param to The recipient of the bought tokens.
 | 
			
		||||
    /// @param amount Minimum amount of `toTokenAddress` tokens to buy.
 | 
			
		||||
    /// @param bridgeData The abi-encoeded "from" token address.
 | 
			
		||||
    /// @return success The magic bytes if successful.
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address toTokenAddress,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        // Decode the bridge data to get the SnowSwap metadata.
 | 
			
		||||
        SnowSwapBridgeData memory data = abi.decode(bridgeData, (SnowSwapBridgeData));
 | 
			
		||||
 | 
			
		||||
        require(toTokenAddress != data.fromTokenAddress, "SnowSwapBridge/INVALID_PAIR");
 | 
			
		||||
        uint256 fromTokenBalance = IERC20Token(data.fromTokenAddress).balanceOf(address(this));
 | 
			
		||||
        // Grant an allowance to the exchange to spend `fromTokenAddress` token.
 | 
			
		||||
        LibERC20Token.approveIfBelow(data.fromTokenAddress, data.curveAddress, fromTokenBalance);
 | 
			
		||||
 | 
			
		||||
        // Try to sell all of this contract's `fromTokenAddress` token balance.
 | 
			
		||||
        {
 | 
			
		||||
            (bool didSucceed, bytes memory resultData) =
 | 
			
		||||
                data.curveAddress.call(abi.encodeWithSelector(
 | 
			
		||||
                    data.exchangeFunctionSelector,
 | 
			
		||||
                    data.fromCoinIdx,
 | 
			
		||||
                    data.toCoinIdx,
 | 
			
		||||
                    // dx
 | 
			
		||||
                    fromTokenBalance,
 | 
			
		||||
                    // min dy
 | 
			
		||||
                    amount
 | 
			
		||||
                ));
 | 
			
		||||
            if (!didSucceed) {
 | 
			
		||||
                assembly { revert(add(resultData, 32), mload(resultData)) }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this));
 | 
			
		||||
        // Transfer the converted `toToken`s to `to`.
 | 
			
		||||
        LibERC20Token.transfer(toTokenAddress, to, toTokenBalance);
 | 
			
		||||
 | 
			
		||||
        emit ERC20BridgeTransfer(
 | 
			
		||||
            data.fromTokenAddress,
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            fromTokenBalance,
 | 
			
		||||
            toTokenBalance,
 | 
			
		||||
            from,
 | 
			
		||||
            to
 | 
			
		||||
        );
 | 
			
		||||
        return BRIDGE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
 | 
			
		||||
    ///      and sign for itself in orders. Always succeeds.
 | 
			
		||||
    /// @return magicValue Magic success bytes, always.
 | 
			
		||||
    function isValidSignature(
 | 
			
		||||
        bytes32,
 | 
			
		||||
        bytes calldata
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes4 magicValue)
 | 
			
		||||
    {
 | 
			
		||||
        return LEGACY_WALLET_MAGIC_VALUE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										136
									
								
								contracts/asset-proxy/contracts/src/bridges/SushiSwapBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								contracts/asset-proxy/contracts/src/bridges/SushiSwapBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,136 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.5.9;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
			
		||||
import "../interfaces/IUniswapV2Router01.sol";
 | 
			
		||||
import "../interfaces/IERC20Bridge.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable space-after-comma
 | 
			
		||||
// solhint-disable not-rely-on-time
 | 
			
		||||
contract SushiSwapBridge is
 | 
			
		||||
    IERC20Bridge,
 | 
			
		||||
    IWallet,
 | 
			
		||||
    DeploymentConstants
 | 
			
		||||
{
 | 
			
		||||
    struct TransferState {
 | 
			
		||||
        address[] path;
 | 
			
		||||
        address router;
 | 
			
		||||
        uint256 fromTokenBalance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
 | 
			
		||||
    ///      `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
 | 
			
		||||
    ///      token encoded in the bridge data.
 | 
			
		||||
    /// @param toTokenAddress The token to buy and transfer to `to`.
 | 
			
		||||
    /// @param from The maker (this contract).
 | 
			
		||||
    /// @param to The recipient of the bought tokens.
 | 
			
		||||
    /// @param amount Minimum amount of `toTokenAddress` tokens to buy.
 | 
			
		||||
    /// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress
 | 
			
		||||
    /// @return success The magic bytes if successful.
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address toTokenAddress,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        // hold variables to get around stack depth limitations
 | 
			
		||||
        TransferState memory state;
 | 
			
		||||
 | 
			
		||||
        // Decode the bridge data to get the `fromTokenAddress`.
 | 
			
		||||
        // solhint-disable indent
 | 
			
		||||
        (state.path, state.router) = abi.decode(bridgeData, (address[], address));
 | 
			
		||||
        // solhint-enable indent
 | 
			
		||||
 | 
			
		||||
        require(state.path.length >= 2, "SushiSwapBridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
 | 
			
		||||
        require(state.path[state.path.length - 1] == toTokenAddress, "SushiSwapBridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN");
 | 
			
		||||
 | 
			
		||||
        // Just transfer the tokens if they're the same.
 | 
			
		||||
        if (state.path[0] == toTokenAddress) {
 | 
			
		||||
            LibERC20Token.transfer(state.path[0], to, amount);
 | 
			
		||||
            return BRIDGE_SUCCESS;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Get our balance of `fromTokenAddress` token.
 | 
			
		||||
        state.fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this));
 | 
			
		||||
 | 
			
		||||
        // Grant the SushiSwap router an allowance.
 | 
			
		||||
        LibERC20Token.approveIfBelow(
 | 
			
		||||
            state.path[0],
 | 
			
		||||
            state.router,
 | 
			
		||||
            state.fromTokenBalance
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Buy as much `toTokenAddress` token with `fromTokenAddress` token
 | 
			
		||||
        // and transfer it to `to`.
 | 
			
		||||
        IUniswapV2Router01 router = IUniswapV2Router01(state.router);
 | 
			
		||||
        uint[] memory amounts = router.swapExactTokensForTokens(
 | 
			
		||||
             // Sell all tokens we hold.
 | 
			
		||||
            state.fromTokenBalance,
 | 
			
		||||
             // Minimum buy amount.
 | 
			
		||||
            amount,
 | 
			
		||||
            // Convert `fromTokenAddress` to `toTokenAddress`.
 | 
			
		||||
            state.path,
 | 
			
		||||
            // Recipient is `to`.
 | 
			
		||||
            to,
 | 
			
		||||
            // Expires after this block.
 | 
			
		||||
            block.timestamp
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        emit ERC20BridgeTransfer(
 | 
			
		||||
            // input token
 | 
			
		||||
            state.path[0],
 | 
			
		||||
            // output token
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            // input token amount
 | 
			
		||||
            state.fromTokenBalance,
 | 
			
		||||
            // output token amount
 | 
			
		||||
            amounts[amounts.length - 1],
 | 
			
		||||
            from,
 | 
			
		||||
            to
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return BRIDGE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
 | 
			
		||||
    ///      and sign for itself in orders. Always succeeds.
 | 
			
		||||
    /// @return magicValue Success bytes, always.
 | 
			
		||||
    function isValidSignature(
 | 
			
		||||
        bytes32,
 | 
			
		||||
        bytes calldata
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes4 magicValue)
 | 
			
		||||
    {
 | 
			
		||||
        return LEGACY_WALLET_MAGIC_VALUE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										119
									
								
								contracts/asset-proxy/contracts/src/bridges/SwerveBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								contracts/asset-proxy/contracts/src/bridges/SwerveBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
			
		||||
import "../interfaces/IERC20Bridge.sol";
 | 
			
		||||
import "../interfaces/ICurve.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable not-rely-on-time
 | 
			
		||||
// solhint-disable space-after-comma
 | 
			
		||||
contract SwerveBridge is
 | 
			
		||||
    IERC20Bridge,
 | 
			
		||||
    IWallet,
 | 
			
		||||
    DeploymentConstants
 | 
			
		||||
{
 | 
			
		||||
    struct SwerveBridgeData {
 | 
			
		||||
        address curveAddress;
 | 
			
		||||
        bytes4 exchangeFunctionSelector;
 | 
			
		||||
        address fromTokenAddress;
 | 
			
		||||
        int128 fromCoinIdx;
 | 
			
		||||
        int128 toCoinIdx;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Callback for `ICurve`. Tries to buy `amount` of
 | 
			
		||||
    ///      `toTokenAddress` tokens by selling the entirety of the opposing asset
 | 
			
		||||
    ///      (DAI, USDC) to the Curve contract, then transfers the bought
 | 
			
		||||
    ///      tokens to `to`.
 | 
			
		||||
    /// @param toTokenAddress The token to give to `to` (i.e DAI, USDC, USDT).
 | 
			
		||||
    /// @param from The maker (this contract).
 | 
			
		||||
    /// @param to The recipient of the bought tokens.
 | 
			
		||||
    /// @param amount Minimum amount of `toTokenAddress` tokens to buy.
 | 
			
		||||
    /// @param bridgeData The abi-encoeded "from" token address.
 | 
			
		||||
    /// @return success The magic bytes if successful.
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address toTokenAddress,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        // Decode the bridge data to get the SwerveBridgeData metadata.
 | 
			
		||||
        SwerveBridgeData memory data = abi.decode(bridgeData, (SwerveBridgeData));
 | 
			
		||||
 | 
			
		||||
        require(toTokenAddress != data.fromTokenAddress, "SwerveBridge/INVALID_PAIR");
 | 
			
		||||
        uint256 fromTokenBalance = IERC20Token(data.fromTokenAddress).balanceOf(address(this));
 | 
			
		||||
        // Grant an allowance to the exchange to spend `fromTokenAddress` token.
 | 
			
		||||
        LibERC20Token.approveIfBelow(data.fromTokenAddress, data.curveAddress, fromTokenBalance);
 | 
			
		||||
 | 
			
		||||
        // Try to sell all of this contract's `fromTokenAddress` token balance.
 | 
			
		||||
        {
 | 
			
		||||
            (bool didSucceed, bytes memory resultData) =
 | 
			
		||||
                data.curveAddress.call(abi.encodeWithSelector(
 | 
			
		||||
                    data.exchangeFunctionSelector,
 | 
			
		||||
                    data.fromCoinIdx,
 | 
			
		||||
                    data.toCoinIdx,
 | 
			
		||||
                    // dx
 | 
			
		||||
                    fromTokenBalance,
 | 
			
		||||
                    // min dy
 | 
			
		||||
                    amount
 | 
			
		||||
                ));
 | 
			
		||||
            if (!didSucceed) {
 | 
			
		||||
                assembly { revert(add(resultData, 32), mload(resultData)) }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        uint256 toTokenBalance = IERC20Token(toTokenAddress).balanceOf(address(this));
 | 
			
		||||
        // Transfer the converted `toToken`s to `to`.
 | 
			
		||||
        LibERC20Token.transfer(toTokenAddress, to, toTokenBalance);
 | 
			
		||||
 | 
			
		||||
        emit ERC20BridgeTransfer(
 | 
			
		||||
            data.fromTokenAddress,
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            fromTokenBalance,
 | 
			
		||||
            toTokenBalance,
 | 
			
		||||
            from,
 | 
			
		||||
            to
 | 
			
		||||
        );
 | 
			
		||||
        return BRIDGE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
 | 
			
		||||
    ///      and sign for itself in orders. Always succeeds.
 | 
			
		||||
    /// @return magicValue Magic success bytes, always.
 | 
			
		||||
    function isValidSignature(
 | 
			
		||||
        bytes32,
 | 
			
		||||
        bytes calldata
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes4 magicValue)
 | 
			
		||||
    {
 | 
			
		||||
        return LEGACY_WALLET_MAGIC_VALUE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										220
									
								
								contracts/asset-proxy/contracts/src/bridges/UniswapBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								contracts/asset-proxy/contracts/src/bridges/UniswapBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,220 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
			
		||||
import "../interfaces/IUniswapExchangeFactory.sol";
 | 
			
		||||
import "../interfaces/IUniswapExchange.sol";
 | 
			
		||||
import "../interfaces/IERC20Bridge.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable space-after-comma
 | 
			
		||||
// solhint-disable not-rely-on-time
 | 
			
		||||
contract UniswapBridge is
 | 
			
		||||
    IERC20Bridge,
 | 
			
		||||
    IWallet,
 | 
			
		||||
    DeploymentConstants
 | 
			
		||||
{
 | 
			
		||||
    // Struct to hold `bridgeTransferFrom()` local variables in memory and to avoid
 | 
			
		||||
    // stack overflows.
 | 
			
		||||
    struct TransferState {
 | 
			
		||||
        IUniswapExchange exchange;
 | 
			
		||||
        uint256 fromTokenBalance;
 | 
			
		||||
        IEtherToken weth;
 | 
			
		||||
        uint256 boughtAmount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // solhint-disable no-empty-blocks
 | 
			
		||||
    /// @dev Payable fallback to receive ETH from uniswap.
 | 
			
		||||
    function ()
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
 | 
			
		||||
    ///      `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
 | 
			
		||||
    ///      token encoded in the bridge data.
 | 
			
		||||
    /// @param toTokenAddress The token to buy and transfer to `to`.
 | 
			
		||||
    /// @param from The maker (this contract).
 | 
			
		||||
    /// @param to The recipient of the bought tokens.
 | 
			
		||||
    /// @param amount Minimum amount of `toTokenAddress` tokens to buy.
 | 
			
		||||
    /// @param bridgeData The abi-encoded "from" token address.
 | 
			
		||||
    /// @return success The magic bytes if successful.
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address toTokenAddress,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        // State memory object to avoid stack overflows.
 | 
			
		||||
        TransferState memory state;
 | 
			
		||||
        // Decode the bridge data to get the `fromTokenAddress`.
 | 
			
		||||
        (address fromTokenAddress) = abi.decode(bridgeData, (address));
 | 
			
		||||
 | 
			
		||||
        // Just transfer the tokens if they're the same.
 | 
			
		||||
        if (fromTokenAddress == toTokenAddress) {
 | 
			
		||||
            LibERC20Token.transfer(fromTokenAddress, to, amount);
 | 
			
		||||
            return BRIDGE_SUCCESS;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Get the exchange for the token pair.
 | 
			
		||||
        state.exchange = _getUniswapExchangeForTokenPair(
 | 
			
		||||
            fromTokenAddress,
 | 
			
		||||
            toTokenAddress
 | 
			
		||||
        );
 | 
			
		||||
        // Get our balance of `fromTokenAddress` token.
 | 
			
		||||
        state.fromTokenBalance = IERC20Token(fromTokenAddress).balanceOf(address(this));
 | 
			
		||||
        // Get the weth contract.
 | 
			
		||||
        state.weth = IEtherToken(_getWethAddress());
 | 
			
		||||
 | 
			
		||||
        // Convert from WETH to a token.
 | 
			
		||||
        if (fromTokenAddress == address(state.weth)) {
 | 
			
		||||
            // Unwrap the WETH.
 | 
			
		||||
            state.weth.withdraw(state.fromTokenBalance);
 | 
			
		||||
            // Buy as much of `toTokenAddress` token with ETH as possible and
 | 
			
		||||
            // transfer it to `to`.
 | 
			
		||||
            state.boughtAmount = state.exchange.ethToTokenTransferInput.value(state.fromTokenBalance)(
 | 
			
		||||
                // Minimum buy amount.
 | 
			
		||||
                amount,
 | 
			
		||||
                // Expires after this block.
 | 
			
		||||
                block.timestamp,
 | 
			
		||||
                // Recipient is `to`.
 | 
			
		||||
                to
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
        // Convert from a token to WETH.
 | 
			
		||||
        } else if (toTokenAddress == address(state.weth)) {
 | 
			
		||||
            // Grant the exchange an allowance.
 | 
			
		||||
            _grantExchangeAllowance(state.exchange, fromTokenAddress, state.fromTokenBalance);
 | 
			
		||||
            // Buy as much ETH with `fromTokenAddress` token as possible.
 | 
			
		||||
            state.boughtAmount = state.exchange.tokenToEthSwapInput(
 | 
			
		||||
                // Sell all tokens we hold.
 | 
			
		||||
                state.fromTokenBalance,
 | 
			
		||||
                // Minimum buy amount.
 | 
			
		||||
                amount,
 | 
			
		||||
                // Expires after this block.
 | 
			
		||||
                block.timestamp
 | 
			
		||||
            );
 | 
			
		||||
            // Wrap the ETH.
 | 
			
		||||
            state.weth.deposit.value(state.boughtAmount)();
 | 
			
		||||
            // Transfer the WETH to `to`.
 | 
			
		||||
            IEtherToken(toTokenAddress).transfer(to, state.boughtAmount);
 | 
			
		||||
 | 
			
		||||
        // Convert from one token to another.
 | 
			
		||||
        } else {
 | 
			
		||||
            // Grant the exchange an allowance.
 | 
			
		||||
            _grantExchangeAllowance(state.exchange, fromTokenAddress, state.fromTokenBalance);
 | 
			
		||||
            // Buy as much `toTokenAddress` token with `fromTokenAddress` token
 | 
			
		||||
            // and transfer it to `to`.
 | 
			
		||||
            state.boughtAmount = state.exchange.tokenToTokenTransferInput(
 | 
			
		||||
                // Sell all tokens we hold.
 | 
			
		||||
                state.fromTokenBalance,
 | 
			
		||||
                // Minimum buy amount.
 | 
			
		||||
                amount,
 | 
			
		||||
                // Must buy at least 1 intermediate ETH.
 | 
			
		||||
                1,
 | 
			
		||||
                // Expires after this block.
 | 
			
		||||
                block.timestamp,
 | 
			
		||||
                // Recipient is `to`.
 | 
			
		||||
                to,
 | 
			
		||||
                // Convert to `toTokenAddress`.
 | 
			
		||||
                toTokenAddress
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        emit ERC20BridgeTransfer(
 | 
			
		||||
            fromTokenAddress,
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            state.fromTokenBalance,
 | 
			
		||||
            state.boughtAmount,
 | 
			
		||||
            from,
 | 
			
		||||
            to
 | 
			
		||||
        );
 | 
			
		||||
        return BRIDGE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
 | 
			
		||||
    ///      and sign for itself in orders. Always succeeds.
 | 
			
		||||
    /// @return magicValue Success bytes, always.
 | 
			
		||||
    function isValidSignature(
 | 
			
		||||
        bytes32,
 | 
			
		||||
        bytes calldata
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes4 magicValue)
 | 
			
		||||
    {
 | 
			
		||||
        return LEGACY_WALLET_MAGIC_VALUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Grants an unlimited allowance to the exchange for its token
 | 
			
		||||
    ///      on behalf of this contract.
 | 
			
		||||
    /// @param exchange The Uniswap token exchange.
 | 
			
		||||
    /// @param tokenAddress The token address for the exchange.
 | 
			
		||||
    /// @param minimumAllowance The minimum necessary allowance.
 | 
			
		||||
    function _grantExchangeAllowance(
 | 
			
		||||
        IUniswapExchange exchange,
 | 
			
		||||
        address tokenAddress,
 | 
			
		||||
        uint256 minimumAllowance
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
    {
 | 
			
		||||
        LibERC20Token.approveIfBelow(
 | 
			
		||||
            tokenAddress,
 | 
			
		||||
            address(exchange),
 | 
			
		||||
            minimumAllowance
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Retrieves the uniswap exchange for a given token pair.
 | 
			
		||||
    ///      In the case of a WETH-token exchange, this will be the non-WETH token.
 | 
			
		||||
    ///      In th ecase of a token-token exchange, this will be the first token.
 | 
			
		||||
    /// @param fromTokenAddress The address of the token we are converting from.
 | 
			
		||||
    /// @param toTokenAddress The address of the token we are converting to.
 | 
			
		||||
    /// @return exchange The uniswap exchange.
 | 
			
		||||
    function _getUniswapExchangeForTokenPair(
 | 
			
		||||
        address fromTokenAddress,
 | 
			
		||||
        address toTokenAddress
 | 
			
		||||
    )
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
        returns (IUniswapExchange exchange)
 | 
			
		||||
    {
 | 
			
		||||
        address exchangeTokenAddress = fromTokenAddress;
 | 
			
		||||
        // Whichever isn't WETH is the exchange token.
 | 
			
		||||
        if (fromTokenAddress == _getWethAddress()) {
 | 
			
		||||
            exchangeTokenAddress = toTokenAddress;
 | 
			
		||||
        }
 | 
			
		||||
        exchange = IUniswapExchange(
 | 
			
		||||
            IUniswapExchangeFactory(_getUniswapExchangeFactoryAddress())
 | 
			
		||||
            .getExchange(exchangeTokenAddress)
 | 
			
		||||
        );
 | 
			
		||||
        require(address(exchange) != address(0), "NO_UNISWAP_EXCHANGE_FOR_TOKEN");
 | 
			
		||||
        return exchange;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										135
									
								
								contracts/asset-proxy/contracts/src/bridges/UniswapV2Bridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								contracts/asset-proxy/contracts/src/bridges/UniswapV2Bridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,135 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.5.9;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/LibERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-exchange-libs/contracts/src/IWallet.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/DeploymentConstants.sol";
 | 
			
		||||
import "../interfaces/IUniswapV2Router01.sol";
 | 
			
		||||
import "../interfaces/IERC20Bridge.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable space-after-comma
 | 
			
		||||
// solhint-disable not-rely-on-time
 | 
			
		||||
contract UniswapV2Bridge is
 | 
			
		||||
    IERC20Bridge,
 | 
			
		||||
    IWallet,
 | 
			
		||||
    DeploymentConstants
 | 
			
		||||
{
 | 
			
		||||
    struct TransferState {
 | 
			
		||||
        address[] path;
 | 
			
		||||
        uint256 fromTokenBalance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Callback for `IERC20Bridge`. Tries to buy `amount` of
 | 
			
		||||
    ///      `toTokenAddress` tokens by selling the entirety of the `fromTokenAddress`
 | 
			
		||||
    ///      token encoded in the bridge data.
 | 
			
		||||
    /// @param toTokenAddress The token to buy and transfer to `to`.
 | 
			
		||||
    /// @param from The maker (this contract).
 | 
			
		||||
    /// @param to The recipient of the bought tokens.
 | 
			
		||||
    /// @param amount Minimum amount of `toTokenAddress` tokens to buy.
 | 
			
		||||
    /// @param bridgeData The abi-encoded path of token addresses. Last element must be toTokenAddress
 | 
			
		||||
    /// @return success The magic bytes if successful.
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address toTokenAddress,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        // hold variables to get around stack depth limitations
 | 
			
		||||
        TransferState memory state;
 | 
			
		||||
 | 
			
		||||
        // Decode the bridge data to get the `fromTokenAddress`.
 | 
			
		||||
        // solhint-disable indent
 | 
			
		||||
        state.path = abi.decode(bridgeData, (address[]));
 | 
			
		||||
        // solhint-enable indent
 | 
			
		||||
 | 
			
		||||
        require(state.path.length >= 2, "UniswapV2Bridge/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
 | 
			
		||||
        require(state.path[state.path.length - 1] == toTokenAddress, "UniswapV2Bridge/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN");
 | 
			
		||||
 | 
			
		||||
        // Just transfer the tokens if they're the same.
 | 
			
		||||
        if (state.path[0] == toTokenAddress) {
 | 
			
		||||
            LibERC20Token.transfer(state.path[0], to, amount);
 | 
			
		||||
            return BRIDGE_SUCCESS;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Get our balance of `fromTokenAddress` token.
 | 
			
		||||
        state.fromTokenBalance = IERC20Token(state.path[0]).balanceOf(address(this));
 | 
			
		||||
 | 
			
		||||
        // Grant the Uniswap router an allowance.
 | 
			
		||||
        LibERC20Token.approveIfBelow(
 | 
			
		||||
            state.path[0],
 | 
			
		||||
            _getUniswapV2Router01Address(),
 | 
			
		||||
            state.fromTokenBalance
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Buy as much `toTokenAddress` token with `fromTokenAddress` token
 | 
			
		||||
        // and transfer it to `to`.
 | 
			
		||||
        IUniswapV2Router01 router = IUniswapV2Router01(_getUniswapV2Router01Address());
 | 
			
		||||
        uint[] memory amounts = router.swapExactTokensForTokens(
 | 
			
		||||
             // Sell all tokens we hold.
 | 
			
		||||
            state.fromTokenBalance,
 | 
			
		||||
             // Minimum buy amount.
 | 
			
		||||
            amount,
 | 
			
		||||
            // Convert `fromTokenAddress` to `toTokenAddress`.
 | 
			
		||||
            state.path,
 | 
			
		||||
            // Recipient is `to`.
 | 
			
		||||
            to,
 | 
			
		||||
            // Expires after this block.
 | 
			
		||||
            block.timestamp
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        emit ERC20BridgeTransfer(
 | 
			
		||||
            // input token
 | 
			
		||||
            state.path[0],
 | 
			
		||||
            // output token
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            // input token amount
 | 
			
		||||
            state.fromTokenBalance,
 | 
			
		||||
            // output token amount
 | 
			
		||||
            amounts[amounts.length - 1],
 | 
			
		||||
            from,
 | 
			
		||||
            to
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return BRIDGE_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `SignatureType.Wallet` callback, so that this bridge can be the maker
 | 
			
		||||
    ///      and sign for itself in orders. Always succeeds.
 | 
			
		||||
    /// @return magicValue Success bytes, always.
 | 
			
		||||
    function isValidSignature(
 | 
			
		||||
        bytes32,
 | 
			
		||||
        bytes calldata
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes4 magicValue)
 | 
			
		||||
    {
 | 
			
		||||
        return LEGACY_WALLET_MAGIC_VALUE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,88 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
// solhint-disable
 | 
			
		||||
pragma solidity ^0.5.9;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// @dev Interface of the asset proxy's assetData.
 | 
			
		||||
// The asset proxies take an ABI encoded `bytes assetData` as argument.
 | 
			
		||||
// This argument is ABI encoded as one of the methods of this interface.
 | 
			
		||||
interface IAssetData {
 | 
			
		||||
 | 
			
		||||
    /// @dev Function signature for encoding ERC20 assetData.
 | 
			
		||||
    /// @param tokenAddress Address of ERC20Token contract.
 | 
			
		||||
    function ERC20Token(address tokenAddress)
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Function signature for encoding ERC721 assetData.
 | 
			
		||||
    /// @param tokenAddress Address of ERC721 token contract.
 | 
			
		||||
    /// @param tokenId Id of ERC721 token to be transferred.
 | 
			
		||||
    function ERC721Token(
 | 
			
		||||
        address tokenAddress,
 | 
			
		||||
        uint256 tokenId
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Function signature for encoding ERC1155 assetData.
 | 
			
		||||
    /// @param tokenAddress Address of ERC1155 token contract.
 | 
			
		||||
    /// @param tokenIds Array of ids of tokens to be transferred.
 | 
			
		||||
    /// @param values Array of values that correspond to each token id to be transferred.
 | 
			
		||||
    ///        Note that each value will be multiplied by the amount being filled in the order before transferring.
 | 
			
		||||
    /// @param callbackData Extra data to be passed to receiver's `onERC1155Received` callback function.
 | 
			
		||||
    function ERC1155Assets(
 | 
			
		||||
        address tokenAddress,
 | 
			
		||||
        uint256[] calldata tokenIds,
 | 
			
		||||
        uint256[] calldata values,
 | 
			
		||||
        bytes calldata callbackData
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Function signature for encoding MultiAsset assetData.
 | 
			
		||||
    /// @param values Array of amounts that correspond to each asset to be transferred.
 | 
			
		||||
    ///        Note that each value will be multiplied by the amount being filled in the order before transferring.
 | 
			
		||||
    /// @param nestedAssetData Array of assetData fields that will be be dispatched to their correspnding AssetProxy contract.
 | 
			
		||||
    function MultiAsset(
 | 
			
		||||
        uint256[] calldata values,
 | 
			
		||||
        bytes[] calldata nestedAssetData
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Function signature for encoding StaticCall assetData.
 | 
			
		||||
    /// @param staticCallTargetAddress Address that will execute the staticcall.
 | 
			
		||||
    /// @param staticCallData Data that will be executed via staticcall on the staticCallTargetAddress.
 | 
			
		||||
    /// @param expectedReturnDataHash Keccak-256 hash of the expected staticcall return data.
 | 
			
		||||
    function StaticCall(
 | 
			
		||||
        address staticCallTargetAddress,
 | 
			
		||||
        bytes calldata staticCallData,
 | 
			
		||||
        bytes32 expectedReturnDataHash
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Function signature for encoding ERC20Bridge assetData.
 | 
			
		||||
    /// @param tokenAddress Address of token to transfer.
 | 
			
		||||
    /// @param bridgeAddress Address of the bridge contract.
 | 
			
		||||
    /// @param bridgeData Arbitrary data to be passed to the bridge contract.
 | 
			
		||||
    function ERC20Bridge(
 | 
			
		||||
        address tokenAddress,
 | 
			
		||||
        address bridgeAddress,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,43 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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 IAssetProxy {
 | 
			
		||||
 | 
			
		||||
    /// @dev Transfers assets. Either succeeds or throws.
 | 
			
		||||
    /// @param assetData Byte array encoded for the respective asset proxy.
 | 
			
		||||
    /// @param from Address to transfer asset from.
 | 
			
		||||
    /// @param to Address to transfer asset to.
 | 
			
		||||
    /// @param amount Amount of asset to transfer.
 | 
			
		||||
    function transferFrom(
 | 
			
		||||
        bytes calldata assetData,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
    
 | 
			
		||||
    /// @dev Gets the proxy id associated with the proxy address.
 | 
			
		||||
    /// @return Proxy id.
 | 
			
		||||
    function getProxyId()
 | 
			
		||||
        external
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bytes4);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,43 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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 IAssetProxyDispatcher {
 | 
			
		||||
 | 
			
		||||
    // Logs registration of new asset proxy
 | 
			
		||||
    event AssetProxyRegistered(
 | 
			
		||||
        bytes4 id,              // Id of new registered AssetProxy.
 | 
			
		||||
        address assetProxy      // Address of new registered AssetProxy.
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    /// @dev Registers an asset proxy to its asset proxy id.
 | 
			
		||||
    ///      Once an asset proxy is registered, it cannot be unregistered.
 | 
			
		||||
    /// @param assetProxy Address of new asset proxy to register.
 | 
			
		||||
    function registerAssetProxy(address assetProxy)
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets an asset proxy.
 | 
			
		||||
    /// @param assetProxyId Id of the asset proxy.
 | 
			
		||||
    /// @return The asset proxy registered to assetProxyId. Returns 0x0 if no proxy is registered.
 | 
			
		||||
    function getAssetProxy(bytes4 assetProxyId)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (address);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,64 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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/interfaces/IOwnable.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract IAuthorizable is
 | 
			
		||||
    IOwnable
 | 
			
		||||
{
 | 
			
		||||
    // Event logged when a new address is authorized.
 | 
			
		||||
    event AuthorizedAddressAdded(
 | 
			
		||||
        address indexed target,
 | 
			
		||||
        address indexed caller
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Event logged when a currently authorized address is unauthorized.
 | 
			
		||||
    event AuthorizedAddressRemoved(
 | 
			
		||||
        address indexed target,
 | 
			
		||||
        address indexed caller
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    /// @dev Authorizes an address.
 | 
			
		||||
    /// @param target Address to authorize.
 | 
			
		||||
    function addAuthorizedAddress(address target)
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Removes authorizion of an address.
 | 
			
		||||
    /// @param target Address to remove authorization from.
 | 
			
		||||
    function removeAuthorizedAddress(address target)
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Removes authorizion of an address.
 | 
			
		||||
    /// @param target Address to remove authorization from.
 | 
			
		||||
    /// @param index Index of target in authorities array.
 | 
			
		||||
    function removeAuthorizedAddressAtIndex(
 | 
			
		||||
        address target,
 | 
			
		||||
        uint256 index
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Gets all authorized addresses.
 | 
			
		||||
    /// @return Array of authorized addresses.
 | 
			
		||||
    function getAuthorizedAddresses()
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (address[] memory);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,39 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.5.9;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IBalancerPool {
 | 
			
		||||
    /// @dev Sell `tokenAmountIn` of `tokenIn` and receive `tokenOut`.
 | 
			
		||||
    /// @param tokenIn The token being sold
 | 
			
		||||
    /// @param tokenAmountIn The amount of `tokenIn` to sell.
 | 
			
		||||
    /// @param tokenOut The token being bought.
 | 
			
		||||
    /// @param minAmountOut The minimum amount of `tokenOut` to buy.
 | 
			
		||||
    /// @param maxPrice The maximum value for `spotPriceAfter`.
 | 
			
		||||
    /// @return tokenAmountOut The amount of `tokenOut` bought.
 | 
			
		||||
    /// @return spotPriceAfter The new marginal spot price of the given
 | 
			
		||||
    ///         token pair for this pool.
 | 
			
		||||
    function swapExactAmountIn(
 | 
			
		||||
        address tokenIn,
 | 
			
		||||
        uint tokenAmountIn,
 | 
			
		||||
        address tokenOut,
 | 
			
		||||
        uint minAmountOut,
 | 
			
		||||
        uint maxPrice
 | 
			
		||||
    ) external returns (uint tokenAmountOut, uint spotPriceAfter);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,38 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.5.9;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract IContractRegistry {
 | 
			
		||||
    function addressOf(
 | 
			
		||||
        bytes32 contractName
 | 
			
		||||
    ) external returns(address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract IBancorNetwork {
 | 
			
		||||
    function convertByPath(
 | 
			
		||||
        address[] calldata _path,
 | 
			
		||||
        uint256 _amount,
 | 
			
		||||
        uint256 _minReturn,
 | 
			
		||||
        address _beneficiary,
 | 
			
		||||
        address _affiliateAccount,
 | 
			
		||||
        uint256 _affiliateFee
 | 
			
		||||
    ) external payable returns (uint256);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										66
									
								
								contracts/asset-proxy/contracts/src/interfaces/IChai.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								contracts/asset-proxy/contracts/src/interfaces/IChai.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract PotLike {
 | 
			
		||||
    function chi() external returns (uint256);
 | 
			
		||||
    function rho() external returns (uint256);
 | 
			
		||||
    function drip() external returns (uint256);
 | 
			
		||||
    function join(uint256) external;
 | 
			
		||||
    function exit(uint256) external;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// The actual Chai contract can be found here: https://github.com/dapphub/chai
 | 
			
		||||
contract IChai is
 | 
			
		||||
    IERC20Token
 | 
			
		||||
{
 | 
			
		||||
    /// @dev Withdraws Dai owned by `src`
 | 
			
		||||
    /// @param src Address that owns Dai.
 | 
			
		||||
    /// @param wad Amount of Dai to withdraw.
 | 
			
		||||
    function draw(
 | 
			
		||||
        address src,
 | 
			
		||||
        uint256 wad
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Queries Dai balance of Chai holder.
 | 
			
		||||
    /// @param usr Address of Chai holder.
 | 
			
		||||
    /// @return Dai balance.
 | 
			
		||||
    function dai(address usr)
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256);
 | 
			
		||||
 | 
			
		||||
    /// @dev Queries the Pot contract used by the Chai contract.
 | 
			
		||||
    function pot()
 | 
			
		||||
        external
 | 
			
		||||
        returns (PotLike);
 | 
			
		||||
 | 
			
		||||
    /// @dev Deposits Dai in exchange for Chai
 | 
			
		||||
    /// @param dst Address to receive Chai.
 | 
			
		||||
    /// @param wad Amount of Dai to deposit.
 | 
			
		||||
    function join(
 | 
			
		||||
        address dst,
 | 
			
		||||
        uint256 wad
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										70
									
								
								contracts/asset-proxy/contracts/src/interfaces/ICurve.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								contracts/asset-proxy/contracts/src/interfaces/ICurve.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable func-name-mixedcase
 | 
			
		||||
interface ICurve {
 | 
			
		||||
 | 
			
		||||
    /// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token.
 | 
			
		||||
    ///      This function exists on later versions of Curve (USDC/DAI/USDT)
 | 
			
		||||
    /// @param i The token index being sold.
 | 
			
		||||
    /// @param j The token index being bought.
 | 
			
		||||
    /// @param sellAmount The amount of token being bought.
 | 
			
		||||
    /// @param minBuyAmount The minimum buy amount of the token being bought.
 | 
			
		||||
    function exchange_underlying(
 | 
			
		||||
        int128 i,
 | 
			
		||||
        int128 j,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        uint256 minBuyAmount
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the amount of `toToken` by selling `sellAmount` of `fromToken`
 | 
			
		||||
    /// @param i The token index being sold.
 | 
			
		||||
    /// @param j The token index being bought.
 | 
			
		||||
    /// @param sellAmount The amount of token being bought.
 | 
			
		||||
    function get_dy_underlying(
 | 
			
		||||
        int128 i,
 | 
			
		||||
        int128 j,
 | 
			
		||||
        uint256 sellAmount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 dy);
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the amount of `fromToken` by buying `buyAmount` of `toToken`
 | 
			
		||||
    /// @param i The token index being sold.
 | 
			
		||||
    /// @param j The token index being bought.
 | 
			
		||||
    /// @param buyAmount The amount of token being bought.
 | 
			
		||||
    function get_dx_underlying(
 | 
			
		||||
        int128 i,
 | 
			
		||||
        int128 j,
 | 
			
		||||
        uint256 buyAmount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 dx);
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the underlying token address from the token index
 | 
			
		||||
    /// @param i The token index.
 | 
			
		||||
    function underlying_coins(
 | 
			
		||||
        int128 i
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (address tokenAddress);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										192
									
								
								contracts/asset-proxy/contracts/src/interfaces/IDydx.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								contracts/asset-proxy/contracts/src/interfaces/IDydx.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,192 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IDydx {
 | 
			
		||||
 | 
			
		||||
    /// @dev Represents the unique key that specifies an account
 | 
			
		||||
    struct AccountInfo {
 | 
			
		||||
        address owner;  // The address that owns the account
 | 
			
		||||
        uint256 number; // A nonce that allows a single address to control many accounts
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enum ActionType {
 | 
			
		||||
        Deposit,   // supply tokens
 | 
			
		||||
        Withdraw,  // borrow tokens
 | 
			
		||||
        Transfer,  // transfer balance between accounts
 | 
			
		||||
        Buy,       // buy an amount of some token (externally)
 | 
			
		||||
        Sell,      // sell an amount of some token (externally)
 | 
			
		||||
        Trade,     // trade tokens against another account
 | 
			
		||||
        Liquidate, // liquidate an undercollateralized or expiring account
 | 
			
		||||
        Vaporize,  // use excess tokens to zero-out a completely negative account
 | 
			
		||||
        Call       // send arbitrary data to an address
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Arguments that are passed to Solo in an ordered list as part of a single operation.
 | 
			
		||||
    /// Each ActionArgs has an actionType which specifies which action struct that this data will be
 | 
			
		||||
    /// parsed into before being processed.
 | 
			
		||||
    struct ActionArgs {
 | 
			
		||||
        ActionType actionType;
 | 
			
		||||
        uint256 accountIdx;
 | 
			
		||||
        AssetAmount amount;
 | 
			
		||||
        uint256 primaryMarketId;
 | 
			
		||||
        uint256 secondaryMarketId;
 | 
			
		||||
        address otherAddress;
 | 
			
		||||
        uint256 otherAccountIdx;
 | 
			
		||||
        bytes data;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enum AssetDenomination {
 | 
			
		||||
        Wei, // the amount is denominated in wei
 | 
			
		||||
        Par  // the amount is denominated in par
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enum AssetReference {
 | 
			
		||||
        Delta, // the amount is given as a delta from the current value
 | 
			
		||||
        Target // the amount is given as an exact number to end up at
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct AssetAmount {
 | 
			
		||||
        bool sign; // true if positive
 | 
			
		||||
        AssetDenomination denomination;
 | 
			
		||||
        AssetReference ref;
 | 
			
		||||
        uint256 value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct D256 {
 | 
			
		||||
        uint256 value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct Value {
 | 
			
		||||
        uint256 value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct Price {
 | 
			
		||||
        uint256 value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct OperatorArg {
 | 
			
		||||
        address operator;
 | 
			
		||||
        bool trusted;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev The global risk parameters that govern the health and security of the system
 | 
			
		||||
    struct RiskParams {
 | 
			
		||||
        // Required ratio of over-collateralization
 | 
			
		||||
        D256 marginRatio;
 | 
			
		||||
        // Percentage penalty incurred by liquidated accounts
 | 
			
		||||
        D256 liquidationSpread;
 | 
			
		||||
        // Percentage of the borrower's interest fee that gets passed to the suppliers
 | 
			
		||||
        D256 earningsRate;
 | 
			
		||||
        // The minimum absolute borrow value of an account
 | 
			
		||||
        // There must be sufficient incentivize to liquidate undercollateralized accounts
 | 
			
		||||
        Value minBorrowedValue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev The main entry-point to Solo that allows users and contracts to manage accounts.
 | 
			
		||||
    ///      Take one or more actions on one or more accounts. The msg.sender must be the owner or
 | 
			
		||||
    ///      operator of all accounts except for those being liquidated, vaporized, or traded with.
 | 
			
		||||
    ///      One call to operate() is considered a singular "operation". Account collateralization is
 | 
			
		||||
    ///      ensured only after the completion of the entire operation.
 | 
			
		||||
    /// @param  accounts  A list of all accounts that will be used in this operation. Cannot contain
 | 
			
		||||
    ///                   duplicates. In each action, the relevant account will be referred-to by its
 | 
			
		||||
    ///                   index in the list.
 | 
			
		||||
    /// @param  actions   An ordered list of all actions that will be taken in this operation. The
 | 
			
		||||
    ///                   actions will be processed in order.
 | 
			
		||||
    function operate(
 | 
			
		||||
        AccountInfo[] calldata accounts,
 | 
			
		||||
        ActionArgs[] calldata actions
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    // @dev Approves/disapproves any number of operators. An operator is an external address that has the
 | 
			
		||||
    //      same permissions to manipulate an account as the owner of the account. Operators are simply
 | 
			
		||||
    //      addresses and therefore may either be externally-owned Ethereum accounts OR smart contracts.
 | 
			
		||||
    //      Operators are also able to act as AutoTrader contracts on behalf of the account owner if the
 | 
			
		||||
    //      operator is a smart contract and implements the IAutoTrader interface.
 | 
			
		||||
    // @param args A list of OperatorArgs which have an address and a boolean. The boolean value
 | 
			
		||||
    //        denotes whether to approve (true) or revoke approval (false) for that address.
 | 
			
		||||
    function setOperators(OperatorArg[] calldata args) external;
 | 
			
		||||
 | 
			
		||||
    /// @dev Return true if a particular address is approved as an operator for an owner's accounts.
 | 
			
		||||
    ///      Approved operators can act on the accounts of the owner as if it were the operator's own.
 | 
			
		||||
    /// @param owner The owner of the accounts
 | 
			
		||||
    /// @param operator The possible operator
 | 
			
		||||
    /// @return isLocalOperator True if operator is approved for owner's accounts
 | 
			
		||||
    function getIsLocalOperator(
 | 
			
		||||
        address owner,
 | 
			
		||||
        address operator
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bool isLocalOperator);
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the ERC20 token address for a market.
 | 
			
		||||
    /// @param marketId The market to query
 | 
			
		||||
    /// @return tokenAddress The token address
 | 
			
		||||
    function getMarketTokenAddress(
 | 
			
		||||
        uint256 marketId
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (address tokenAddress);
 | 
			
		||||
 | 
			
		||||
    /// @dev Get all risk parameters in a single struct.
 | 
			
		||||
    /// @return riskParams All global risk parameters
 | 
			
		||||
    function getRiskParams()
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (RiskParams memory riskParams);
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the price of the token for a market.
 | 
			
		||||
    /// @param marketId The market to query
 | 
			
		||||
    /// @return price The price of each atomic unit of the token
 | 
			
		||||
    function getMarketPrice(
 | 
			
		||||
        uint256 marketId
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (Price memory price);
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the margin premium for a market. A margin premium makes it so that any positions that
 | 
			
		||||
    ///      include the market require a higher collateralization to avoid being liquidated.
 | 
			
		||||
    /// @param  marketId  The market to query
 | 
			
		||||
    /// @return premium The market's margin premium
 | 
			
		||||
    function getMarketMarginPremium(uint256 marketId)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (D256 memory premium);
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the total supplied and total borrowed values of an account adjusted by the marginPremium
 | 
			
		||||
    ///      of each market. Supplied values are divided by (1 + marginPremium) for each market and
 | 
			
		||||
    ///      borrowed values are multiplied by (1 + marginPremium) for each market. Comparing these
 | 
			
		||||
    ///      adjusted values gives the margin-ratio of the account which will be compared to the global
 | 
			
		||||
    ///      margin-ratio when determining if the account can be liquidated.
 | 
			
		||||
    /// @param account The account to query
 | 
			
		||||
    /// @return supplyValue The supplied value of the account (adjusted for marginPremium)
 | 
			
		||||
    /// @return borrowValue The borrowed value of the account (adjusted for marginPremium)
 | 
			
		||||
    function getAdjustedAccountValues(
 | 
			
		||||
        AccountInfo calldata account
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (Value memory supplyValue, Value memory borrowValue);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,42 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IDydxBridge {
 | 
			
		||||
 | 
			
		||||
    /// @dev This is the subset of `IDydx.ActionType` that are supported by the bridge.
 | 
			
		||||
    enum BridgeActionType {
 | 
			
		||||
        Deposit,                    // Deposit tokens into dydx account.
 | 
			
		||||
        Withdraw                    // Withdraw tokens from dydx account.
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct BridgeAction {
 | 
			
		||||
        BridgeActionType actionType;            // Action to run on dydx account.
 | 
			
		||||
        uint256 accountIdx;                     // Index in `BridgeData.accountNumbers` for this action.
 | 
			
		||||
        uint256 marketId;                       // Market to operate on.
 | 
			
		||||
        uint256 conversionRateNumerator;        // Optional. If set, transfer amount is scaled by (conversionRateNumerator/conversionRateDenominator).
 | 
			
		||||
        uint256 conversionRateDenominator;      // Optional. If set, transfer amount is scaled by (conversionRateNumerator/conversionRateDenominator).
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct BridgeData {
 | 
			
		||||
        uint256[] accountNumbers;               // Account number used to identify the owner's specific account.
 | 
			
		||||
        BridgeAction[] actions;                 // Actions to carry out on the owner's accounts.
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,59 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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 IERC20Bridge {
 | 
			
		||||
 | 
			
		||||
    /// @dev Result of a successful bridge call.
 | 
			
		||||
    bytes4 constant internal BRIDGE_SUCCESS = 0xdc1600f3;
 | 
			
		||||
 | 
			
		||||
    /// @dev Emitted when a trade occurs.
 | 
			
		||||
    /// @param inputToken The token the bridge is converting from.
 | 
			
		||||
    /// @param outputToken The token the bridge is converting to.
 | 
			
		||||
    /// @param inputTokenAmount Amount of input token.
 | 
			
		||||
    /// @param outputTokenAmount Amount of output token.
 | 
			
		||||
    /// @param from The `from` address in `bridgeTransferFrom()`
 | 
			
		||||
    /// @param to The `to` address in `bridgeTransferFrom()`
 | 
			
		||||
    event ERC20BridgeTransfer(
 | 
			
		||||
        address inputToken,
 | 
			
		||||
        address outputToken,
 | 
			
		||||
        uint256 inputTokenAmount,
 | 
			
		||||
        uint256 outputTokenAmount,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    /// @dev Transfers `amount` of the ERC20 `tokenAddress` from `from` to `to`.
 | 
			
		||||
    /// @param tokenAddress The address of the ERC20 token to transfer.
 | 
			
		||||
    /// @param from Address to transfer asset from.
 | 
			
		||||
    /// @param to Address to transfer asset to.
 | 
			
		||||
    /// @param amount Amount of asset to transfer.
 | 
			
		||||
    /// @param bridgeData Arbitrary asset data needed by the bridge contract.
 | 
			
		||||
    /// @return success The magic bytes `0xdc1600f3` if successful.
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address tokenAddress,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4 success);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								contracts/asset-proxy/contracts/src/interfaces/IEth2Dai.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								contracts/asset-proxy/contracts/src/interfaces/IEth2Dai.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IEth2Dai {
 | 
			
		||||
 | 
			
		||||
    /// @dev Sell `sellAmount` of `fromToken` token and receive `toToken` token.
 | 
			
		||||
    /// @param fromToken The token being sold.
 | 
			
		||||
    /// @param sellAmount The amount of `fromToken` token being sold.
 | 
			
		||||
    /// @param toToken The token being bought.
 | 
			
		||||
    /// @param minFillAmount Minimum amount of `toToken` token to buy.
 | 
			
		||||
    /// @return fillAmount Amount of `toToken` bought.
 | 
			
		||||
    function sellAllAmount(
 | 
			
		||||
        address fromToken,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        address toToken,
 | 
			
		||||
        uint256 minFillAmount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 fillAmount);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								contracts/asset-proxy/contracts/src/interfaces/IGasToken.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								contracts/asset-proxy/contracts/src/interfaces/IGasToken.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  Copyright 2019 ZeroEx Intl.
 | 
			
		||||
 | 
			
		||||
  Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
  you may not use this file except in compliance with the License.
 | 
			
		||||
  You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
  Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
  distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
  See the License for the specific language governing permissions and
 | 
			
		||||
  limitations under the License.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
pragma solidity ^0.5.15;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract IGasToken is IERC20Token {
 | 
			
		||||
 | 
			
		||||
    /// @dev Frees up to `value` sub-tokens
 | 
			
		||||
    /// @param value The amount of tokens to free
 | 
			
		||||
    /// @return How many tokens were freed
 | 
			
		||||
    function freeUpTo(uint256 value) external returns (uint256 freed);
 | 
			
		||||
 | 
			
		||||
    /// @dev Frees up to `value` sub-tokens owned by `from`
 | 
			
		||||
    /// @param from The owner of tokens to spend
 | 
			
		||||
    /// @param value The amount of tokens to free
 | 
			
		||||
    /// @return How many tokens were freed
 | 
			
		||||
    function freeFromUpTo(address from, uint256 value) external returns (uint256 freed);
 | 
			
		||||
 | 
			
		||||
    /// @dev Mints `value` amount of tokens
 | 
			
		||||
    /// @param value The amount of tokens to mint
 | 
			
		||||
    function mint(uint256 value) external;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,72 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IKyberNetworkProxy {
 | 
			
		||||
 | 
			
		||||
    /// @dev Sells `sellTokenAddress` tokens for `buyTokenAddress` tokens.
 | 
			
		||||
    /// @param sellTokenAddress Token to sell.
 | 
			
		||||
    /// @param sellAmount Amount of tokens to sell.
 | 
			
		||||
    /// @param buyTokenAddress Token to buy.
 | 
			
		||||
    /// @param recipientAddress Address to send bought tokens to.
 | 
			
		||||
    /// @param maxBuyTokenAmount A limit on the amount of tokens to buy.
 | 
			
		||||
    /// @param minConversionRate The minimal conversion rate. If actual rate
 | 
			
		||||
    ///        is lower, trade is canceled.
 | 
			
		||||
    /// @param walletId The wallet ID to send part of the fees
 | 
			
		||||
    /// @return boughtAmount Amount of tokens bought.
 | 
			
		||||
    function trade(
 | 
			
		||||
        address sellTokenAddress,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        address buyTokenAddress,
 | 
			
		||||
        address payable recipientAddress,
 | 
			
		||||
        uint256 maxBuyTokenAmount,
 | 
			
		||||
        uint256 minConversionRate,
 | 
			
		||||
        address walletId
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        returns (uint256 boughtAmount);
 | 
			
		||||
 | 
			
		||||
    /// @dev Sells `sellTokenAddress` tokens for `buyTokenAddress` tokens
 | 
			
		||||
    /// using a hint for the reserve.
 | 
			
		||||
    /// @param sellTokenAddress Token to sell.
 | 
			
		||||
    /// @param sellAmount Amount of tokens to sell.
 | 
			
		||||
    /// @param buyTokenAddress Token to buy.
 | 
			
		||||
    /// @param recipientAddress Address to send bought tokens to.
 | 
			
		||||
    /// @param maxBuyTokenAmount A limit on the amount of tokens to buy.
 | 
			
		||||
    /// @param minConversionRate The minimal conversion rate. If actual rate
 | 
			
		||||
    ///        is lower, trade is canceled.
 | 
			
		||||
    /// @param walletId The wallet ID to send part of the fees
 | 
			
		||||
    /// @param hint The hint for the selective inclusion (or exclusion) of reserves
 | 
			
		||||
    /// @return boughtAmount Amount of tokens bought.
 | 
			
		||||
    function tradeWithHint(
 | 
			
		||||
        address sellTokenAddress,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        address buyTokenAddress,
 | 
			
		||||
        address payable recipientAddress,
 | 
			
		||||
        uint256 maxBuyTokenAmount,
 | 
			
		||||
        uint256 minConversionRate,
 | 
			
		||||
        address payable walletId,
 | 
			
		||||
        bytes calldata hint
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        returns (uint256 boughtAmount);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								contracts/asset-proxy/contracts/src/interfaces/IMStable.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								contracts/asset-proxy/contracts/src/interfaces/IMStable.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.5.9;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IMStable {
 | 
			
		||||
 | 
			
		||||
    function swap(
 | 
			
		||||
        address _input,
 | 
			
		||||
        address _output,
 | 
			
		||||
        uint256 _quantity,
 | 
			
		||||
        address _recipient
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 output);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,40 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.5.9;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IMooniswapRegistry {
 | 
			
		||||
 | 
			
		||||
    function pools(address token1, address token2) external view returns(address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IMooniswap {
 | 
			
		||||
 | 
			
		||||
    function swap(
 | 
			
		||||
        address fromToken,
 | 
			
		||||
        address destToken,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        uint256 minReturn,
 | 
			
		||||
        address referral
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        returns(uint256 returnAmount);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								contracts/asset-proxy/contracts/src/interfaces/IShell.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								contracts/asset-proxy/contracts/src/interfaces/IShell.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.5.9;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IShell {
 | 
			
		||||
 | 
			
		||||
    function originSwap(
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 fromAmount,
 | 
			
		||||
        uint256 minTargetAmount,
 | 
			
		||||
        uint256 deadline
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 toAmount);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,70 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IUniswapExchange {
 | 
			
		||||
 | 
			
		||||
    /// @dev Buys at least `minTokensBought` tokens with ETH and transfer them
 | 
			
		||||
    ///      to `recipient`.
 | 
			
		||||
    /// @param minTokensBought The minimum number of tokens to buy.
 | 
			
		||||
    /// @param deadline Time when this order expires.
 | 
			
		||||
    /// @param recipient Who to transfer the tokens to.
 | 
			
		||||
    /// @return tokensBought Amount of tokens bought.
 | 
			
		||||
    function ethToTokenTransferInput(
 | 
			
		||||
        uint256 minTokensBought,
 | 
			
		||||
        uint256 deadline,
 | 
			
		||||
        address recipient
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        returns (uint256 tokensBought);
 | 
			
		||||
 | 
			
		||||
    /// @dev Buys at least `minEthBought` ETH with tokens.
 | 
			
		||||
    /// @param tokensSold Amount of tokens to sell.
 | 
			
		||||
    /// @param minEthBought The minimum amount of ETH to buy.
 | 
			
		||||
    /// @param deadline Time when this order expires.
 | 
			
		||||
    /// @return ethBought Amount of tokens bought.
 | 
			
		||||
    function tokenToEthSwapInput(
 | 
			
		||||
        uint256 tokensSold,
 | 
			
		||||
        uint256 minEthBought,
 | 
			
		||||
        uint256 deadline
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 ethBought);
 | 
			
		||||
 | 
			
		||||
    /// @dev Buys at least `minTokensBought` tokens with the exchange token
 | 
			
		||||
    ///      and transfer them to `recipient`.
 | 
			
		||||
    /// @param minTokensBought The minimum number of tokens to buy.
 | 
			
		||||
    /// @param minEthBought The minimum amount of intermediate ETH to buy.
 | 
			
		||||
    /// @param deadline Time when this order expires.
 | 
			
		||||
    /// @param recipient Who to transfer the tokens to.
 | 
			
		||||
    /// @param toTokenAddress The token being bought.
 | 
			
		||||
    /// @return tokensBought Amount of tokens bought.
 | 
			
		||||
    function tokenToTokenTransferInput(
 | 
			
		||||
        uint256 tokensSold,
 | 
			
		||||
        uint256 minTokensBought,
 | 
			
		||||
        uint256 minEthBought,
 | 
			
		||||
        uint256 deadline,
 | 
			
		||||
        address recipient,
 | 
			
		||||
        address toTokenAddress
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 tokensBought);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,32 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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 "./IUniswapExchange.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IUniswapExchangeFactory {
 | 
			
		||||
 | 
			
		||||
    /// @dev Get the exchange for a token.
 | 
			
		||||
    /// @param tokenAddress The address of the token contract.
 | 
			
		||||
    function getExchange(address tokenAddress)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (address);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,40 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.5.9;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface IUniswapV2Router01 {
 | 
			
		||||
 | 
			
		||||
    /// @dev Swaps an exact amount of input tokens for as many output tokens as possible, along the route determined by the path.
 | 
			
		||||
    ///      The first element of path is the input token, the last is the output token, and any intermediate elements represent
 | 
			
		||||
    ///      intermediate pairs to trade through (if, for example, a direct pair does not exist).
 | 
			
		||||
    /// @param amountIn The amount of input tokens to send.
 | 
			
		||||
    /// @param amountOutMin The minimum amount of output tokens that must be received for the transaction not to revert.
 | 
			
		||||
    /// @param path An array of token addresses. path.length must be >= 2. Pools for each consecutive pair of addresses must exist and have liquidity.
 | 
			
		||||
    /// @param to Recipient of the output tokens.
 | 
			
		||||
    /// @param deadline Unix timestamp after which the transaction will revert.
 | 
			
		||||
    /// @return amounts The input token amount and all subsequent output token amounts.
 | 
			
		||||
    function swapExactTokensForTokens(
 | 
			
		||||
        uint amountIn,
 | 
			
		||||
        uint amountOutMin,
 | 
			
		||||
        address[] calldata path,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint deadline
 | 
			
		||||
    ) external returns (uint[] memory amounts);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										247
									
								
								contracts/asset-proxy/contracts/test/TestBancorBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										247
									
								
								contracts/asset-proxy/contracts/test/TestBancorBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,247 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
 | 
			
		||||
import "../src/bridges/BancorBridge.sol";
 | 
			
		||||
import "../src/interfaces/IBancorNetwork.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract TestEventsRaiser {
 | 
			
		||||
 | 
			
		||||
    event TokenTransfer(
 | 
			
		||||
        address token,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    event TokenApprove(
 | 
			
		||||
        address spender,
 | 
			
		||||
        uint256 allowance
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    event ConvertByPathInput(
 | 
			
		||||
        uint amountIn,
 | 
			
		||||
        uint amountOutMin,
 | 
			
		||||
        address toTokenAddress,
 | 
			
		||||
        address to,
 | 
			
		||||
        address feeRecipient,
 | 
			
		||||
        uint256 feeAmount
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    function raiseTokenTransfer(
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        emit TokenTransfer(
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            from,
 | 
			
		||||
            to,
 | 
			
		||||
            amount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function raiseTokenApprove(address spender, uint256 allowance) external {
 | 
			
		||||
        emit TokenApprove(spender, allowance);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function raiseConvertByPathInput(
 | 
			
		||||
        uint amountIn,
 | 
			
		||||
        uint amountOutMin,
 | 
			
		||||
        address toTokenAddress,
 | 
			
		||||
        address to,
 | 
			
		||||
        address feeRecipient,
 | 
			
		||||
        uint256 feeAmount
 | 
			
		||||
    ) external
 | 
			
		||||
    {
 | 
			
		||||
        emit ConvertByPathInput(
 | 
			
		||||
            amountIn,
 | 
			
		||||
            amountOutMin,
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            to,
 | 
			
		||||
            feeRecipient,
 | 
			
		||||
            feeAmount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev A minimalist ERC20 token.
 | 
			
		||||
contract TestToken {
 | 
			
		||||
 | 
			
		||||
    using LibSafeMath for uint256;
 | 
			
		||||
 | 
			
		||||
    mapping (address => uint256) public balances;
 | 
			
		||||
    string private _nextRevertReason;
 | 
			
		||||
 | 
			
		||||
    /// @dev Set the balance for `owner`.
 | 
			
		||||
    function setBalance(address owner, uint256 balance)
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
    {
 | 
			
		||||
        balances[owner] = balance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Just emits a TokenTransfer event on the caller
 | 
			
		||||
    function transfer(address to, uint256 amount)
 | 
			
		||||
        external
 | 
			
		||||
        returns (bool)
 | 
			
		||||
    {
 | 
			
		||||
        TestEventsRaiser(msg.sender).raiseTokenTransfer(msg.sender, to, amount);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Just emits a TokenApprove event on the caller
 | 
			
		||||
    function approve(address spender, uint256 allowance)
 | 
			
		||||
        external
 | 
			
		||||
        returns (bool)
 | 
			
		||||
    {
 | 
			
		||||
        TestEventsRaiser(msg.sender).raiseTokenApprove(spender, allowance);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function allowance(address, address) external view returns (uint256) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Retrieve the balance for `owner`.
 | 
			
		||||
    function balanceOf(address owner)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256)
 | 
			
		||||
    {
 | 
			
		||||
        return balances[owner];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev Mock the BancorNetwork contract
 | 
			
		||||
contract TestBancorNetwork is
 | 
			
		||||
    IBancorNetwork
 | 
			
		||||
{
 | 
			
		||||
    string private _nextRevertReason;
 | 
			
		||||
 | 
			
		||||
    /// @dev Set the revert reason for `swapExactTokensForTokens`.
 | 
			
		||||
    function setRevertReason(string calldata reason)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        _nextRevertReason = reason;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function convertByPath(
 | 
			
		||||
        address[] calldata _path,
 | 
			
		||||
        uint256 _amount,
 | 
			
		||||
        uint256 _minReturn,
 | 
			
		||||
        address _beneficiary,
 | 
			
		||||
        address _affiliateAccount,
 | 
			
		||||
        uint256 _affiliateFee
 | 
			
		||||
    ) external payable returns (uint256)
 | 
			
		||||
    {
 | 
			
		||||
        _revertIfReasonExists();
 | 
			
		||||
 | 
			
		||||
        TestEventsRaiser(msg.sender).raiseConvertByPathInput(
 | 
			
		||||
            // tokens sold
 | 
			
		||||
            _amount,
 | 
			
		||||
            // tokens bought
 | 
			
		||||
            _minReturn,
 | 
			
		||||
            // output token
 | 
			
		||||
            _path[_path.length - 1],
 | 
			
		||||
            // recipient
 | 
			
		||||
            _beneficiary,
 | 
			
		||||
            // fee recipient
 | 
			
		||||
            _affiliateAccount,
 | 
			
		||||
            // fee amount
 | 
			
		||||
            _affiliateFee
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _revertIfReasonExists()
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
    {
 | 
			
		||||
        if (bytes(_nextRevertReason).length != 0) {
 | 
			
		||||
            revert(_nextRevertReason);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev BancorBridge overridden to mock tokens and BancorNetwork
 | 
			
		||||
contract TestBancorBridge is
 | 
			
		||||
    BancorBridge,
 | 
			
		||||
    TestEventsRaiser
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    // Token address to TestToken instance.
 | 
			
		||||
    mapping (address => TestToken) private _testTokens;
 | 
			
		||||
    // TestRouter instance.
 | 
			
		||||
    TestBancorNetwork private _testNetwork;
 | 
			
		||||
 | 
			
		||||
    constructor() public {
 | 
			
		||||
        _testNetwork = new TestBancorNetwork();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setNetworkRevertReason(string calldata revertReason)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        _testNetwork.setRevertReason(revertReason);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sets the balance of this contract for an existing token.
 | 
			
		||||
    function setTokenBalance(address tokenAddress, uint256 balance)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        TestToken token = _testTokens[tokenAddress];
 | 
			
		||||
        token.setBalance(address(this), balance);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Create a new token
 | 
			
		||||
    /// @param tokenAddress The token address. If zero, one will be created.
 | 
			
		||||
    function createToken(
 | 
			
		||||
        address tokenAddress
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (TestToken token)
 | 
			
		||||
    {
 | 
			
		||||
        token = TestToken(tokenAddress);
 | 
			
		||||
        if (tokenAddress == address(0)) {
 | 
			
		||||
            token = new TestToken();
 | 
			
		||||
        }
 | 
			
		||||
        _testTokens[address(token)] = token;
 | 
			
		||||
 | 
			
		||||
        return token;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getNetworkAddress()
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (address)
 | 
			
		||||
    {
 | 
			
		||||
        return address(_testNetwork);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										80
									
								
								contracts/asset-proxy/contracts/test/TestChaiBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								contracts/asset-proxy/contracts/test/TestChaiBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,80 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "../src/bridges/ChaiBridge.sol";
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/ERC20Token.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract TestChaiDai is
 | 
			
		||||
    ERC20Token
 | 
			
		||||
{
 | 
			
		||||
    address private constant ALWAYS_REVERT_ADDRESS = address(1);
 | 
			
		||||
 | 
			
		||||
    function draw(
 | 
			
		||||
        address from,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        if (from == ALWAYS_REVERT_ADDRESS) {
 | 
			
		||||
            revert();
 | 
			
		||||
        }
 | 
			
		||||
        balances[msg.sender] += amount;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract TestChaiBridge is
 | 
			
		||||
    ChaiBridge
 | 
			
		||||
{
 | 
			
		||||
    address public testChaiDai;
 | 
			
		||||
    address private constant ALWAYS_REVERT_ADDRESS = address(1);
 | 
			
		||||
 | 
			
		||||
    constructor()
 | 
			
		||||
        public
 | 
			
		||||
    {
 | 
			
		||||
        testChaiDai = address(new TestChaiDai());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _getDaiAddress()
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (address)
 | 
			
		||||
    {
 | 
			
		||||
        return testChaiDai;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _getChaiAddress()
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (address)
 | 
			
		||||
    {
 | 
			
		||||
        return testChaiDai;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _getERC20BridgeProxyAddress()
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (address)
 | 
			
		||||
    {
 | 
			
		||||
        return msg.sender == ALWAYS_REVERT_ADDRESS ? address(0) : msg.sender;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										244
									
								
								contracts/asset-proxy/contracts/test/TestDexForwarderBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								contracts/asset-proxy/contracts/test/TestDexForwarderBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,244 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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.5.9;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "../src/bridges/DexForwarderBridge.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface ITestDexForwarderBridge {
 | 
			
		||||
    event BridgeTransferFromCalled(
 | 
			
		||||
        address caller,
 | 
			
		||||
        uint256 inputTokenBalance,
 | 
			
		||||
        address inputToken,
 | 
			
		||||
        address outputToken,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    event TokenTransferCalled(
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    function emitBridgeTransferFromCalled(
 | 
			
		||||
        address caller,
 | 
			
		||||
        uint256 inputTokenBalance,
 | 
			
		||||
        address inputToken,
 | 
			
		||||
        address outputToken,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    ) external;
 | 
			
		||||
 | 
			
		||||
    function emitTokenTransferCalled(
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    ) external;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface ITestDexForwarderBridgeTestToken {
 | 
			
		||||
 | 
			
		||||
    function transfer(address to, uint256 amount)
 | 
			
		||||
        external
 | 
			
		||||
        returns (bool);
 | 
			
		||||
 | 
			
		||||
    function mint(address to, uint256 amount)
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    function balanceOf(address owner) external view returns (uint256);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract TestDexForwarderBridgeTestBridge {
 | 
			
		||||
 | 
			
		||||
    bytes4 private _returnCode;
 | 
			
		||||
    string private _revertError;
 | 
			
		||||
    uint256 private _transferAmount;
 | 
			
		||||
    ITestDexForwarderBridge private _testContract;
 | 
			
		||||
 | 
			
		||||
    constructor(bytes4 returnCode, string memory revertError) public {
 | 
			
		||||
        _testContract = ITestDexForwarderBridge(msg.sender);
 | 
			
		||||
        _returnCode = returnCode;
 | 
			
		||||
        _revertError = revertError;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setTransferAmount(uint256 amount) external {
 | 
			
		||||
        _transferAmount = amount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address outputToken,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes memory bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        returns (bytes4 success)
 | 
			
		||||
    {
 | 
			
		||||
        if (bytes(_revertError).length != 0) {
 | 
			
		||||
            revert(_revertError);
 | 
			
		||||
        }
 | 
			
		||||
        address inputToken = abi.decode(bridgeData, (address));
 | 
			
		||||
        _testContract.emitBridgeTransferFromCalled(
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            ITestDexForwarderBridgeTestToken(inputToken).balanceOf(address(this)),
 | 
			
		||||
            inputToken,
 | 
			
		||||
            outputToken,
 | 
			
		||||
            from,
 | 
			
		||||
            to,
 | 
			
		||||
            amount
 | 
			
		||||
        );
 | 
			
		||||
        ITestDexForwarderBridgeTestToken(outputToken).mint(to, _transferAmount);
 | 
			
		||||
        return _returnCode;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract TestDexForwarderBridgeTestToken {
 | 
			
		||||
 | 
			
		||||
    using LibSafeMath for uint256;
 | 
			
		||||
 | 
			
		||||
    mapping(address => uint256) public balanceOf;
 | 
			
		||||
    ITestDexForwarderBridge private _testContract;
 | 
			
		||||
 | 
			
		||||
    constructor() public {
 | 
			
		||||
        _testContract = ITestDexForwarderBridge(msg.sender);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function transfer(address to, uint256 amount)
 | 
			
		||||
        external
 | 
			
		||||
        returns (bool)
 | 
			
		||||
    {
 | 
			
		||||
        balanceOf[msg.sender] = balanceOf[msg.sender].safeSub(amount);
 | 
			
		||||
        balanceOf[to] = balanceOf[to].safeAdd(amount);
 | 
			
		||||
        _testContract.emitTokenTransferCalled(msg.sender, to, amount);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function mint(address owner, uint256 amount)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        balanceOf[owner] = balanceOf[owner].safeAdd(amount);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setBalance(address owner, uint256 amount)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        balanceOf[owner] = amount;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract TestDexForwarderBridge is
 | 
			
		||||
    ITestDexForwarderBridge,
 | 
			
		||||
    DexForwarderBridge
 | 
			
		||||
{
 | 
			
		||||
    address private AUTHORIZED_ADDRESS; // solhint-disable-line var-name-mixedcase
 | 
			
		||||
 | 
			
		||||
    function setAuthorized(address authorized)
 | 
			
		||||
        public
 | 
			
		||||
    {
 | 
			
		||||
        AUTHORIZED_ADDRESS = authorized;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function createBridge(
 | 
			
		||||
        bytes4 returnCode,
 | 
			
		||||
        string memory revertError
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
        returns (address bridge)
 | 
			
		||||
    {
 | 
			
		||||
        return address(new TestDexForwarderBridgeTestBridge(returnCode, revertError));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function createToken() public returns (address token) {
 | 
			
		||||
        return address(new TestDexForwarderBridgeTestToken());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setTokenBalance(address token, address owner, uint256 amount) public {
 | 
			
		||||
        TestDexForwarderBridgeTestToken(token).setBalance(owner, amount);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setBridgeTransferAmount(address bridge, uint256 amount) public {
 | 
			
		||||
        TestDexForwarderBridgeTestBridge(bridge).setTransferAmount(amount);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function emitBridgeTransferFromCalled(
 | 
			
		||||
        address caller,
 | 
			
		||||
        uint256 inputTokenBalance,
 | 
			
		||||
        address inputToken,
 | 
			
		||||
        address outputToken,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
    {
 | 
			
		||||
        emit BridgeTransferFromCalled(
 | 
			
		||||
            caller,
 | 
			
		||||
            inputTokenBalance,
 | 
			
		||||
            inputToken,
 | 
			
		||||
            outputToken,
 | 
			
		||||
            from,
 | 
			
		||||
            to,
 | 
			
		||||
            amount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function emitTokenTransferCalled(
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        public
 | 
			
		||||
    {
 | 
			
		||||
        emit TokenTransferCalled(
 | 
			
		||||
            from,
 | 
			
		||||
            to,
 | 
			
		||||
            amount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function balanceOf(address token, address owner) public view returns (uint256) {
 | 
			
		||||
        return TestDexForwarderBridgeTestToken(token).balanceOf(owner);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _getGstAddress()
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (address gst)
 | 
			
		||||
    {
 | 
			
		||||
        return address(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _getERC20BridgeProxyAddress()
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (address erc20BridgeProxyAddress)
 | 
			
		||||
    {
 | 
			
		||||
        return AUTHORIZED_ADDRESS;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										246
									
								
								contracts/asset-proxy/contracts/test/TestDydxBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										246
									
								
								contracts/asset-proxy/contracts/test/TestDydxBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,246 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "../src/bridges/DydxBridge.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable no-empty-blocks
 | 
			
		||||
contract TestDydxBridgeToken {
 | 
			
		||||
 | 
			
		||||
    uint256 private constant INIT_HOLDER_BALANCE = 10 * 10**18; // 10 tokens
 | 
			
		||||
    mapping (address => uint256) private _balances;
 | 
			
		||||
 | 
			
		||||
    /// @dev Sets initial balance of token holders.
 | 
			
		||||
    constructor(address[] memory holders)
 | 
			
		||||
        public
 | 
			
		||||
    {
 | 
			
		||||
        for (uint256 i = 0; i != holders.length; ++i) {
 | 
			
		||||
            _balances[holders[i]] = INIT_HOLDER_BALANCE;
 | 
			
		||||
        }
 | 
			
		||||
        _balances[msg.sender] = INIT_HOLDER_BALANCE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Basic transferFrom implementation.
 | 
			
		||||
    function transferFrom(address from, address to, uint256 amount)
 | 
			
		||||
        external
 | 
			
		||||
        returns (bool)
 | 
			
		||||
    {
 | 
			
		||||
        if (_balances[from] < amount || _balances[to] + amount < _balances[to]) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        _balances[from] -= amount;
 | 
			
		||||
        _balances[to] += amount;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Returns balance of `holder`.
 | 
			
		||||
    function balanceOf(address holder)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256)
 | 
			
		||||
    {
 | 
			
		||||
        return _balances[holder];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable space-after-comma
 | 
			
		||||
contract TestDydxBridge is
 | 
			
		||||
    IDydx,
 | 
			
		||||
    DydxBridge
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    address private constant ALWAYS_REVERT_ADDRESS = address(1);
 | 
			
		||||
    address private _testTokenAddress;
 | 
			
		||||
    bool private _shouldRevertOnOperate;
 | 
			
		||||
 | 
			
		||||
    event OperateAccount(
 | 
			
		||||
        address owner,
 | 
			
		||||
        uint256 number
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    event OperateAction(
 | 
			
		||||
        ActionType actionType,
 | 
			
		||||
        uint256 accountIdx,
 | 
			
		||||
        bool amountSign,
 | 
			
		||||
        AssetDenomination amountDenomination,
 | 
			
		||||
        AssetReference amountRef,
 | 
			
		||||
        uint256 amountValue,
 | 
			
		||||
        uint256 primaryMarketId,
 | 
			
		||||
        uint256 secondaryMarketId,
 | 
			
		||||
        address otherAddress,
 | 
			
		||||
        uint256 otherAccountId,
 | 
			
		||||
        bytes data
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    constructor(address[] memory holders)
 | 
			
		||||
        public
 | 
			
		||||
    {
 | 
			
		||||
        // Deploy a test token. This represents the asset being deposited/withdrawn from dydx.
 | 
			
		||||
        _testTokenAddress = address(new TestDydxBridgeToken(holders));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Simulates `operate` in dydx contract.
 | 
			
		||||
    ///      Emits events so that arguments can be validated client-side.
 | 
			
		||||
    function operate(
 | 
			
		||||
        AccountInfo[] calldata accounts,
 | 
			
		||||
        ActionArgs[] calldata actions
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        if (_shouldRevertOnOperate) {
 | 
			
		||||
            revert("TestDydxBridge/SHOULD_REVERT_ON_OPERATE");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (uint i = 0; i < accounts.length; ++i) {
 | 
			
		||||
            emit OperateAccount(
 | 
			
		||||
                accounts[i].owner,
 | 
			
		||||
                accounts[i].number
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (uint i = 0; i < actions.length; ++i) {
 | 
			
		||||
            emit OperateAction(
 | 
			
		||||
                actions[i].actionType,
 | 
			
		||||
                actions[i].accountIdx,
 | 
			
		||||
                actions[i].amount.sign,
 | 
			
		||||
                actions[i].amount.denomination,
 | 
			
		||||
                actions[i].amount.ref,
 | 
			
		||||
                actions[i].amount.value,
 | 
			
		||||
                actions[i].primaryMarketId,
 | 
			
		||||
                actions[i].secondaryMarketId,
 | 
			
		||||
                actions[i].otherAddress,
 | 
			
		||||
                actions[i].otherAccountIdx,
 | 
			
		||||
                actions[i].data
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            if (actions[i].actionType == IDydx.ActionType.Withdraw) {
 | 
			
		||||
                require(
 | 
			
		||||
                    IERC20Token(_testTokenAddress).transferFrom(
 | 
			
		||||
                        address(this),
 | 
			
		||||
                        actions[i].otherAddress,
 | 
			
		||||
                        actions[i].amount.value
 | 
			
		||||
                    ),
 | 
			
		||||
                    "TestDydxBridge/WITHDRAW_FAILED"
 | 
			
		||||
                );
 | 
			
		||||
            } else if (actions[i].actionType == IDydx.ActionType.Deposit) {
 | 
			
		||||
                require(
 | 
			
		||||
                    IERC20Token(_testTokenAddress).transferFrom(
 | 
			
		||||
                        actions[i].otherAddress,
 | 
			
		||||
                        address(this),
 | 
			
		||||
                        actions[i].amount.value
 | 
			
		||||
                    ),
 | 
			
		||||
                    "TestDydxBridge/DEPOSIT_FAILED"
 | 
			
		||||
                );
 | 
			
		||||
            } else {
 | 
			
		||||
                revert("TestDydxBridge/UNSUPPORTED_ACTION");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev If `true` then subsequent calls to `operate` will revert.
 | 
			
		||||
    function setRevertOnOperate(bool shouldRevert)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        _shouldRevertOnOperate = shouldRevert;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Returns test token.
 | 
			
		||||
    function getTestToken()
 | 
			
		||||
        external
 | 
			
		||||
        returns (address)
 | 
			
		||||
    {
 | 
			
		||||
        return _testTokenAddress;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Unused.
 | 
			
		||||
    function setOperators(OperatorArg[] calldata args) external {}
 | 
			
		||||
 | 
			
		||||
    /// @dev Unused.
 | 
			
		||||
    function getIsLocalOperator(
 | 
			
		||||
        address owner,
 | 
			
		||||
        address operator
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bool isLocalOperator)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    /// @dev Unused.
 | 
			
		||||
    function getMarketTokenAddress(
 | 
			
		||||
        uint256 marketId
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (address tokenAddress)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    /// @dev Unused.
 | 
			
		||||
    function getRiskParams()
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (RiskParams memory riskParams)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    /// @dev Unsused.
 | 
			
		||||
    function getMarketPrice(
 | 
			
		||||
        uint256 marketId
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (Price memory price)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    /// @dev Unsused
 | 
			
		||||
    function getMarketMarginPremium(uint256 marketId)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (IDydx.D256 memory premium)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    /// @dev Unused.
 | 
			
		||||
    function getAdjustedAccountValues(
 | 
			
		||||
        AccountInfo calldata account
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (Value memory supplyValue, Value memory borrowValue)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    /// @dev overrides `_getDydxAddress()` from `DeploymentConstants` to return this address.
 | 
			
		||||
    function _getDydxAddress()
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (address)
 | 
			
		||||
    {
 | 
			
		||||
        return address(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev overrides `_getERC20BridgeProxyAddress()` from `DeploymentConstants` for testing.
 | 
			
		||||
    function _getERC20BridgeProxyAddress()
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (address)
 | 
			
		||||
    {
 | 
			
		||||
        return msg.sender == ALWAYS_REVERT_ADDRESS ? address(0) : msg.sender;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										108
									
								
								contracts/asset-proxy/contracts/test/TestERC20Bridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								contracts/asset-proxy/contracts/test/TestERC20Bridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "../src/interfaces/IERC20Bridge.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev Test bridge token
 | 
			
		||||
contract TestERC20BridgeToken {
 | 
			
		||||
    mapping (address => uint256) private _balances;
 | 
			
		||||
 | 
			
		||||
    function addBalance(address owner, int256 amount)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        setBalance(owner, uint256(int256(balanceOf(owner)) + amount));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setBalance(address owner, uint256 balance)
 | 
			
		||||
        public
 | 
			
		||||
    {
 | 
			
		||||
        _balances[owner] = balance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function balanceOf(address owner)
 | 
			
		||||
        public
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256)
 | 
			
		||||
    {
 | 
			
		||||
        return _balances[owner];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev Test bridge contract.
 | 
			
		||||
contract TestERC20Bridge is
 | 
			
		||||
    IERC20Bridge
 | 
			
		||||
{
 | 
			
		||||
    TestERC20BridgeToken public testToken;
 | 
			
		||||
 | 
			
		||||
    event BridgeWithdrawTo(
 | 
			
		||||
        address tokenAddress,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes bridgeData
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    constructor() public {
 | 
			
		||||
        testToken = new TestERC20BridgeToken();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setTestTokenBalance(address owner, uint256 balance)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        testToken.setBalance(owner, balance);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function bridgeTransferFrom(
 | 
			
		||||
        address tokenAddress,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount,
 | 
			
		||||
        bytes calldata bridgeData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bytes4)
 | 
			
		||||
    {
 | 
			
		||||
        emit BridgeWithdrawTo(
 | 
			
		||||
            tokenAddress,
 | 
			
		||||
            from,
 | 
			
		||||
            to,
 | 
			
		||||
            amount,
 | 
			
		||||
            bridgeData
 | 
			
		||||
        );
 | 
			
		||||
        // Unpack the bridgeData.
 | 
			
		||||
        (
 | 
			
		||||
            int256 transferAmount,
 | 
			
		||||
            bytes memory revertData,
 | 
			
		||||
            bytes memory returnData
 | 
			
		||||
        ) = abi.decode(bridgeData, (int256, bytes, bytes));
 | 
			
		||||
 | 
			
		||||
        // If `revertData` is set, revert.
 | 
			
		||||
        if (revertData.length != 0) {
 | 
			
		||||
            assembly { revert(add(revertData, 0x20), mload(revertData)) }
 | 
			
		||||
        }
 | 
			
		||||
        // Increase `to`'s balance by `transferAmount`.
 | 
			
		||||
        TestERC20BridgeToken(tokenAddress).addBalance(to, transferAmount);
 | 
			
		||||
        // Return `returnData`.
 | 
			
		||||
        assembly { return(add(returnData, 0x20), mload(returnData)) }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										206
									
								
								contracts/asset-proxy/contracts/test/TestEth2DaiBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								contracts/asset-proxy/contracts/test/TestEth2DaiBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,206 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "../src/bridges/Eth2DaiBridge.sol";
 | 
			
		||||
import "../src/interfaces/IEth2Dai.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable no-simple-event-func-name
 | 
			
		||||
contract TestEvents {
 | 
			
		||||
 | 
			
		||||
    event TokenTransfer(
 | 
			
		||||
        address token,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    event TokenApprove(
 | 
			
		||||
        address token,
 | 
			
		||||
        address spender,
 | 
			
		||||
        uint256 allowance
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    function raiseTokenTransfer(
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        emit TokenTransfer(
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            from,
 | 
			
		||||
            to,
 | 
			
		||||
            amount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function raiseTokenApprove(address spender, uint256 allowance)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        emit TokenApprove(msg.sender, spender, allowance);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev A minimalist ERC20 token.
 | 
			
		||||
contract TestToken {
 | 
			
		||||
 | 
			
		||||
    mapping (address => uint256) public balances;
 | 
			
		||||
    string private _nextTransferRevertReason;
 | 
			
		||||
    bytes private _nextTransferReturnData;
 | 
			
		||||
 | 
			
		||||
    /// @dev Just calls `raiseTokenTransfer()` on the caller.
 | 
			
		||||
    function transfer(address to, uint256 amount)
 | 
			
		||||
        external
 | 
			
		||||
        returns (bool)
 | 
			
		||||
    {
 | 
			
		||||
        TestEvents(msg.sender).raiseTokenTransfer(msg.sender, to, amount);
 | 
			
		||||
        if (bytes(_nextTransferRevertReason).length != 0) {
 | 
			
		||||
            revert(_nextTransferRevertReason);
 | 
			
		||||
        }
 | 
			
		||||
        bytes memory returnData = _nextTransferReturnData;
 | 
			
		||||
        assembly { return(add(returnData, 0x20), mload(returnData)) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Set the balance for `owner`.
 | 
			
		||||
    function setBalance(address owner, uint256 balance)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        balances[owner] = balance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Set the behavior of the `transfer()` call.
 | 
			
		||||
    function setTransferBehavior(
 | 
			
		||||
        string calldata revertReason,
 | 
			
		||||
        bytes calldata returnData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        _nextTransferRevertReason = revertReason;
 | 
			
		||||
        _nextTransferReturnData = returnData;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Just calls `raiseTokenApprove()` on the caller.
 | 
			
		||||
    function approve(address spender, uint256 allowance)
 | 
			
		||||
        external
 | 
			
		||||
        returns (bool)
 | 
			
		||||
    {
 | 
			
		||||
        TestEvents(msg.sender).raiseTokenApprove(spender, allowance);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function allowance(address, address) external view returns (uint256) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Retrieve the balance for `owner`.
 | 
			
		||||
    function balanceOf(address owner)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256)
 | 
			
		||||
    {
 | 
			
		||||
        return balances[owner];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev Eth2DaiBridge overridden to mock tokens and
 | 
			
		||||
///      implement IEth2Dai.
 | 
			
		||||
contract TestEth2DaiBridge is
 | 
			
		||||
    TestEvents,
 | 
			
		||||
    IEth2Dai,
 | 
			
		||||
    Eth2DaiBridge
 | 
			
		||||
{
 | 
			
		||||
    event SellAllAmount(
 | 
			
		||||
        address sellToken,
 | 
			
		||||
        uint256 sellTokenAmount,
 | 
			
		||||
        address buyToken,
 | 
			
		||||
        uint256 minimumFillAmount
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    mapping (address => TestToken)  public testTokens;
 | 
			
		||||
    string private _nextRevertReason;
 | 
			
		||||
    uint256 private _nextFillAmount;
 | 
			
		||||
 | 
			
		||||
    /// @dev Create a token and set this contract's balance.
 | 
			
		||||
    function createToken(uint256 balance)
 | 
			
		||||
        external
 | 
			
		||||
        returns (address tokenAddress)
 | 
			
		||||
    {
 | 
			
		||||
        TestToken token = new TestToken();
 | 
			
		||||
        testTokens[address(token)] = token;
 | 
			
		||||
        token.setBalance(address(this), balance);
 | 
			
		||||
        return address(token);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Set the behavior for `IEth2Dai.sellAllAmount()`.
 | 
			
		||||
    function setFillBehavior(string calldata revertReason, uint256 fillAmount)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        _nextRevertReason = revertReason;
 | 
			
		||||
        _nextFillAmount = fillAmount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Set the behavior of a token's `transfer()`.
 | 
			
		||||
    function setTransferBehavior(
 | 
			
		||||
        address tokenAddress,
 | 
			
		||||
        string calldata revertReason,
 | 
			
		||||
        bytes calldata returnData
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        testTokens[tokenAddress].setTransferBehavior(revertReason, returnData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Implementation of `IEth2Dai.sellAllAmount()`
 | 
			
		||||
    function sellAllAmount(
 | 
			
		||||
        address sellTokenAddress,
 | 
			
		||||
        uint256 sellTokenAmount,
 | 
			
		||||
        address buyTokenAddress,
 | 
			
		||||
        uint256 minimumFillAmount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 fillAmount)
 | 
			
		||||
    {
 | 
			
		||||
        emit SellAllAmount(
 | 
			
		||||
            sellTokenAddress,
 | 
			
		||||
            sellTokenAmount,
 | 
			
		||||
            buyTokenAddress,
 | 
			
		||||
            minimumFillAmount
 | 
			
		||||
        );
 | 
			
		||||
        if (bytes(_nextRevertReason).length != 0) {
 | 
			
		||||
            revert(_nextRevertReason);
 | 
			
		||||
        }
 | 
			
		||||
        return _nextFillAmount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // @dev This contract will double as the Eth2Dai contract.
 | 
			
		||||
    function _getEth2DaiAddress()
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (address)
 | 
			
		||||
    {
 | 
			
		||||
        return address(this);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										355
									
								
								contracts/asset-proxy/contracts/test/TestKyberBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										355
									
								
								contracts/asset-proxy/contracts/test/TestKyberBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,355 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "../src/bridges/KyberBridge.sol";
 | 
			
		||||
import "../src/interfaces/IKyberNetworkProxy.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable no-simple-event-func-name
 | 
			
		||||
interface ITestContract {
 | 
			
		||||
 | 
			
		||||
    function wethWithdraw(
 | 
			
		||||
        address payable ownerAddress,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        external;
 | 
			
		||||
 | 
			
		||||
    function wethDeposit(
 | 
			
		||||
        address ownerAddress
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable;
 | 
			
		||||
 | 
			
		||||
    function tokenTransfer(
 | 
			
		||||
        address ownerAddress,
 | 
			
		||||
        address recipientAddress,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bool success);
 | 
			
		||||
 | 
			
		||||
    function tokenApprove(
 | 
			
		||||
        address ownerAddress,
 | 
			
		||||
        address spenderAddress,
 | 
			
		||||
        uint256 allowance
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bool success);
 | 
			
		||||
 | 
			
		||||
    function tokenBalanceOf(
 | 
			
		||||
        address ownerAddress
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 balance);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev A minimalist ERC20/WETH token.
 | 
			
		||||
contract TestToken {
 | 
			
		||||
 | 
			
		||||
    uint8 public decimals;
 | 
			
		||||
    ITestContract private _testContract;
 | 
			
		||||
 | 
			
		||||
    constructor(uint8 decimals_) public {
 | 
			
		||||
        decimals = decimals_;
 | 
			
		||||
        _testContract = ITestContract(msg.sender);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function approve(address spender, uint256 allowance)
 | 
			
		||||
        external
 | 
			
		||||
        returns (bool)
 | 
			
		||||
    {
 | 
			
		||||
        return _testContract.tokenApprove(
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            spender,
 | 
			
		||||
            allowance
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function transfer(address recipient, uint256 amount)
 | 
			
		||||
        external
 | 
			
		||||
        returns (bool)
 | 
			
		||||
    {
 | 
			
		||||
        return _testContract.tokenTransfer(
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            recipient,
 | 
			
		||||
            amount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function withdraw(uint256 amount)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        return _testContract.wethWithdraw(msg.sender, amount);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function deposit()
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
    {
 | 
			
		||||
        return _testContract.wethDeposit.value(msg.value)(msg.sender);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function allowance(address, address) external view returns (uint256) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function balanceOf(address owner)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256)
 | 
			
		||||
    {
 | 
			
		||||
        return _testContract.tokenBalanceOf(owner);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev KyberBridge overridden to mock tokens and implement IKyberBridge.
 | 
			
		||||
contract TestKyberBridge is
 | 
			
		||||
    KyberBridge,
 | 
			
		||||
    ITestContract,
 | 
			
		||||
    IKyberNetworkProxy
 | 
			
		||||
{
 | 
			
		||||
    event KyberBridgeTrade(
 | 
			
		||||
        uint256 msgValue,
 | 
			
		||||
        address sellTokenAddress,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        address buyTokenAddress,
 | 
			
		||||
        address payable recipientAddress,
 | 
			
		||||
        uint256 maxBuyTokenAmount,
 | 
			
		||||
        uint256 minConversionRate,
 | 
			
		||||
        address walletId
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    event KyberBridgeWethWithdraw(
 | 
			
		||||
        address ownerAddress,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    event KyberBridgeWethDeposit(
 | 
			
		||||
        uint256 msgValue,
 | 
			
		||||
        address ownerAddress,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    event KyberBridgeTokenApprove(
 | 
			
		||||
        address tokenAddress,
 | 
			
		||||
        address ownerAddress,
 | 
			
		||||
        address spenderAddress,
 | 
			
		||||
        uint256 allowance
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    event KyberBridgeTokenTransfer(
 | 
			
		||||
        address tokenAddress,
 | 
			
		||||
        address ownerAddress,
 | 
			
		||||
        address recipientAddress,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    IEtherToken public weth;
 | 
			
		||||
    mapping (address => mapping (address => uint256)) private _tokenBalances;
 | 
			
		||||
    uint256 private _nextFillAmount;
 | 
			
		||||
 | 
			
		||||
    constructor() public {
 | 
			
		||||
        weth = IEtherToken(address(new TestToken(18)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Implementation of `IKyberNetworkProxy.trade()`
 | 
			
		||||
    function trade(
 | 
			
		||||
        address sellTokenAddress,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        address buyTokenAddress,
 | 
			
		||||
        address payable recipientAddress,
 | 
			
		||||
        uint256 maxBuyTokenAmount,
 | 
			
		||||
        uint256 minConversionRate,
 | 
			
		||||
        address walletId
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        returns(uint256 boughtAmount)
 | 
			
		||||
    {
 | 
			
		||||
        emit KyberBridgeTrade(
 | 
			
		||||
            msg.value,
 | 
			
		||||
            sellTokenAddress,
 | 
			
		||||
            sellAmount,
 | 
			
		||||
            buyTokenAddress,
 | 
			
		||||
            recipientAddress,
 | 
			
		||||
            maxBuyTokenAmount,
 | 
			
		||||
            minConversionRate,
 | 
			
		||||
            walletId
 | 
			
		||||
        );
 | 
			
		||||
        return _nextFillAmount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function tradeWithHint(
 | 
			
		||||
        address sellTokenAddress,
 | 
			
		||||
        uint256 sellAmount,
 | 
			
		||||
        address buyTokenAddress,
 | 
			
		||||
        address payable recipientAddress,
 | 
			
		||||
        uint256 maxBuyTokenAmount,
 | 
			
		||||
        uint256 minConversionRate,
 | 
			
		||||
        address payable walletId,
 | 
			
		||||
        bytes calldata hint
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        returns (uint256 boughtAmount)
 | 
			
		||||
    {
 | 
			
		||||
        emit KyberBridgeTrade(
 | 
			
		||||
            msg.value,
 | 
			
		||||
            sellTokenAddress,
 | 
			
		||||
            sellAmount,
 | 
			
		||||
            buyTokenAddress,
 | 
			
		||||
            recipientAddress,
 | 
			
		||||
            maxBuyTokenAmount,
 | 
			
		||||
            minConversionRate,
 | 
			
		||||
            walletId
 | 
			
		||||
        );
 | 
			
		||||
        return _nextFillAmount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function createToken(uint8 decimals)
 | 
			
		||||
        external
 | 
			
		||||
        returns (address tokenAddress)
 | 
			
		||||
    {
 | 
			
		||||
        return address(new TestToken(decimals));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setNextFillAmount(uint256 amount)
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
    {
 | 
			
		||||
        if (msg.value != 0) {
 | 
			
		||||
            require(amount == msg.value, "VALUE_AMOUNT_MISMATCH");
 | 
			
		||||
            grantTokensTo(address(weth), address(this), msg.value);
 | 
			
		||||
        }
 | 
			
		||||
        _nextFillAmount = amount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function wethDeposit(
 | 
			
		||||
        address ownerAddress
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
    {
 | 
			
		||||
        require(msg.sender == address(weth), "ONLY_WETH");
 | 
			
		||||
        grantTokensTo(address(weth), ownerAddress, msg.value);
 | 
			
		||||
        emit KyberBridgeWethDeposit(
 | 
			
		||||
            msg.value,
 | 
			
		||||
            ownerAddress,
 | 
			
		||||
            msg.value
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function wethWithdraw(
 | 
			
		||||
        address payable ownerAddress,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        require(msg.sender == address(weth), "ONLY_WETH");
 | 
			
		||||
        _tokenBalances[address(weth)][ownerAddress] -= amount;
 | 
			
		||||
        ownerAddress.transfer(amount);
 | 
			
		||||
        emit KyberBridgeWethWithdraw(
 | 
			
		||||
            ownerAddress,
 | 
			
		||||
            amount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function tokenApprove(
 | 
			
		||||
        address ownerAddress,
 | 
			
		||||
        address spenderAddress,
 | 
			
		||||
        uint256 allowance
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bool success)
 | 
			
		||||
    {
 | 
			
		||||
        emit KyberBridgeTokenApprove(
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            ownerAddress,
 | 
			
		||||
            spenderAddress,
 | 
			
		||||
            allowance
 | 
			
		||||
        );
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function tokenTransfer(
 | 
			
		||||
        address ownerAddress,
 | 
			
		||||
        address recipientAddress,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (bool success)
 | 
			
		||||
    {
 | 
			
		||||
        _tokenBalances[msg.sender][ownerAddress] -= amount;
 | 
			
		||||
        _tokenBalances[msg.sender][recipientAddress] += amount;
 | 
			
		||||
        emit KyberBridgeTokenTransfer(
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            ownerAddress,
 | 
			
		||||
            recipientAddress,
 | 
			
		||||
            amount
 | 
			
		||||
        );
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function tokenBalanceOf(
 | 
			
		||||
        address ownerAddress
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256 balance)
 | 
			
		||||
    {
 | 
			
		||||
        return _tokenBalances[msg.sender][ownerAddress];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function grantTokensTo(address tokenAddress, address ownerAddress, uint256 amount)
 | 
			
		||||
        public
 | 
			
		||||
        payable
 | 
			
		||||
    {
 | 
			
		||||
        _tokenBalances[tokenAddress][ownerAddress] += amount;
 | 
			
		||||
        if (tokenAddress != address(weth)) {
 | 
			
		||||
            // Send back ether if not WETH.
 | 
			
		||||
            msg.sender.transfer(msg.value);
 | 
			
		||||
        } else {
 | 
			
		||||
            require(msg.value == amount, "VALUE_AMOUNT_MISMATCH");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // @dev overridden to point to this contract.
 | 
			
		||||
    function _getKyberNetworkProxyAddress()
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (address)
 | 
			
		||||
    {
 | 
			
		||||
        return address(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // @dev overridden to point to test WETH.
 | 
			
		||||
    function _getWethAddress()
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (address)
 | 
			
		||||
    {
 | 
			
		||||
        return address(weth);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,82 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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/LibBytes.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract TestStaticCallTarget {
 | 
			
		||||
 | 
			
		||||
    using LibBytes for bytes;
 | 
			
		||||
 | 
			
		||||
    uint256 internal _state;
 | 
			
		||||
 
 | 
			
		||||
    function updateState()
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        _state++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function assertEvenNumber(uint256 target)
 | 
			
		||||
        external
 | 
			
		||||
        pure
 | 
			
		||||
    {
 | 
			
		||||
        require(
 | 
			
		||||
            target % 2 == 0,
 | 
			
		||||
            "TARGET_NOT_EVEN"
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function isOddNumber(uint256 target)
 | 
			
		||||
        external
 | 
			
		||||
        pure
 | 
			
		||||
        returns (bool isOdd)
 | 
			
		||||
    {
 | 
			
		||||
        isOdd = target % 2 == 1;
 | 
			
		||||
        return isOdd;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function noInputFunction()
 | 
			
		||||
        external
 | 
			
		||||
        pure
 | 
			
		||||
    {
 | 
			
		||||
        assert(msg.data.length == 4 && msg.data.readBytes4(0) == bytes4(keccak256("noInputFunction()")));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function dynamicInputFunction(bytes calldata a)
 | 
			
		||||
        external
 | 
			
		||||
        pure
 | 
			
		||||
    {
 | 
			
		||||
        bytes memory abiEncodedData = abi.encodeWithSignature("dynamicInputFunction(bytes)", a);
 | 
			
		||||
        assert(msg.data.equals(abiEncodedData));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function returnComplexType(uint256 a, uint256 b)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (bytes memory result)
 | 
			
		||||
    {
 | 
			
		||||
        result = abi.encodePacked(
 | 
			
		||||
            address(this),
 | 
			
		||||
            a,
 | 
			
		||||
            b
 | 
			
		||||
        );
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										436
									
								
								contracts/asset-proxy/contracts/test/TestUniswapBridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										436
									
								
								contracts/asset-proxy/contracts/test/TestUniswapBridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,436 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
 | 
			
		||||
import "../src/bridges/UniswapBridge.sol";
 | 
			
		||||
import "../src/interfaces/IUniswapExchangeFactory.sol";
 | 
			
		||||
import "../src/interfaces/IUniswapExchange.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// solhint-disable no-simple-event-func-name
 | 
			
		||||
contract TestEventsRaiser {
 | 
			
		||||
 | 
			
		||||
    event TokenTransfer(
 | 
			
		||||
        address token,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    event TokenApprove(
 | 
			
		||||
        address spender,
 | 
			
		||||
        uint256 allowance
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    event WethDeposit(
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    event WethWithdraw(
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    event EthToTokenTransferInput(
 | 
			
		||||
        address exchange,
 | 
			
		||||
        uint256 minTokensBought,
 | 
			
		||||
        uint256 deadline,
 | 
			
		||||
        address recipient
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    event TokenToEthSwapInput(
 | 
			
		||||
        address exchange,
 | 
			
		||||
        uint256 tokensSold,
 | 
			
		||||
        uint256 minEthBought,
 | 
			
		||||
        uint256 deadline
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    event TokenToTokenTransferInput(
 | 
			
		||||
        address exchange,
 | 
			
		||||
        uint256 tokensSold,
 | 
			
		||||
        uint256 minTokensBought,
 | 
			
		||||
        uint256 minEthBought,
 | 
			
		||||
        uint256 deadline,
 | 
			
		||||
        address recipient,
 | 
			
		||||
        address toTokenAddress
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    function raiseEthToTokenTransferInput(
 | 
			
		||||
        uint256 minTokensBought,
 | 
			
		||||
        uint256 deadline,
 | 
			
		||||
        address recipient
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        emit EthToTokenTransferInput(
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            minTokensBought,
 | 
			
		||||
            deadline,
 | 
			
		||||
            recipient
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function raiseTokenToEthSwapInput(
 | 
			
		||||
        uint256 tokensSold,
 | 
			
		||||
        uint256 minEthBought,
 | 
			
		||||
        uint256 deadline
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        emit TokenToEthSwapInput(
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            tokensSold,
 | 
			
		||||
            minEthBought,
 | 
			
		||||
            deadline
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function raiseTokenToTokenTransferInput(
 | 
			
		||||
        uint256 tokensSold,
 | 
			
		||||
        uint256 minTokensBought,
 | 
			
		||||
        uint256 minEthBought,
 | 
			
		||||
        uint256 deadline,
 | 
			
		||||
        address recipient,
 | 
			
		||||
        address toTokenAddress
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        emit TokenToTokenTransferInput(
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            tokensSold,
 | 
			
		||||
            minTokensBought,
 | 
			
		||||
            minEthBought,
 | 
			
		||||
            deadline,
 | 
			
		||||
            recipient,
 | 
			
		||||
            toTokenAddress
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function raiseTokenTransfer(
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        emit TokenTransfer(
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            from,
 | 
			
		||||
            to,
 | 
			
		||||
            amount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function raiseTokenApprove(address spender, uint256 allowance)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        emit TokenApprove(spender, allowance);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function raiseWethDeposit(uint256 amount)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        emit WethDeposit(amount);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function raiseWethWithdraw(uint256 amount)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        emit WethWithdraw(amount);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev A minimalist ERC20/WETH token.
 | 
			
		||||
contract TestToken {
 | 
			
		||||
 | 
			
		||||
    using LibSafeMath for uint256;
 | 
			
		||||
 | 
			
		||||
    mapping (address => uint256) public balances;
 | 
			
		||||
    string private _nextRevertReason;
 | 
			
		||||
 | 
			
		||||
    /// @dev Set the balance for `owner`.
 | 
			
		||||
    function setBalance(address owner)
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
    {
 | 
			
		||||
        balances[owner] = msg.value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Set the revert reason for `transfer()`,
 | 
			
		||||
    ///      `deposit()`, and `withdraw()`.
 | 
			
		||||
    function setRevertReason(string calldata reason)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        _nextRevertReason = reason;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Just calls `raiseTokenTransfer()` on the caller.
 | 
			
		||||
    function transfer(address to, uint256 amount)
 | 
			
		||||
        external
 | 
			
		||||
        returns (bool)
 | 
			
		||||
    {
 | 
			
		||||
        _revertIfReasonExists();
 | 
			
		||||
        TestEventsRaiser(msg.sender).raiseTokenTransfer(msg.sender, to, amount);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Just calls `raiseTokenApprove()` on the caller.
 | 
			
		||||
    function approve(address spender, uint256 allowance)
 | 
			
		||||
        external
 | 
			
		||||
        returns (bool)
 | 
			
		||||
    {
 | 
			
		||||
        TestEventsRaiser(msg.sender).raiseTokenApprove(spender, allowance);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `IWETH.deposit()` that increases balances and calls
 | 
			
		||||
    ///     `raiseWethDeposit()` on the caller.
 | 
			
		||||
    function deposit()
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
    {
 | 
			
		||||
        _revertIfReasonExists();
 | 
			
		||||
        balances[msg.sender] += balances[msg.sender].safeAdd(msg.value);
 | 
			
		||||
        TestEventsRaiser(msg.sender).raiseWethDeposit(msg.value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `IWETH.withdraw()` that just reduces balances and calls
 | 
			
		||||
    ///       `raiseWethWithdraw()` on the caller.
 | 
			
		||||
    function withdraw(uint256 amount)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        _revertIfReasonExists();
 | 
			
		||||
        balances[msg.sender] = balances[msg.sender].safeSub(amount);
 | 
			
		||||
        msg.sender.transfer(amount);
 | 
			
		||||
        TestEventsRaiser(msg.sender).raiseWethWithdraw(amount);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function allowance(address, address) external view returns (uint256) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Retrieve the balance for `owner`.
 | 
			
		||||
    function balanceOf(address owner)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256)
 | 
			
		||||
    {
 | 
			
		||||
        return balances[owner];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _revertIfReasonExists()
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
    {
 | 
			
		||||
        if (bytes(_nextRevertReason).length != 0) {
 | 
			
		||||
            revert(_nextRevertReason);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract TestExchange is
 | 
			
		||||
    IUniswapExchange
 | 
			
		||||
{
 | 
			
		||||
    address public tokenAddress;
 | 
			
		||||
    string private _nextRevertReason;
 | 
			
		||||
 | 
			
		||||
    constructor(address _tokenAddress) public {
 | 
			
		||||
        tokenAddress = _tokenAddress;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setFillBehavior(
 | 
			
		||||
        string calldata revertReason
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
    {
 | 
			
		||||
        _nextRevertReason = revertReason;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function ethToTokenTransferInput(
 | 
			
		||||
        uint256 minTokensBought,
 | 
			
		||||
        uint256 deadline,
 | 
			
		||||
        address recipient
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        returns (uint256 tokensBought)
 | 
			
		||||
    {
 | 
			
		||||
        TestEventsRaiser(msg.sender).raiseEthToTokenTransferInput(
 | 
			
		||||
            minTokensBought,
 | 
			
		||||
            deadline,
 | 
			
		||||
            recipient
 | 
			
		||||
        );
 | 
			
		||||
        _revertIfReasonExists();
 | 
			
		||||
        return address(this).balance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function tokenToEthSwapInput(
 | 
			
		||||
        uint256 tokensSold,
 | 
			
		||||
        uint256 minEthBought,
 | 
			
		||||
        uint256 deadline
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 ethBought)
 | 
			
		||||
    {
 | 
			
		||||
        TestEventsRaiser(msg.sender).raiseTokenToEthSwapInput(
 | 
			
		||||
            tokensSold,
 | 
			
		||||
            minEthBought,
 | 
			
		||||
            deadline
 | 
			
		||||
        );
 | 
			
		||||
        _revertIfReasonExists();
 | 
			
		||||
        uint256 fillAmount = address(this).balance;
 | 
			
		||||
        msg.sender.transfer(fillAmount);
 | 
			
		||||
        return fillAmount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function tokenToTokenTransferInput(
 | 
			
		||||
        uint256 tokensSold,
 | 
			
		||||
        uint256 minTokensBought,
 | 
			
		||||
        uint256 minEthBought,
 | 
			
		||||
        uint256 deadline,
 | 
			
		||||
        address recipient,
 | 
			
		||||
        address toTokenAddress
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (uint256 tokensBought)
 | 
			
		||||
    {
 | 
			
		||||
        TestEventsRaiser(msg.sender).raiseTokenToTokenTransferInput(
 | 
			
		||||
            tokensSold,
 | 
			
		||||
            minTokensBought,
 | 
			
		||||
            minEthBought,
 | 
			
		||||
            deadline,
 | 
			
		||||
            recipient,
 | 
			
		||||
            toTokenAddress
 | 
			
		||||
        );
 | 
			
		||||
        _revertIfReasonExists();
 | 
			
		||||
        return address(this).balance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function toTokenAddress()
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (address _tokenAddress)
 | 
			
		||||
    {
 | 
			
		||||
        return tokenAddress;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _revertIfReasonExists()
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
    {
 | 
			
		||||
        if (bytes(_nextRevertReason).length != 0) {
 | 
			
		||||
            revert(_nextRevertReason);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev UniswapBridge overridden to mock tokens and implement IUniswapExchangeFactory.
 | 
			
		||||
contract TestUniswapBridge is
 | 
			
		||||
    IUniswapExchangeFactory,
 | 
			
		||||
    TestEventsRaiser,
 | 
			
		||||
    UniswapBridge
 | 
			
		||||
{
 | 
			
		||||
    TestToken public wethToken;
 | 
			
		||||
    // Token address to TestToken instance.
 | 
			
		||||
    mapping (address => TestToken) private _testTokens;
 | 
			
		||||
    // Token address to TestExchange instance.
 | 
			
		||||
    mapping (address => TestExchange) private _testExchanges;
 | 
			
		||||
 | 
			
		||||
    constructor() public {
 | 
			
		||||
        wethToken = new TestToken();
 | 
			
		||||
        _testTokens[address(wethToken)] = wethToken;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sets the balance of this contract for an existing token.
 | 
			
		||||
    ///      The wei attached will be the balance.
 | 
			
		||||
    function setTokenBalance(address tokenAddress)
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
    {
 | 
			
		||||
        TestToken token = _testTokens[tokenAddress];
 | 
			
		||||
        token.deposit.value(msg.value)();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sets the revert reason for an existing token.
 | 
			
		||||
    function setTokenRevertReason(address tokenAddress, string calldata revertReason)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        TestToken token = _testTokens[tokenAddress];
 | 
			
		||||
        token.setRevertReason(revertReason);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Create a token and exchange (if they don't exist) for a new token
 | 
			
		||||
    ///      and sets the exchange revert and fill behavior. The wei attached
 | 
			
		||||
    ///      will be the fill amount for the exchange.
 | 
			
		||||
    /// @param tokenAddress The token address. If zero, one will be created.
 | 
			
		||||
    /// @param revertReason The revert reason for exchange operations.
 | 
			
		||||
    function createTokenAndExchange(
 | 
			
		||||
        address tokenAddress,
 | 
			
		||||
        string calldata revertReason
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
        returns (TestToken token, TestExchange exchange)
 | 
			
		||||
    {
 | 
			
		||||
        token = TestToken(tokenAddress);
 | 
			
		||||
        if (tokenAddress == address(0)) {
 | 
			
		||||
            token = new TestToken();
 | 
			
		||||
        }
 | 
			
		||||
        _testTokens[address(token)] = token;
 | 
			
		||||
        exchange = _testExchanges[address(token)];
 | 
			
		||||
        if (address(exchange) == address(0)) {
 | 
			
		||||
            _testExchanges[address(token)] = exchange = new TestExchange(address(token));
 | 
			
		||||
        }
 | 
			
		||||
        exchange.setFillBehavior.value(msg.value)(revertReason);
 | 
			
		||||
        return (token, exchange);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev `IUniswapExchangeFactory.getExchange`
 | 
			
		||||
    function getExchange(address tokenAddress)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (address)
 | 
			
		||||
    {
 | 
			
		||||
        return address(_testExchanges[tokenAddress]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // @dev Use `wethToken`.
 | 
			
		||||
    function _getWethAddress()
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (address)
 | 
			
		||||
    {
 | 
			
		||||
        return address(wethToken);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // @dev This contract will double as the Uniswap contract.
 | 
			
		||||
    function _getUniswapExchangeFactoryAddress()
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (address)
 | 
			
		||||
    {
 | 
			
		||||
        return address(this);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										253
									
								
								contracts/asset-proxy/contracts/test/TestUniswapV2Bridge.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										253
									
								
								contracts/asset-proxy/contracts/test/TestUniswapV2Bridge.sol
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,253 @@
 | 
			
		||||
/*
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
pragma experimental ABIEncoderV2;
 | 
			
		||||
 | 
			
		||||
import "@0x/contracts-erc20/contracts/src/interfaces/IERC20Token.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
 | 
			
		||||
import "@0x/contracts-utils/contracts/src/LibAddressArray.sol";
 | 
			
		||||
import "../src/bridges/UniswapV2Bridge.sol";
 | 
			
		||||
import "../src/interfaces/IUniswapV2Router01.sol";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
contract TestEventsRaiser {
 | 
			
		||||
 | 
			
		||||
    event TokenTransfer(
 | 
			
		||||
        address token,
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    event TokenApprove(
 | 
			
		||||
        address spender,
 | 
			
		||||
        uint256 allowance
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    event SwapExactTokensForTokensInput(
 | 
			
		||||
        uint amountIn,
 | 
			
		||||
        uint amountOutMin,
 | 
			
		||||
        address toTokenAddress,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint deadline
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    function raiseTokenTransfer(
 | 
			
		||||
        address from,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint256 amount
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        emit TokenTransfer(
 | 
			
		||||
            msg.sender,
 | 
			
		||||
            from,
 | 
			
		||||
            to,
 | 
			
		||||
            amount
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function raiseTokenApprove(address spender, uint256 allowance) external {
 | 
			
		||||
        emit TokenApprove(spender, allowance);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function raiseSwapExactTokensForTokensInput(
 | 
			
		||||
        uint amountIn,
 | 
			
		||||
        uint amountOutMin,
 | 
			
		||||
        address toTokenAddress,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint deadline
 | 
			
		||||
    ) external
 | 
			
		||||
    {
 | 
			
		||||
        emit SwapExactTokensForTokensInput(
 | 
			
		||||
            amountIn,
 | 
			
		||||
            amountOutMin,
 | 
			
		||||
            toTokenAddress,
 | 
			
		||||
            to,
 | 
			
		||||
            deadline
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev A minimalist ERC20 token.
 | 
			
		||||
contract TestToken {
 | 
			
		||||
 | 
			
		||||
    using LibSafeMath for uint256;
 | 
			
		||||
 | 
			
		||||
    mapping (address => uint256) public balances;
 | 
			
		||||
    string private _nextRevertReason;
 | 
			
		||||
 | 
			
		||||
    /// @dev Set the balance for `owner`.
 | 
			
		||||
    function setBalance(address owner, uint256 balance)
 | 
			
		||||
        external
 | 
			
		||||
        payable
 | 
			
		||||
    {
 | 
			
		||||
        balances[owner] = balance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Just emits a TokenTransfer event on the caller
 | 
			
		||||
    function transfer(address to, uint256 amount)
 | 
			
		||||
        external
 | 
			
		||||
        returns (bool)
 | 
			
		||||
    {
 | 
			
		||||
        TestEventsRaiser(msg.sender).raiseTokenTransfer(msg.sender, to, amount);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Just emits a TokenApprove event on the caller
 | 
			
		||||
    function approve(address spender, uint256 allowance)
 | 
			
		||||
        external
 | 
			
		||||
        returns (bool)
 | 
			
		||||
    {
 | 
			
		||||
        TestEventsRaiser(msg.sender).raiseTokenApprove(spender, allowance);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function allowance(address, address) external view returns (uint256) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Retrieve the balance for `owner`.
 | 
			
		||||
    function balanceOf(address owner)
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (uint256)
 | 
			
		||||
    {
 | 
			
		||||
        return balances[owner];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev Mock the UniswapV2Router01 contract
 | 
			
		||||
contract TestRouter is
 | 
			
		||||
    IUniswapV2Router01
 | 
			
		||||
{
 | 
			
		||||
    string private _nextRevertReason;
 | 
			
		||||
 | 
			
		||||
    /// @dev Set the revert reason for `swapExactTokensForTokens`.
 | 
			
		||||
    function setRevertReason(string calldata reason)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        _nextRevertReason = reason;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function swapExactTokensForTokens(
 | 
			
		||||
        uint amountIn,
 | 
			
		||||
        uint amountOutMin,
 | 
			
		||||
        address[] calldata path,
 | 
			
		||||
        address to,
 | 
			
		||||
        uint deadline
 | 
			
		||||
    ) external returns (uint[] memory amounts)
 | 
			
		||||
    {
 | 
			
		||||
        _revertIfReasonExists();
 | 
			
		||||
 | 
			
		||||
        amounts = new uint[](path.length);
 | 
			
		||||
        amounts[0] = amountIn;
 | 
			
		||||
        amounts[amounts.length - 1] = amountOutMin;
 | 
			
		||||
 | 
			
		||||
        TestEventsRaiser(msg.sender).raiseSwapExactTokensForTokensInput(
 | 
			
		||||
            // tokens sold
 | 
			
		||||
            amountIn,
 | 
			
		||||
            // tokens bought
 | 
			
		||||
            amountOutMin,
 | 
			
		||||
            // output token (toTokenAddress)
 | 
			
		||||
            path[path.length - 1],
 | 
			
		||||
            // recipient
 | 
			
		||||
            to,
 | 
			
		||||
            // deadline
 | 
			
		||||
            deadline
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _revertIfReasonExists()
 | 
			
		||||
        private
 | 
			
		||||
        view
 | 
			
		||||
    {
 | 
			
		||||
        if (bytes(_nextRevertReason).length != 0) {
 | 
			
		||||
            revert(_nextRevertReason);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// @dev UniswapV2Bridge overridden to mock tokens and Uniswap router
 | 
			
		||||
contract TestUniswapV2Bridge is
 | 
			
		||||
    UniswapV2Bridge,
 | 
			
		||||
    TestEventsRaiser
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    // Token address to TestToken instance.
 | 
			
		||||
    mapping (address => TestToken) private _testTokens;
 | 
			
		||||
    // TestRouter instance.
 | 
			
		||||
    TestRouter private _testRouter;
 | 
			
		||||
 | 
			
		||||
    constructor() public {
 | 
			
		||||
        _testRouter = new TestRouter();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function setRouterRevertReason(string calldata revertReason)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        _testRouter.setRevertReason(revertReason);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Sets the balance of this contract for an existing token.
 | 
			
		||||
    ///      The wei attached will be the balance.
 | 
			
		||||
    function setTokenBalance(address tokenAddress, uint256 balance)
 | 
			
		||||
        external
 | 
			
		||||
    {
 | 
			
		||||
        TestToken token = _testTokens[tokenAddress];
 | 
			
		||||
        token.setBalance(address(this), balance);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// @dev Create a new token
 | 
			
		||||
    /// @param tokenAddress The token address. If zero, one will be created.
 | 
			
		||||
    function createToken(
 | 
			
		||||
        address tokenAddress
 | 
			
		||||
    )
 | 
			
		||||
        external
 | 
			
		||||
        returns (TestToken token)
 | 
			
		||||
    {
 | 
			
		||||
        token = TestToken(tokenAddress);
 | 
			
		||||
        if (tokenAddress == address(0)) {
 | 
			
		||||
            token = new TestToken();
 | 
			
		||||
        }
 | 
			
		||||
        _testTokens[address(token)] = token;
 | 
			
		||||
 | 
			
		||||
        return token;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getRouterAddress()
 | 
			
		||||
        external
 | 
			
		||||
        view
 | 
			
		||||
        returns (address)
 | 
			
		||||
    {
 | 
			
		||||
        return address(_testRouter);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function _getUniswapV2Router01Address()
 | 
			
		||||
        internal
 | 
			
		||||
        view
 | 
			
		||||
        returns (address)
 | 
			
		||||
    {
 | 
			
		||||
        return address(_testRouter);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										99
									
								
								contracts/asset-proxy/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								contracts/asset-proxy/package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,99 @@
 | 
			
		||||
{
 | 
			
		||||
    "name": "@0x/contracts-asset-proxy",
 | 
			
		||||
    "version": "3.7.8-multiplex.0",
 | 
			
		||||
    "engines": {
 | 
			
		||||
        "node": ">=6.12"
 | 
			
		||||
    },
 | 
			
		||||
    "description": "Smart contract components of 0x protocol",
 | 
			
		||||
    "main": "lib/src/index.js",
 | 
			
		||||
    "directories": {
 | 
			
		||||
        "test": "test"
 | 
			
		||||
    },
 | 
			
		||||
    "scripts": {
 | 
			
		||||
        "build": "yarn pre_build && tsc -b",
 | 
			
		||||
        "build:ci": "yarn build",
 | 
			
		||||
        "pre_build": "run-s compile 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": "tslint --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
 | 
			
		||||
        "fix": "tslint --fix --format stylish --project . --exclude ./generated-wrappers/**/* --exclude ./test/generated-wrappers/**/* --exclude ./generated-artifacts/**/* --exclude ./test/generated-artifacts/**/* --exclude **/lib/**/* && yarn lint-contracts",
 | 
			
		||||
        "coverage:report:text": "istanbul report text",
 | 
			
		||||
        "coverage:report:html": "istanbul report html && open coverage/index.html",
 | 
			
		||||
        "profiler:report:html": "istanbul report html && open coverage/index.html",
 | 
			
		||||
        "coverage:report:lcov": "istanbul report lcov",
 | 
			
		||||
        "test:circleci": "yarn test",
 | 
			
		||||
        "contracts:gen": "contracts-gen generate",
 | 
			
		||||
        "contracts:copy": "contracts-gen copy",
 | 
			
		||||
        "lint-contracts": "solhint -c ../.solhint.json contracts/**/**/**/**/*.sol",
 | 
			
		||||
        "compile:truffle": "truffle compile",
 | 
			
		||||
        "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": {
 | 
			
		||||
        "abis": "./test/generated-artifacts/@(BalancerBridge|BancorBridge|ChaiBridge|CreamBridge|CryptoComBridge|CurveBridge|DODOBridge|DexForwarderBridge|DydxBridge|ERC1155Proxy|ERC20BridgeProxy|ERC20Proxy|ERC721Proxy|Eth2DaiBridge|IAssetData|IAssetProxy|IAssetProxyDispatcher|IAuthorizable|IBalancerPool|IBancorNetwork|IChai|ICurve|IDydx|IDydxBridge|IERC20Bridge|IEth2Dai|IGasToken|IKyberNetworkProxy|IMStable|IMooniswap|IShell|IUniswapExchange|IUniswapExchangeFactory|IUniswapV2Router01|KyberBridge|MStableBridge|MixinAssetProxyDispatcher|MixinAuthorizable|MixinGasToken|MooniswapBridge|MultiAssetProxy|Ownable|ShellBridge|SnowSwapBridge|StaticCallProxy|SushiSwapBridge|SwerveBridge|TestBancorBridge|TestChaiBridge|TestDexForwarderBridge|TestDydxBridge|TestERC20Bridge|TestEth2DaiBridge|TestKyberBridge|TestStaticCallTarget|TestUniswapBridge|TestUniswapV2Bridge|UniswapBridge|UniswapV2Bridge).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"
 | 
			
		||||
    },
 | 
			
		||||
    "license": "Apache-2.0",
 | 
			
		||||
    "bugs": {
 | 
			
		||||
        "url": "https://github.com/0xProject/protocol/issues"
 | 
			
		||||
    },
 | 
			
		||||
    "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol",
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "@0x/abi-gen": "^5.4.21",
 | 
			
		||||
        "@0x/contract-wrappers": "^13.14.0-multiplex",
 | 
			
		||||
        "@0x/contracts-gen": "^2.0.32",
 | 
			
		||||
        "@0x/contracts-test-utils": "^5.3.23-multiplex.0",
 | 
			
		||||
        "@0x/contracts-utils": "^4.7.5-multiplex.0",
 | 
			
		||||
        "@0x/dev-utils": "^4.2.1",
 | 
			
		||||
        "@0x/sol-compiler": "^4.6.1",
 | 
			
		||||
        "@0x/ts-doc-gen": "^0.0.28",
 | 
			
		||||
        "@0x/tslint-config": "^4.1.3",
 | 
			
		||||
        "@types/lodash": "4.14.104",
 | 
			
		||||
        "@types/mocha": "^5.2.7",
 | 
			
		||||
        "@types/node": "12.12.54",
 | 
			
		||||
        "chai": "^4.0.1",
 | 
			
		||||
        "chai-as-promised": "^7.1.0",
 | 
			
		||||
        "chai-bignumber": "^3.0.0",
 | 
			
		||||
        "dirty-chai": "^2.0.1",
 | 
			
		||||
        "ethereumjs-util": "^5.1.1",
 | 
			
		||||
        "make-promises-safe": "^1.1.0",
 | 
			
		||||
        "mocha": "^6.2.0",
 | 
			
		||||
        "npm-run-all": "^4.1.2",
 | 
			
		||||
        "shx": "^0.2.2",
 | 
			
		||||
        "solhint": "^1.4.1",
 | 
			
		||||
        "truffle": "^5.0.32",
 | 
			
		||||
        "tslint": "5.11.0",
 | 
			
		||||
        "typedoc": "~0.16.11",
 | 
			
		||||
        "typescript": "3.0.1"
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "@0x/base-contract": "^6.2.18",
 | 
			
		||||
        "@0x/contracts-erc1155": "^2.1.26-multiplex.0",
 | 
			
		||||
        "@0x/contracts-erc20": "^3.3.5-multiplex.0",
 | 
			
		||||
        "@0x/contracts-erc721": "^3.1.26-multiplex.0",
 | 
			
		||||
        "@0x/contracts-exchange-libs": "^4.3.26-multiplex.0",
 | 
			
		||||
        "@0x/order-utils": "^10.4.18-multiplex.0",
 | 
			
		||||
        "@0x/types": "^3.3.1",
 | 
			
		||||
        "@0x/typescript-typings": "^5.1.6",
 | 
			
		||||
        "@0x/utils": "^6.2.0",
 | 
			
		||||
        "@0x/web3-wrapper": "^7.4.1",
 | 
			
		||||
        "ethereum-types": "^3.4.0",
 | 
			
		||||
        "lodash": "^4.17.11"
 | 
			
		||||
    },
 | 
			
		||||
    "publishConfig": {
 | 
			
		||||
        "access": "public"
 | 
			
		||||
    },
 | 
			
		||||
    "gitHead": "4f91bfd907996b2f4dd383778b50c479c2602b56"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										127
									
								
								contracts/asset-proxy/src/artifacts.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								contracts/asset-proxy/src/artifacts.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,127 @@
 | 
			
		||||
/*
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 * Warning: This file is auto-generated by contracts-gen. Don't edit manually.
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
import { ContractArtifact } from 'ethereum-types';
 | 
			
		||||
 | 
			
		||||
import * as BalancerBridge from '../generated-artifacts/BalancerBridge.json';
 | 
			
		||||
import * as BancorBridge from '../generated-artifacts/BancorBridge.json';
 | 
			
		||||
import * as ChaiBridge from '../generated-artifacts/ChaiBridge.json';
 | 
			
		||||
import * as CreamBridge from '../generated-artifacts/CreamBridge.json';
 | 
			
		||||
import * as CryptoComBridge from '../generated-artifacts/CryptoComBridge.json';
 | 
			
		||||
import * as CurveBridge from '../generated-artifacts/CurveBridge.json';
 | 
			
		||||
import * as DexForwarderBridge from '../generated-artifacts/DexForwarderBridge.json';
 | 
			
		||||
import * as DODOBridge from '../generated-artifacts/DODOBridge.json';
 | 
			
		||||
import * as DydxBridge from '../generated-artifacts/DydxBridge.json';
 | 
			
		||||
import * as ERC1155Proxy from '../generated-artifacts/ERC1155Proxy.json';
 | 
			
		||||
import * as ERC20BridgeProxy from '../generated-artifacts/ERC20BridgeProxy.json';
 | 
			
		||||
import * as ERC20Proxy from '../generated-artifacts/ERC20Proxy.json';
 | 
			
		||||
import * as ERC721Proxy from '../generated-artifacts/ERC721Proxy.json';
 | 
			
		||||
import * as Eth2DaiBridge from '../generated-artifacts/Eth2DaiBridge.json';
 | 
			
		||||
import * as IAssetData from '../generated-artifacts/IAssetData.json';
 | 
			
		||||
import * as IAssetProxy from '../generated-artifacts/IAssetProxy.json';
 | 
			
		||||
import * as IAssetProxyDispatcher from '../generated-artifacts/IAssetProxyDispatcher.json';
 | 
			
		||||
import * as IAuthorizable from '../generated-artifacts/IAuthorizable.json';
 | 
			
		||||
import * as IBalancerPool from '../generated-artifacts/IBalancerPool.json';
 | 
			
		||||
import * as IBancorNetwork from '../generated-artifacts/IBancorNetwork.json';
 | 
			
		||||
import * as IChai from '../generated-artifacts/IChai.json';
 | 
			
		||||
import * as ICurve from '../generated-artifacts/ICurve.json';
 | 
			
		||||
import * as IDydx from '../generated-artifacts/IDydx.json';
 | 
			
		||||
import * as IDydxBridge from '../generated-artifacts/IDydxBridge.json';
 | 
			
		||||
import * as IERC20Bridge from '../generated-artifacts/IERC20Bridge.json';
 | 
			
		||||
import * as IEth2Dai from '../generated-artifacts/IEth2Dai.json';
 | 
			
		||||
import * as IGasToken from '../generated-artifacts/IGasToken.json';
 | 
			
		||||
import * as IKyberNetworkProxy from '../generated-artifacts/IKyberNetworkProxy.json';
 | 
			
		||||
import * as IMooniswap from '../generated-artifacts/IMooniswap.json';
 | 
			
		||||
import * as IMStable from '../generated-artifacts/IMStable.json';
 | 
			
		||||
import * as IShell from '../generated-artifacts/IShell.json';
 | 
			
		||||
import * as IUniswapExchange from '../generated-artifacts/IUniswapExchange.json';
 | 
			
		||||
import * as IUniswapExchangeFactory from '../generated-artifacts/IUniswapExchangeFactory.json';
 | 
			
		||||
import * as IUniswapV2Router01 from '../generated-artifacts/IUniswapV2Router01.json';
 | 
			
		||||
import * as KyberBridge from '../generated-artifacts/KyberBridge.json';
 | 
			
		||||
import * as MixinAssetProxyDispatcher from '../generated-artifacts/MixinAssetProxyDispatcher.json';
 | 
			
		||||
import * as MixinAuthorizable from '../generated-artifacts/MixinAuthorizable.json';
 | 
			
		||||
import * as MixinGasToken from '../generated-artifacts/MixinGasToken.json';
 | 
			
		||||
import * as MooniswapBridge from '../generated-artifacts/MooniswapBridge.json';
 | 
			
		||||
import * as MStableBridge from '../generated-artifacts/MStableBridge.json';
 | 
			
		||||
import * as MultiAssetProxy from '../generated-artifacts/MultiAssetProxy.json';
 | 
			
		||||
import * as Ownable from '../generated-artifacts/Ownable.json';
 | 
			
		||||
import * as ShellBridge from '../generated-artifacts/ShellBridge.json';
 | 
			
		||||
import * as SnowSwapBridge from '../generated-artifacts/SnowSwapBridge.json';
 | 
			
		||||
import * as StaticCallProxy from '../generated-artifacts/StaticCallProxy.json';
 | 
			
		||||
import * as SushiSwapBridge from '../generated-artifacts/SushiSwapBridge.json';
 | 
			
		||||
import * as SwerveBridge from '../generated-artifacts/SwerveBridge.json';
 | 
			
		||||
import * as TestBancorBridge from '../generated-artifacts/TestBancorBridge.json';
 | 
			
		||||
import * as TestChaiBridge from '../generated-artifacts/TestChaiBridge.json';
 | 
			
		||||
import * as TestDexForwarderBridge from '../generated-artifacts/TestDexForwarderBridge.json';
 | 
			
		||||
import * as TestDydxBridge from '../generated-artifacts/TestDydxBridge.json';
 | 
			
		||||
import * as TestERC20Bridge from '../generated-artifacts/TestERC20Bridge.json';
 | 
			
		||||
import * as TestEth2DaiBridge from '../generated-artifacts/TestEth2DaiBridge.json';
 | 
			
		||||
import * as TestKyberBridge from '../generated-artifacts/TestKyberBridge.json';
 | 
			
		||||
import * as TestStaticCallTarget from '../generated-artifacts/TestStaticCallTarget.json';
 | 
			
		||||
import * as TestUniswapBridge from '../generated-artifacts/TestUniswapBridge.json';
 | 
			
		||||
import * as TestUniswapV2Bridge from '../generated-artifacts/TestUniswapV2Bridge.json';
 | 
			
		||||
import * as UniswapBridge from '../generated-artifacts/UniswapBridge.json';
 | 
			
		||||
import * as UniswapV2Bridge from '../generated-artifacts/UniswapV2Bridge.json';
 | 
			
		||||
export const artifacts = {
 | 
			
		||||
    MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact,
 | 
			
		||||
    MixinAuthorizable: MixinAuthorizable as ContractArtifact,
 | 
			
		||||
    Ownable: Ownable as ContractArtifact,
 | 
			
		||||
    ERC1155Proxy: ERC1155Proxy as ContractArtifact,
 | 
			
		||||
    ERC20BridgeProxy: ERC20BridgeProxy as ContractArtifact,
 | 
			
		||||
    ERC20Proxy: ERC20Proxy as ContractArtifact,
 | 
			
		||||
    ERC721Proxy: ERC721Proxy as ContractArtifact,
 | 
			
		||||
    MultiAssetProxy: MultiAssetProxy as ContractArtifact,
 | 
			
		||||
    StaticCallProxy: StaticCallProxy as ContractArtifact,
 | 
			
		||||
    BalancerBridge: BalancerBridge as ContractArtifact,
 | 
			
		||||
    BancorBridge: BancorBridge as ContractArtifact,
 | 
			
		||||
    ChaiBridge: ChaiBridge as ContractArtifact,
 | 
			
		||||
    CreamBridge: CreamBridge as ContractArtifact,
 | 
			
		||||
    CryptoComBridge: CryptoComBridge as ContractArtifact,
 | 
			
		||||
    CurveBridge: CurveBridge as ContractArtifact,
 | 
			
		||||
    DODOBridge: DODOBridge as ContractArtifact,
 | 
			
		||||
    DexForwarderBridge: DexForwarderBridge as ContractArtifact,
 | 
			
		||||
    DydxBridge: DydxBridge as ContractArtifact,
 | 
			
		||||
    Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
 | 
			
		||||
    KyberBridge: KyberBridge as ContractArtifact,
 | 
			
		||||
    MStableBridge: MStableBridge as ContractArtifact,
 | 
			
		||||
    MixinGasToken: MixinGasToken as ContractArtifact,
 | 
			
		||||
    MooniswapBridge: MooniswapBridge as ContractArtifact,
 | 
			
		||||
    ShellBridge: ShellBridge as ContractArtifact,
 | 
			
		||||
    SnowSwapBridge: SnowSwapBridge as ContractArtifact,
 | 
			
		||||
    SushiSwapBridge: SushiSwapBridge as ContractArtifact,
 | 
			
		||||
    SwerveBridge: SwerveBridge as ContractArtifact,
 | 
			
		||||
    UniswapBridge: UniswapBridge as ContractArtifact,
 | 
			
		||||
    UniswapV2Bridge: UniswapV2Bridge as ContractArtifact,
 | 
			
		||||
    IAssetData: IAssetData as ContractArtifact,
 | 
			
		||||
    IAssetProxy: IAssetProxy as ContractArtifact,
 | 
			
		||||
    IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
 | 
			
		||||
    IAuthorizable: IAuthorizable as ContractArtifact,
 | 
			
		||||
    IBalancerPool: IBalancerPool as ContractArtifact,
 | 
			
		||||
    IBancorNetwork: IBancorNetwork as ContractArtifact,
 | 
			
		||||
    IChai: IChai as ContractArtifact,
 | 
			
		||||
    ICurve: ICurve as ContractArtifact,
 | 
			
		||||
    IDydx: IDydx as ContractArtifact,
 | 
			
		||||
    IDydxBridge: IDydxBridge as ContractArtifact,
 | 
			
		||||
    IERC20Bridge: IERC20Bridge as ContractArtifact,
 | 
			
		||||
    IEth2Dai: IEth2Dai as ContractArtifact,
 | 
			
		||||
    IGasToken: IGasToken as ContractArtifact,
 | 
			
		||||
    IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact,
 | 
			
		||||
    IMStable: IMStable as ContractArtifact,
 | 
			
		||||
    IMooniswap: IMooniswap as ContractArtifact,
 | 
			
		||||
    IShell: IShell as ContractArtifact,
 | 
			
		||||
    IUniswapExchange: IUniswapExchange as ContractArtifact,
 | 
			
		||||
    IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact,
 | 
			
		||||
    IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact,
 | 
			
		||||
    TestBancorBridge: TestBancorBridge as ContractArtifact,
 | 
			
		||||
    TestChaiBridge: TestChaiBridge as ContractArtifact,
 | 
			
		||||
    TestDexForwarderBridge: TestDexForwarderBridge as ContractArtifact,
 | 
			
		||||
    TestDydxBridge: TestDydxBridge as ContractArtifact,
 | 
			
		||||
    TestERC20Bridge: TestERC20Bridge as ContractArtifact,
 | 
			
		||||
    TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact,
 | 
			
		||||
    TestKyberBridge: TestKyberBridge as ContractArtifact,
 | 
			
		||||
    TestStaticCallTarget: TestStaticCallTarget as ContractArtifact,
 | 
			
		||||
    TestUniswapBridge: TestUniswapBridge as ContractArtifact,
 | 
			
		||||
    TestUniswapV2Bridge: TestUniswapV2Bridge as ContractArtifact,
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										112
									
								
								contracts/asset-proxy/src/asset_data.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								contracts/asset-proxy/src/asset_data.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,112 @@
 | 
			
		||||
import { AssetProxyId } from '@0x/types';
 | 
			
		||||
import { BigNumber, hexUtils } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
import { IAssetDataContract } from './wrappers';
 | 
			
		||||
 | 
			
		||||
const assetDataIface = new IAssetDataContract('0x0000000000000000000000000000000000000000', { isEIP1193: true } as any);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get the proxy ID from encoded asset data.
 | 
			
		||||
 */
 | 
			
		||||
export function getAssetDataProxyId(encoded: string): AssetProxyId {
 | 
			
		||||
    // tslint:disable-next-line: no-unnecessary-type-assertion
 | 
			
		||||
    return hexUtils.slice(encoded, 0, 4) as AssetProxyId;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Decode ERC20 asset data.
 | 
			
		||||
 */
 | 
			
		||||
export function decodeERC20AssetData(encoded: string): string {
 | 
			
		||||
    return assetDataIface.getABIDecodedTransactionData<string>('ERC20Token', encoded);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Decode ERC721 asset data.
 | 
			
		||||
 */
 | 
			
		||||
export function decodeERC721AssetData(encoded: string): [string, BigNumber] {
 | 
			
		||||
    return assetDataIface.getABIDecodedTransactionData<[string, BigNumber]>('ERC721Token', encoded);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Decode ERC1155 asset data.
 | 
			
		||||
 */
 | 
			
		||||
export function decodeERC1155AssetData(encoded: string): [string, BigNumber[], BigNumber[], string] {
 | 
			
		||||
    return assetDataIface.getABIDecodedTransactionData<[string, BigNumber[], BigNumber[], string]>(
 | 
			
		||||
        'ERC1155Assets',
 | 
			
		||||
        encoded,
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Decode MultiAsset asset data.
 | 
			
		||||
 */
 | 
			
		||||
export function decodeMultiAssetData(encoded: string): [BigNumber[], string[]] {
 | 
			
		||||
    return assetDataIface.getABIDecodedTransactionData<[BigNumber[], string[]]>('MultiAsset', encoded);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Decode StaticCall asset data.
 | 
			
		||||
 */
 | 
			
		||||
export function decodeStaticCallAssetData(encoded: string): [string, string, string] {
 | 
			
		||||
    return assetDataIface.getABIDecodedTransactionData<[string, string, string]>('StaticCall', encoded);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Decode ERC20Bridge asset data.
 | 
			
		||||
 */
 | 
			
		||||
export function decodeERC20BridgeAssetData(encoded: string): [string, string, string] {
 | 
			
		||||
    return assetDataIface.getABIDecodedTransactionData<[string, string, string]>('ERC20Bridge', encoded);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Encode ERC20 asset data.
 | 
			
		||||
 */
 | 
			
		||||
export function encodeERC20AssetData(tokenAddress: string): string {
 | 
			
		||||
    return assetDataIface.ERC20Token(tokenAddress).getABIEncodedTransactionData();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Encode ERC721 asset data.
 | 
			
		||||
 */
 | 
			
		||||
export function encodeERC721AssetData(tokenAddress: string, tokenId: BigNumber): string {
 | 
			
		||||
    return assetDataIface.ERC721Token(tokenAddress, tokenId).getABIEncodedTransactionData();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Encode ERC1155 asset data.
 | 
			
		||||
 */
 | 
			
		||||
export function encodeERC1155AssetData(
 | 
			
		||||
    tokenAddress: string,
 | 
			
		||||
    tokenIds: BigNumber[],
 | 
			
		||||
    values: BigNumber[],
 | 
			
		||||
    callbackData: string,
 | 
			
		||||
): string {
 | 
			
		||||
    return assetDataIface.ERC1155Assets(tokenAddress, tokenIds, values, callbackData).getABIEncodedTransactionData();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Encode MultiAsset asset data.
 | 
			
		||||
 */
 | 
			
		||||
export function encodeMultiAssetData(values: BigNumber[], nestedAssetData: string[]): string {
 | 
			
		||||
    return assetDataIface.MultiAsset(values, nestedAssetData).getABIEncodedTransactionData();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Encode StaticCall asset data.
 | 
			
		||||
 */
 | 
			
		||||
export function encodeStaticCallAssetData(
 | 
			
		||||
    staticCallTargetAddress: string,
 | 
			
		||||
    staticCallData: string,
 | 
			
		||||
    expectedReturnDataHash: string,
 | 
			
		||||
): string {
 | 
			
		||||
    return assetDataIface
 | 
			
		||||
        .StaticCall(staticCallTargetAddress, staticCallData, expectedReturnDataHash)
 | 
			
		||||
        .getABIEncodedTransactionData();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Encode ERC20Bridge asset data.
 | 
			
		||||
 */
 | 
			
		||||
export function encodeERC20BridgeAssetData(tokenAddress: string, bridgeAddress: string, bridgeData: string): string {
 | 
			
		||||
    return assetDataIface.ERC20Bridge(tokenAddress, bridgeAddress, bridgeData).getABIEncodedTransactionData();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								contracts/asset-proxy/src/dex_forwarder_bridge.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								contracts/asset-proxy/src/dex_forwarder_bridge.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
import { AbiEncoder, BigNumber } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
export interface DexForwarderBridgeCall {
 | 
			
		||||
    target: string;
 | 
			
		||||
    inputTokenAmount: BigNumber;
 | 
			
		||||
    outputTokenAmount: BigNumber;
 | 
			
		||||
    bridgeData: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface DexForwaderBridgeData {
 | 
			
		||||
    inputToken: string;
 | 
			
		||||
    calls: DexForwarderBridgeCall[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const dexForwarderBridgeDataEncoder = AbiEncoder.create([
 | 
			
		||||
    { name: 'inputToken', type: 'address' },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'calls',
 | 
			
		||||
        type: 'tuple[]',
 | 
			
		||||
        components: [
 | 
			
		||||
            { name: 'target', type: 'address' },
 | 
			
		||||
            { name: 'inputTokenAmount', type: 'uint256' },
 | 
			
		||||
            { name: 'outputTokenAmount', type: 'uint256' },
 | 
			
		||||
            { name: 'bridgeData', type: 'bytes' },
 | 
			
		||||
        ],
 | 
			
		||||
    },
 | 
			
		||||
]);
 | 
			
		||||
							
								
								
									
										40
									
								
								contracts/asset-proxy/src/dydx_bridge_encoder.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								contracts/asset-proxy/src/dydx_bridge_encoder.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
import { AbiEncoder, BigNumber } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
export enum DydxBridgeActionType {
 | 
			
		||||
    Deposit,
 | 
			
		||||
    Withdraw,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface DydxBridgeAction {
 | 
			
		||||
    actionType: DydxBridgeActionType;
 | 
			
		||||
    accountIdx: BigNumber;
 | 
			
		||||
    marketId: BigNumber;
 | 
			
		||||
    conversionRateNumerator: BigNumber;
 | 
			
		||||
    conversionRateDenominator: BigNumber;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface DydxBridgeData {
 | 
			
		||||
    accountNumbers: BigNumber[];
 | 
			
		||||
    actions: DydxBridgeAction[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const dydxBridgeDataEncoder = AbiEncoder.create([
 | 
			
		||||
    {
 | 
			
		||||
        name: 'bridgeData',
 | 
			
		||||
        type: 'tuple',
 | 
			
		||||
        components: [
 | 
			
		||||
            { name: 'accountNumbers', type: 'uint256[]' },
 | 
			
		||||
            {
 | 
			
		||||
                name: 'actions',
 | 
			
		||||
                type: 'tuple[]',
 | 
			
		||||
                components: [
 | 
			
		||||
                    { name: 'actionType', type: 'uint8' },
 | 
			
		||||
                    { name: 'accountIdx', type: 'uint256' },
 | 
			
		||||
                    { name: 'marketId', type: 'uint256' },
 | 
			
		||||
                    { name: 'conversionRateNumerator', type: 'uint256' },
 | 
			
		||||
                    { name: 'conversionRateDenominator', type: 'uint256' },
 | 
			
		||||
                ],
 | 
			
		||||
            },
 | 
			
		||||
        ],
 | 
			
		||||
    },
 | 
			
		||||
]);
 | 
			
		||||
							
								
								
									
										410
									
								
								contracts/asset-proxy/src/erc1155_proxy_wrapper.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										410
									
								
								contracts/asset-proxy/src/erc1155_proxy_wrapper.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,410 @@
 | 
			
		||||
import { artifacts as erc1155Artifacts, ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155';
 | 
			
		||||
import {
 | 
			
		||||
    constants,
 | 
			
		||||
    ERC1155FungibleHoldingsByOwner,
 | 
			
		||||
    ERC1155HoldingsByOwner,
 | 
			
		||||
    ERC1155NonFungibleHoldingsByOwner,
 | 
			
		||||
    LogDecoder,
 | 
			
		||||
    txDefaults,
 | 
			
		||||
} from '@0x/contracts-test-utils';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
import { Web3Wrapper } from '@0x/web3-wrapper';
 | 
			
		||||
import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
import { artifacts } from './artifacts';
 | 
			
		||||
 | 
			
		||||
import { ERC1155ProxyContract, IAssetDataContract, IAssetProxyContract } from './wrappers';
 | 
			
		||||
 | 
			
		||||
export class ERC1155ProxyWrapper {
 | 
			
		||||
    private readonly _tokenOwnerAddresses: string[];
 | 
			
		||||
    private readonly _fungibleTokenIds: string[];
 | 
			
		||||
    private readonly _nonFungibleTokenIds: string[];
 | 
			
		||||
    private readonly _nfts: Array<{ id: BigNumber; tokenId: BigNumber }>;
 | 
			
		||||
    private readonly _contractOwnerAddress: string;
 | 
			
		||||
    private readonly _web3Wrapper: Web3Wrapper;
 | 
			
		||||
    private readonly _provider: Provider;
 | 
			
		||||
    private readonly _logDecoder: LogDecoder;
 | 
			
		||||
    private readonly _dummyTokenWrappers: Erc1155Wrapper[];
 | 
			
		||||
    private readonly _assetProxyInterface: IAssetProxyContract;
 | 
			
		||||
    private readonly _assetDataInterface: IAssetDataContract;
 | 
			
		||||
    private _proxyContract?: ERC1155ProxyContract;
 | 
			
		||||
    private _proxyIdIfExists?: string;
 | 
			
		||||
    private _initialTokenIdsByOwner: ERC1155HoldingsByOwner = { fungible: {}, nonFungible: {} };
 | 
			
		||||
 | 
			
		||||
    constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) {
 | 
			
		||||
        this._web3Wrapper = new Web3Wrapper(provider);
 | 
			
		||||
        this._provider = provider;
 | 
			
		||||
        const allArtifacts = _.merge(artifacts, erc1155Artifacts);
 | 
			
		||||
        this._logDecoder = new LogDecoder(this._web3Wrapper, allArtifacts);
 | 
			
		||||
        this._dummyTokenWrappers = [];
 | 
			
		||||
        this._assetProxyInterface = new IAssetProxyContract(constants.NULL_ADDRESS, provider);
 | 
			
		||||
        this._assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider);
 | 
			
		||||
        this._tokenOwnerAddresses = tokenOwnerAddresses;
 | 
			
		||||
        this._contractOwnerAddress = contractOwnerAddress;
 | 
			
		||||
        this._fungibleTokenIds = [];
 | 
			
		||||
        this._nonFungibleTokenIds = [];
 | 
			
		||||
        this._nfts = [];
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Deploys dummy ERC1155 contracts
 | 
			
		||||
     * @return An array of ERC1155 wrappers; one for each deployed contract.
 | 
			
		||||
     */
 | 
			
		||||
    public async deployDummyContractsAsync(): Promise<Erc1155Wrapper[]> {
 | 
			
		||||
        // tslint:disable-next-line:no-unused-variable
 | 
			
		||||
        for (const i of _.times(constants.NUM_DUMMY_ERC1155_CONTRACTS_TO_DEPLOY)) {
 | 
			
		||||
            const erc1155Contract = await ERC1155MintableContract.deployFrom0xArtifactAsync(
 | 
			
		||||
                erc1155Artifacts.ERC1155Mintable,
 | 
			
		||||
                this._provider,
 | 
			
		||||
                txDefaults,
 | 
			
		||||
                artifacts,
 | 
			
		||||
            );
 | 
			
		||||
            const erc1155Wrapper = new Erc1155Wrapper(erc1155Contract, this._contractOwnerAddress);
 | 
			
		||||
            this._dummyTokenWrappers.push(erc1155Wrapper);
 | 
			
		||||
        }
 | 
			
		||||
        return this._dummyTokenWrappers;
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Deploys the ERC1155 proxy
 | 
			
		||||
     * @return Deployed ERC1155 proxy contract instance
 | 
			
		||||
     */
 | 
			
		||||
    public async deployProxyAsync(): Promise<ERC1155ProxyContract> {
 | 
			
		||||
        this._proxyContract = await ERC1155ProxyContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.ERC1155Proxy,
 | 
			
		||||
            this._provider,
 | 
			
		||||
            txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
        this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync();
 | 
			
		||||
        return this._proxyContract;
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Gets the ERC1155 proxy id
 | 
			
		||||
     */
 | 
			
		||||
    public getProxyId(): string {
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        return this._proxyIdIfExists as string;
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev generates abi-encoded tx data for transferring erc1155 fungible/non-fungible tokens.
 | 
			
		||||
     * @param from source address
 | 
			
		||||
     * @param to destination address
 | 
			
		||||
     * @param contractAddress address of erc155 contract
 | 
			
		||||
     * @param tokensToTransfer array of erc1155 tokens to transfer
 | 
			
		||||
     * @param valuesToTransfer array of corresponding values for each erc1155 token to transfer
 | 
			
		||||
     * @param valueMultiplier each value in `valuesToTransfer` is multiplied by this
 | 
			
		||||
     * @param receiverCallbackData callback data if `to` is a contract
 | 
			
		||||
     * @param authorizedSender sender of `transferFrom` transaction
 | 
			
		||||
     * @param extraData extra data to append to `transferFrom` transaction. Optional.
 | 
			
		||||
     * @return abi encoded tx data.
 | 
			
		||||
     */
 | 
			
		||||
    public async getTransferFromAbiEncodedTxDataAsync(
 | 
			
		||||
        from: string,
 | 
			
		||||
        to: string,
 | 
			
		||||
        contractAddress: string,
 | 
			
		||||
        tokensToTransfer: BigNumber[],
 | 
			
		||||
        valuesToTransfer: BigNumber[],
 | 
			
		||||
        valueMultiplier: BigNumber,
 | 
			
		||||
        receiverCallbackData: string,
 | 
			
		||||
        authorizedSender: string,
 | 
			
		||||
        assetData_?: string,
 | 
			
		||||
    ): Promise<string> {
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        const assetData =
 | 
			
		||||
            assetData_ === undefined
 | 
			
		||||
                ? this._assetDataInterface
 | 
			
		||||
                      .ERC1155Assets(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
 | 
			
		||||
                      .getABIEncodedTransactionData()
 | 
			
		||||
                : assetData_;
 | 
			
		||||
        const data = this._assetProxyInterface
 | 
			
		||||
            .transferFrom(assetData, from, to, valueMultiplier)
 | 
			
		||||
            .getABIEncodedTransactionData();
 | 
			
		||||
        return data;
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev transfers erc1155 fungible/non-fungible tokens.
 | 
			
		||||
     * @param txData: abi-encoded tx data
 | 
			
		||||
     * @param authorizedSender sender of `transferFrom` transaction
 | 
			
		||||
     */
 | 
			
		||||
    public async transferFromRawAsync(
 | 
			
		||||
        txData: string,
 | 
			
		||||
        authorizedSender: string,
 | 
			
		||||
    ): Promise<TransactionReceiptWithDecodedLogs> {
 | 
			
		||||
        const txHash = await this._web3Wrapper.sendTransactionAsync({
 | 
			
		||||
            to: (this._proxyContract as ERC1155ProxyContract).address,
 | 
			
		||||
            data: txData,
 | 
			
		||||
            from: authorizedSender,
 | 
			
		||||
            gas: 300000,
 | 
			
		||||
        });
 | 
			
		||||
        const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
 | 
			
		||||
        return txReceipt;
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev transfers erc1155 fungible/non-fungible tokens.
 | 
			
		||||
     * @param from source address
 | 
			
		||||
     * @param to destination address
 | 
			
		||||
     * @param contractAddress address of erc155 contract
 | 
			
		||||
     * @param tokensToTransfer array of erc1155 tokens to transfer
 | 
			
		||||
     * @param valuesToTransfer array of corresponding values for each erc1155 token to transfer
 | 
			
		||||
     * @param valueMultiplier each value in `valuesToTransfer` is multiplied by this
 | 
			
		||||
     * @param receiverCallbackData callback data if `to` is a contract
 | 
			
		||||
     * @param authorizedSender sender of `transferFrom` transaction
 | 
			
		||||
     * @param extraData extra data to append to `transferFrom` transaction. Optional.
 | 
			
		||||
     * @return tranasction hash.
 | 
			
		||||
     */
 | 
			
		||||
    public async transferFromAsync(
 | 
			
		||||
        from: string,
 | 
			
		||||
        to: string,
 | 
			
		||||
        contractAddress: string,
 | 
			
		||||
        tokensToTransfer: BigNumber[],
 | 
			
		||||
        valuesToTransfer: BigNumber[],
 | 
			
		||||
        valueMultiplier: BigNumber,
 | 
			
		||||
        receiverCallbackData: string,
 | 
			
		||||
        authorizedSender: string,
 | 
			
		||||
        assetData_?: string,
 | 
			
		||||
    ): Promise<TransactionReceiptWithDecodedLogs> {
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        const assetData =
 | 
			
		||||
            assetData_ === undefined
 | 
			
		||||
                ? this._assetDataInterface
 | 
			
		||||
                      .ERC1155Assets(contractAddress, tokensToTransfer, valuesToTransfer, receiverCallbackData)
 | 
			
		||||
                      .getABIEncodedTransactionData()
 | 
			
		||||
                : assetData_;
 | 
			
		||||
        const data = this._assetProxyInterface
 | 
			
		||||
            .transferFrom(assetData, from, to, valueMultiplier)
 | 
			
		||||
            .getABIEncodedTransactionData();
 | 
			
		||||
        const txHash = await this._web3Wrapper.sendTransactionAsync({
 | 
			
		||||
            to: (this._proxyContract as ERC1155ProxyContract).address,
 | 
			
		||||
            data,
 | 
			
		||||
            from: authorizedSender,
 | 
			
		||||
            gas: 300000,
 | 
			
		||||
        });
 | 
			
		||||
        const txReceipt = await this._logDecoder.getTxWithDecodedLogsAsync(txHash);
 | 
			
		||||
        return txReceipt;
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev For each deployed ERC1155 contract, this function mints a set of fungible/non-fungible
 | 
			
		||||
     *      tokens for each token owner address (`_tokenOwnerAddresses`).
 | 
			
		||||
     * @return Balances of each token owner, across all ERC1155 contracts and tokens.
 | 
			
		||||
     */
 | 
			
		||||
    public async setBalancesAndAllowancesAsync(): Promise<ERC1155HoldingsByOwner> {
 | 
			
		||||
        this._validateDummyTokenContractsExistOrThrow();
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        this._initialTokenIdsByOwner = {
 | 
			
		||||
            fungible: {},
 | 
			
		||||
            nonFungible: {},
 | 
			
		||||
        };
 | 
			
		||||
        const fungibleHoldingsByOwner: ERC1155FungibleHoldingsByOwner = {};
 | 
			
		||||
        const nonFungibleHoldingsByOwner: ERC1155NonFungibleHoldingsByOwner = {};
 | 
			
		||||
        // Set balances accordingly
 | 
			
		||||
        for (const dummyWrapper of this._dummyTokenWrappers) {
 | 
			
		||||
            const dummyAddress = dummyWrapper.getContract().address;
 | 
			
		||||
            // tslint:disable-next-line:no-unused-variable
 | 
			
		||||
            for (const i of _.times(constants.NUM_ERC1155_FUNGIBLE_TOKENS_MINT)) {
 | 
			
		||||
                // Create a fungible token
 | 
			
		||||
                const tokenId = await dummyWrapper.mintFungibleTokensAsync(
 | 
			
		||||
                    this._tokenOwnerAddresses,
 | 
			
		||||
                    constants.INITIAL_ERC1155_FUNGIBLE_BALANCE,
 | 
			
		||||
                );
 | 
			
		||||
                const tokenIdAsString = tokenId.toString();
 | 
			
		||||
                this._fungibleTokenIds.push(tokenIdAsString);
 | 
			
		||||
                // Mint tokens for each owner for this token
 | 
			
		||||
                for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
 | 
			
		||||
                    // tslint:disable-next-line:no-unused-variable
 | 
			
		||||
                    if (fungibleHoldingsByOwner[tokenOwnerAddress] === undefined) {
 | 
			
		||||
                        fungibleHoldingsByOwner[tokenOwnerAddress] = {};
 | 
			
		||||
                    }
 | 
			
		||||
                    if (fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] === undefined) {
 | 
			
		||||
                        fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] = {};
 | 
			
		||||
                    }
 | 
			
		||||
                    fungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] =
 | 
			
		||||
                        constants.INITIAL_ERC1155_FUNGIBLE_BALANCE;
 | 
			
		||||
                    await dummyWrapper.setApprovalForAllAsync(
 | 
			
		||||
                        tokenOwnerAddress,
 | 
			
		||||
                        (this._proxyContract as ERC1155ProxyContract).address,
 | 
			
		||||
                        true,
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            // Non-fungible tokens
 | 
			
		||||
            // tslint:disable-next-line:no-unused-variable
 | 
			
		||||
            for (const j of _.times(constants.NUM_ERC1155_NONFUNGIBLE_TOKENS_MINT)) {
 | 
			
		||||
                const [tokenId, nftIds] = await dummyWrapper.mintNonFungibleTokensAsync(this._tokenOwnerAddresses);
 | 
			
		||||
                const tokenIdAsString = tokenId.toString();
 | 
			
		||||
                this._nonFungibleTokenIds.push(tokenIdAsString);
 | 
			
		||||
                _.each(this._tokenOwnerAddresses, async (tokenOwnerAddress: string, i: number) => {
 | 
			
		||||
                    if (nonFungibleHoldingsByOwner[tokenOwnerAddress] === undefined) {
 | 
			
		||||
                        nonFungibleHoldingsByOwner[tokenOwnerAddress] = {};
 | 
			
		||||
                    }
 | 
			
		||||
                    if (nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] === undefined) {
 | 
			
		||||
                        nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress] = {};
 | 
			
		||||
                    }
 | 
			
		||||
                    if (nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] === undefined) {
 | 
			
		||||
                        nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString] = [];
 | 
			
		||||
                    }
 | 
			
		||||
                    this._nfts.push({ id: nftIds[i], tokenId });
 | 
			
		||||
                    nonFungibleHoldingsByOwner[tokenOwnerAddress][dummyAddress][tokenIdAsString].push(nftIds[i]);
 | 
			
		||||
                    await dummyWrapper.setApprovalForAllAsync(
 | 
			
		||||
                        tokenOwnerAddress,
 | 
			
		||||
                        (this._proxyContract as ERC1155ProxyContract).address,
 | 
			
		||||
                        true,
 | 
			
		||||
                    );
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        this._initialTokenIdsByOwner = {
 | 
			
		||||
            fungible: fungibleHoldingsByOwner,
 | 
			
		||||
            nonFungible: nonFungibleHoldingsByOwner,
 | 
			
		||||
        };
 | 
			
		||||
        return this._initialTokenIdsByOwner;
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev For each deployed ERC1155 contract, this function quieries the set of fungible/non-fungible
 | 
			
		||||
     *      tokens for each token owner address (`_tokenOwnerAddresses`).
 | 
			
		||||
     * @return Balances of each token owner, across all ERC1155 contracts and tokens.
 | 
			
		||||
     */
 | 
			
		||||
    public async getBalancesAsync(): Promise<ERC1155HoldingsByOwner> {
 | 
			
		||||
        this._validateDummyTokenContractsExistOrThrow();
 | 
			
		||||
        this._validateBalancesAndAllowancesSetOrThrow();
 | 
			
		||||
        const tokenHoldingsByOwner: ERC1155FungibleHoldingsByOwner = {};
 | 
			
		||||
        const nonFungibleHoldingsByOwner: ERC1155NonFungibleHoldingsByOwner = {};
 | 
			
		||||
        for (const dummyTokenWrapper of this._dummyTokenWrappers) {
 | 
			
		||||
            const tokenContract = dummyTokenWrapper.getContract();
 | 
			
		||||
            const tokenAddress = tokenContract.address;
 | 
			
		||||
            // Construct batch balance call
 | 
			
		||||
            const tokenOwners: string[] = [];
 | 
			
		||||
            const tokenIds: BigNumber[] = [];
 | 
			
		||||
            for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
 | 
			
		||||
                for (const tokenId of this._fungibleTokenIds) {
 | 
			
		||||
                    tokenOwners.push(tokenOwnerAddress);
 | 
			
		||||
                    tokenIds.push(new BigNumber(tokenId));
 | 
			
		||||
                }
 | 
			
		||||
                for (const nft of this._nfts) {
 | 
			
		||||
                    tokenOwners.push(tokenOwnerAddress);
 | 
			
		||||
                    tokenIds.push(nft.id);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            const balances = await dummyTokenWrapper.getBalancesAsync(tokenOwners, tokenIds);
 | 
			
		||||
            // Parse out balances into fungible / non-fungible token holdings
 | 
			
		||||
            let i = 0;
 | 
			
		||||
            for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
 | 
			
		||||
                // Fungible tokens
 | 
			
		||||
                for (const tokenId of this._fungibleTokenIds) {
 | 
			
		||||
                    if (tokenHoldingsByOwner[tokenOwnerAddress] === undefined) {
 | 
			
		||||
                        tokenHoldingsByOwner[tokenOwnerAddress] = {};
 | 
			
		||||
                    }
 | 
			
		||||
                    if (tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress] === undefined) {
 | 
			
		||||
                        tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress] = {};
 | 
			
		||||
                    }
 | 
			
		||||
                    tokenHoldingsByOwner[tokenOwnerAddress][tokenAddress][tokenId] = balances[i++];
 | 
			
		||||
                }
 | 
			
		||||
                // Non-fungible tokens
 | 
			
		||||
                for (const nft of this._nfts) {
 | 
			
		||||
                    if (nonFungibleHoldingsByOwner[tokenOwnerAddress] === undefined) {
 | 
			
		||||
                        nonFungibleHoldingsByOwner[tokenOwnerAddress] = {};
 | 
			
		||||
                    }
 | 
			
		||||
                    if (nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress] === undefined) {
 | 
			
		||||
                        nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress] = {};
 | 
			
		||||
                    }
 | 
			
		||||
                    if (
 | 
			
		||||
                        nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()] ===
 | 
			
		||||
                        undefined
 | 
			
		||||
                    ) {
 | 
			
		||||
                        nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()] = [];
 | 
			
		||||
                    }
 | 
			
		||||
                    const isOwner = balances[i++];
 | 
			
		||||
                    if (isOwner.isEqualTo(1)) {
 | 
			
		||||
                        nonFungibleHoldingsByOwner[tokenOwnerAddress][tokenAddress][nft.tokenId.toString()].push(
 | 
			
		||||
                            nft.id,
 | 
			
		||||
                        );
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        const holdingsByOwner = {
 | 
			
		||||
            fungible: tokenHoldingsByOwner,
 | 
			
		||||
            nonFungible: nonFungibleHoldingsByOwner,
 | 
			
		||||
        };
 | 
			
		||||
        return holdingsByOwner;
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Set the approval for the proxy on behalf of `userAddress` .
 | 
			
		||||
     * @param userAddress owner of ERC1155 tokens.
 | 
			
		||||
     * @param contractAddress address of ERC1155 contract.
 | 
			
		||||
     * @param isApproved Whether to approve the proxy for all or not.
 | 
			
		||||
     */
 | 
			
		||||
    public async setProxyAllowanceForAllAsync(
 | 
			
		||||
        userAddress: string,
 | 
			
		||||
        contractAddress: string,
 | 
			
		||||
        isApproved: boolean,
 | 
			
		||||
    ): Promise<void> {
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        const tokenWrapper = this.getContractWrapper(contractAddress);
 | 
			
		||||
        const operator = (this._proxyContract as ERC1155ProxyContract).address;
 | 
			
		||||
        await tokenWrapper.setApprovalForAllAsync(userAddress, operator, isApproved);
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * @dev Checks if proxy is approved to transfer tokens on behalf of `userAddress`.
 | 
			
		||||
     * @param userAddress owner of ERC1155 tokens.
 | 
			
		||||
     * @param contractAddress address of ERC1155 contract.
 | 
			
		||||
     * @return True iff the proxy is approved for all. False otherwise.
 | 
			
		||||
     */
 | 
			
		||||
    public async isProxyApprovedForAllAsync(userAddress: string, contractAddress: string): Promise<boolean> {
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        const tokenContract = this._getContractFromAddress(contractAddress);
 | 
			
		||||
        const operator = (this._proxyContract as ERC1155ProxyContract).address;
 | 
			
		||||
        const didApproveAll = await tokenContract.isApprovedForAll(userAddress, operator).callAsync();
 | 
			
		||||
        return didApproveAll;
 | 
			
		||||
    }
 | 
			
		||||
    public getFungibleTokenIds(): BigNumber[] {
 | 
			
		||||
        const fungibleTokenIds = _.map(this._fungibleTokenIds, (tokenIdAsString: string) => {
 | 
			
		||||
            return new BigNumber(tokenIdAsString);
 | 
			
		||||
        });
 | 
			
		||||
        return fungibleTokenIds;
 | 
			
		||||
    }
 | 
			
		||||
    public getNonFungibleTokenIds(): BigNumber[] {
 | 
			
		||||
        const nonFungibleTokenIds = _.map(this._nonFungibleTokenIds, (tokenIdAsString: string) => {
 | 
			
		||||
            return new BigNumber(tokenIdAsString);
 | 
			
		||||
        });
 | 
			
		||||
        return nonFungibleTokenIds;
 | 
			
		||||
    }
 | 
			
		||||
    public getTokenOwnerAddresses(): string[] {
 | 
			
		||||
        return this._tokenOwnerAddresses;
 | 
			
		||||
    }
 | 
			
		||||
    public getContractWrapper(contractAddress: string): Erc1155Wrapper {
 | 
			
		||||
        const tokenWrapper = _.find(this._dummyTokenWrappers, (wrapper: Erc1155Wrapper) => {
 | 
			
		||||
            return wrapper.getContract().address === contractAddress;
 | 
			
		||||
        });
 | 
			
		||||
        if (tokenWrapper === undefined) {
 | 
			
		||||
            throw new Error(`Contract: ${contractAddress} was not deployed through ERC1155ProxyWrapper`);
 | 
			
		||||
        }
 | 
			
		||||
        return tokenWrapper;
 | 
			
		||||
    }
 | 
			
		||||
    private _getContractFromAddress(tokenAddress: string): ERC1155MintableContract {
 | 
			
		||||
        const tokenContractIfExists = _.find(this._dummyTokenWrappers, c => c.getContract().address === tokenAddress);
 | 
			
		||||
        if (tokenContractIfExists === undefined) {
 | 
			
		||||
            throw new Error(`Token: ${tokenAddress} was not deployed through ERC1155ProxyWrapper`);
 | 
			
		||||
        }
 | 
			
		||||
        return tokenContractIfExists.getContract();
 | 
			
		||||
    }
 | 
			
		||||
    private _validateDummyTokenContractsExistOrThrow(): void {
 | 
			
		||||
        if (this._dummyTokenWrappers === undefined) {
 | 
			
		||||
            throw new Error('Dummy ERC1155 tokens not yet deployed, please call "deployDummyTokensAsync"');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    private _validateProxyContractExistsOrThrow(): void {
 | 
			
		||||
        if (this._proxyContract === undefined) {
 | 
			
		||||
            throw new Error('ERC1155 proxy contract not yet deployed, please call "deployProxyAsync"');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    private _validateBalancesAndAllowancesSetOrThrow(): void {
 | 
			
		||||
        if (
 | 
			
		||||
            _.keys(this._initialTokenIdsByOwner.fungible).length === 0 ||
 | 
			
		||||
            _.keys(this._initialTokenIdsByOwner.nonFungible).length === 0
 | 
			
		||||
        ) {
 | 
			
		||||
            throw new Error(
 | 
			
		||||
                'Dummy ERC1155 balances and allowances not yet set, please call "setBalancesAndAllowancesAsync"',
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										164
									
								
								contracts/asset-proxy/src/erc20_wrapper.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								contracts/asset-proxy/src/erc20_wrapper.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,164 @@
 | 
			
		||||
import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20';
 | 
			
		||||
import { constants, ERC20BalancesByOwner, txDefaults } from '@0x/contracts-test-utils';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
import { ZeroExProvider } from 'ethereum-types';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
import { artifacts } from './artifacts';
 | 
			
		||||
 | 
			
		||||
import { ERC20ProxyContract, IAssetDataContract } from './wrappers';
 | 
			
		||||
 | 
			
		||||
export class ERC20Wrapper {
 | 
			
		||||
    private readonly _tokenOwnerAddresses: string[];
 | 
			
		||||
    private readonly _contractOwnerAddress: string;
 | 
			
		||||
    private readonly _provider: ZeroExProvider;
 | 
			
		||||
    private readonly _dummyTokenContracts: DummyERC20TokenContract[];
 | 
			
		||||
    private readonly _assetDataInterface: IAssetDataContract;
 | 
			
		||||
    private _proxyContract?: ERC20ProxyContract;
 | 
			
		||||
    private _proxyIdIfExists?: string;
 | 
			
		||||
    /**
 | 
			
		||||
     * Instanitates an ERC20Wrapper
 | 
			
		||||
     * @param provider Web3 provider to use for all JSON RPC requests
 | 
			
		||||
     * @param tokenOwnerAddresses Addresses that we want to endow as owners for dummy ERC20 tokens
 | 
			
		||||
     * @param contractOwnerAddress Desired owner of the contract
 | 
			
		||||
     * Instance of ERC20Wrapper
 | 
			
		||||
     */
 | 
			
		||||
    constructor(provider: ZeroExProvider, tokenOwnerAddresses: string[], contractOwnerAddress: string) {
 | 
			
		||||
        this._dummyTokenContracts = [];
 | 
			
		||||
        this._provider = provider;
 | 
			
		||||
        this._tokenOwnerAddresses = tokenOwnerAddresses;
 | 
			
		||||
        this._contractOwnerAddress = contractOwnerAddress;
 | 
			
		||||
        this._assetDataInterface = new IAssetDataContract(constants.NULL_ADDRESS, provider);
 | 
			
		||||
    }
 | 
			
		||||
    public async deployDummyTokensAsync(
 | 
			
		||||
        numberToDeploy: number,
 | 
			
		||||
        decimals: BigNumber,
 | 
			
		||||
    ): Promise<DummyERC20TokenContract[]> {
 | 
			
		||||
        for (let i = 0; i < numberToDeploy; i++) {
 | 
			
		||||
            this._dummyTokenContracts.push(
 | 
			
		||||
                await DummyERC20TokenContract.deployFrom0xArtifactAsync(
 | 
			
		||||
                    erc20Artifacts.DummyERC20Token,
 | 
			
		||||
                    this._provider,
 | 
			
		||||
                    txDefaults,
 | 
			
		||||
                    artifacts,
 | 
			
		||||
                    constants.DUMMY_TOKEN_NAME,
 | 
			
		||||
                    constants.DUMMY_TOKEN_SYMBOL,
 | 
			
		||||
                    decimals,
 | 
			
		||||
                    constants.DUMMY_TOKEN_TOTAL_SUPPLY,
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        return this._dummyTokenContracts;
 | 
			
		||||
    }
 | 
			
		||||
    public async deployProxyAsync(): Promise<ERC20ProxyContract> {
 | 
			
		||||
        this._proxyContract = await ERC20ProxyContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.ERC20Proxy,
 | 
			
		||||
            this._provider,
 | 
			
		||||
            txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
        this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync();
 | 
			
		||||
        return this._proxyContract;
 | 
			
		||||
    }
 | 
			
		||||
    public getProxyId(): string {
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        return this._proxyIdIfExists as string;
 | 
			
		||||
    }
 | 
			
		||||
    public async setBalancesAndAllowancesAsync(): Promise<void> {
 | 
			
		||||
        this._validateDummyTokenContractsExistOrThrow();
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        for (const dummyTokenContract of this._dummyTokenContracts) {
 | 
			
		||||
            for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
 | 
			
		||||
                await dummyTokenContract
 | 
			
		||||
                    .setBalance(tokenOwnerAddress, constants.INITIAL_ERC20_BALANCE)
 | 
			
		||||
                    .awaitTransactionSuccessAsync({ from: this._contractOwnerAddress });
 | 
			
		||||
                await dummyTokenContract
 | 
			
		||||
                    .approve((this._proxyContract as ERC20ProxyContract).address, constants.INITIAL_ERC20_ALLOWANCE)
 | 
			
		||||
                    .awaitTransactionSuccessAsync({ from: tokenOwnerAddress });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    public async getBalanceAsync(userAddress: string, assetData: string): Promise<BigNumber> {
 | 
			
		||||
        const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData);
 | 
			
		||||
        const balance = new BigNumber(await tokenContract.balanceOf(userAddress).callAsync());
 | 
			
		||||
        return balance;
 | 
			
		||||
    }
 | 
			
		||||
    public async setBalanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> {
 | 
			
		||||
        const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData);
 | 
			
		||||
        await tokenContract
 | 
			
		||||
            .setBalance(userAddress, amount)
 | 
			
		||||
            .awaitTransactionSuccessAsync(
 | 
			
		||||
                { from: this._contractOwnerAddress },
 | 
			
		||||
                { pollingIntervalMs: constants.AWAIT_TRANSACTION_MINED_MS },
 | 
			
		||||
            );
 | 
			
		||||
    }
 | 
			
		||||
    public async getProxyAllowanceAsync(userAddress: string, assetData: string): Promise<BigNumber> {
 | 
			
		||||
        const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData);
 | 
			
		||||
        const proxyAddress = (this._proxyContract as ERC20ProxyContract).address;
 | 
			
		||||
        const allowance = new BigNumber(await tokenContract.allowance(userAddress, proxyAddress).callAsync());
 | 
			
		||||
        return allowance;
 | 
			
		||||
    }
 | 
			
		||||
    public async setAllowanceAsync(userAddress: string, assetData: string, amount: BigNumber): Promise<void> {
 | 
			
		||||
        const tokenContract = await this._getTokenContractFromAssetDataAsync(assetData);
 | 
			
		||||
        const proxyAddress = (this._proxyContract as ERC20ProxyContract).address;
 | 
			
		||||
        await tokenContract.approve(proxyAddress, amount).awaitTransactionSuccessAsync({ from: userAddress });
 | 
			
		||||
    }
 | 
			
		||||
    public async getBalancesAsync(): Promise<ERC20BalancesByOwner> {
 | 
			
		||||
        this._validateDummyTokenContractsExistOrThrow();
 | 
			
		||||
        const balancesByOwner: ERC20BalancesByOwner = {};
 | 
			
		||||
        const balances: BigNumber[] = [];
 | 
			
		||||
        const balanceInfo: Array<{ tokenOwnerAddress: string; tokenAddress: string }> = [];
 | 
			
		||||
        for (const dummyTokenContract of this._dummyTokenContracts) {
 | 
			
		||||
            for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
 | 
			
		||||
                balances.push(await dummyTokenContract.balanceOf(tokenOwnerAddress).callAsync());
 | 
			
		||||
                balanceInfo.push({
 | 
			
		||||
                    tokenOwnerAddress,
 | 
			
		||||
                    tokenAddress: dummyTokenContract.address,
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        _.forEach(balances, (balance, balanceIndex) => {
 | 
			
		||||
            const tokenAddress = balanceInfo[balanceIndex].tokenAddress;
 | 
			
		||||
            const tokenOwnerAddress = balanceInfo[balanceIndex].tokenOwnerAddress;
 | 
			
		||||
            if (balancesByOwner[tokenOwnerAddress] === undefined) {
 | 
			
		||||
                balancesByOwner[tokenOwnerAddress] = {};
 | 
			
		||||
            }
 | 
			
		||||
            const wrappedBalance = new BigNumber(balance);
 | 
			
		||||
            balancesByOwner[tokenOwnerAddress][tokenAddress] = wrappedBalance;
 | 
			
		||||
        });
 | 
			
		||||
        return balancesByOwner;
 | 
			
		||||
    }
 | 
			
		||||
    public addDummyTokenContract(dummy: DummyERC20TokenContract): void {
 | 
			
		||||
        if (this._dummyTokenContracts !== undefined) {
 | 
			
		||||
            this._dummyTokenContracts.push(dummy);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    public addTokenOwnerAddress(address: string): void {
 | 
			
		||||
        this._tokenOwnerAddresses.push(address);
 | 
			
		||||
    }
 | 
			
		||||
    public getTokenOwnerAddresses(): string[] {
 | 
			
		||||
        return this._tokenOwnerAddresses;
 | 
			
		||||
    }
 | 
			
		||||
    public getTokenAddresses(): string[] {
 | 
			
		||||
        const tokenAddresses = _.map(this._dummyTokenContracts, dummyTokenContract => dummyTokenContract.address);
 | 
			
		||||
        return tokenAddresses;
 | 
			
		||||
    }
 | 
			
		||||
    private async _getTokenContractFromAssetDataAsync(assetData: string): Promise<DummyERC20TokenContract> {
 | 
			
		||||
        const tokenAddress = this._assetDataInterface.getABIDecodedTransactionData<string>('ERC20Token', assetData); // tslint:disable-line:no-unused-variable
 | 
			
		||||
        const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress);
 | 
			
		||||
        if (tokenContractIfExists === undefined) {
 | 
			
		||||
            throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`);
 | 
			
		||||
        }
 | 
			
		||||
        return tokenContractIfExists;
 | 
			
		||||
    }
 | 
			
		||||
    private _validateDummyTokenContractsExistOrThrow(): void {
 | 
			
		||||
        if (this._dummyTokenContracts === undefined) {
 | 
			
		||||
            throw new Error('Dummy ERC20 tokens not yet deployed, please call "deployDummyTokensAsync"');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    private _validateProxyContractExistsOrThrow(): void {
 | 
			
		||||
        if (this._proxyContract === undefined) {
 | 
			
		||||
            throw new Error('ERC20 proxy contract not yet deployed, please call "deployProxyAsync"');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										220
									
								
								contracts/asset-proxy/src/erc721_wrapper.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								contracts/asset-proxy/src/erc721_wrapper.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,220 @@
 | 
			
		||||
import { artifacts as erc721Artifacts, DummyERC721TokenContract } from '@0x/contracts-erc721';
 | 
			
		||||
import { constants, ERC721TokenIdsByOwner, txDefaults } from '@0x/contracts-test-utils';
 | 
			
		||||
import { generatePseudoRandomSalt } from '@0x/order-utils';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
import { ZeroExProvider } from 'ethereum-types';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
import { artifacts } from './artifacts';
 | 
			
		||||
 | 
			
		||||
import { ERC721ProxyContract } from './wrappers';
 | 
			
		||||
 | 
			
		||||
export class ERC721Wrapper {
 | 
			
		||||
    private readonly _tokenOwnerAddresses: string[];
 | 
			
		||||
    private readonly _contractOwnerAddress: string;
 | 
			
		||||
    private readonly _provider: ZeroExProvider;
 | 
			
		||||
    private readonly _dummyTokenContracts: DummyERC721TokenContract[];
 | 
			
		||||
    private _proxyContract?: ERC721ProxyContract;
 | 
			
		||||
    private _proxyIdIfExists?: string;
 | 
			
		||||
    private _initialTokenIdsByOwner: ERC721TokenIdsByOwner = {};
 | 
			
		||||
    constructor(provider: ZeroExProvider, tokenOwnerAddresses: string[], contractOwnerAddress: string) {
 | 
			
		||||
        this._provider = provider;
 | 
			
		||||
        this._dummyTokenContracts = [];
 | 
			
		||||
        this._tokenOwnerAddresses = tokenOwnerAddresses;
 | 
			
		||||
        this._contractOwnerAddress = contractOwnerAddress;
 | 
			
		||||
    }
 | 
			
		||||
    public async deployDummyTokensAsync(): Promise<DummyERC721TokenContract[]> {
 | 
			
		||||
        // tslint:disable-next-line:no-unused-variable
 | 
			
		||||
        for (const i of _.times(constants.NUM_DUMMY_ERC721_TO_DEPLOY)) {
 | 
			
		||||
            this._dummyTokenContracts.push(
 | 
			
		||||
                await DummyERC721TokenContract.deployFrom0xArtifactAsync(
 | 
			
		||||
                    erc721Artifacts.DummyERC721Token,
 | 
			
		||||
                    this._provider,
 | 
			
		||||
                    txDefaults,
 | 
			
		||||
                    artifacts,
 | 
			
		||||
                    constants.DUMMY_TOKEN_NAME,
 | 
			
		||||
                    constants.DUMMY_TOKEN_SYMBOL,
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        return this._dummyTokenContracts;
 | 
			
		||||
    }
 | 
			
		||||
    public async deployProxyAsync(): Promise<ERC721ProxyContract> {
 | 
			
		||||
        this._proxyContract = await ERC721ProxyContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.ERC721Proxy,
 | 
			
		||||
            this._provider,
 | 
			
		||||
            txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
        this._proxyIdIfExists = await this._proxyContract.getProxyId().callAsync();
 | 
			
		||||
        return this._proxyContract;
 | 
			
		||||
    }
 | 
			
		||||
    public getProxyId(): string {
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        return this._proxyIdIfExists as string;
 | 
			
		||||
    }
 | 
			
		||||
    public async setBalancesAndAllowancesAsync(): Promise<void> {
 | 
			
		||||
        this._validateDummyTokenContractsExistOrThrow();
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        this._initialTokenIdsByOwner = {};
 | 
			
		||||
        for (const dummyTokenContract of this._dummyTokenContracts) {
 | 
			
		||||
            for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
 | 
			
		||||
                // tslint:disable-next-line:no-unused-variable
 | 
			
		||||
                for (const i of _.times(constants.NUM_ERC721_TOKENS_TO_MINT)) {
 | 
			
		||||
                    const tokenId = generatePseudoRandomSalt();
 | 
			
		||||
                    await this.mintAsync(dummyTokenContract.address, tokenId, tokenOwnerAddress);
 | 
			
		||||
                    if (this._initialTokenIdsByOwner[tokenOwnerAddress] === undefined) {
 | 
			
		||||
                        this._initialTokenIdsByOwner[tokenOwnerAddress] = {
 | 
			
		||||
                            [dummyTokenContract.address]: [],
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                    if (this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address] === undefined) {
 | 
			
		||||
                        this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address] = [];
 | 
			
		||||
                    }
 | 
			
		||||
                    this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address].push(tokenId);
 | 
			
		||||
 | 
			
		||||
                    await this.approveProxyForAllAsync(dummyTokenContract.address, tokenOwnerAddress, true);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    public async doesTokenExistAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> {
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
 | 
			
		||||
        const owner = await tokenContract.ownerOf(tokenId).callAsync();
 | 
			
		||||
        const doesExist = owner !== constants.NULL_ADDRESS;
 | 
			
		||||
        return doesExist;
 | 
			
		||||
    }
 | 
			
		||||
    public async approveProxyAsync(tokenAddress: string, tokenId: BigNumber): Promise<void> {
 | 
			
		||||
        const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
 | 
			
		||||
        await this.approveAsync(proxyAddress, tokenAddress, tokenId);
 | 
			
		||||
    }
 | 
			
		||||
    public async approveProxyForAllAsync(
 | 
			
		||||
        tokenAddress: string,
 | 
			
		||||
        ownerAddress: string,
 | 
			
		||||
        isApproved: boolean,
 | 
			
		||||
    ): Promise<void> {
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
 | 
			
		||||
        const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
 | 
			
		||||
        await tokenContract.setApprovalForAll(proxyAddress, isApproved).awaitTransactionSuccessAsync({
 | 
			
		||||
            from: ownerAddress,
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    public async approveAsync(to: string, tokenAddress: string, tokenId: BigNumber): Promise<void> {
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
 | 
			
		||||
        const tokenOwner = await this.ownerOfAsync(tokenAddress, tokenId);
 | 
			
		||||
        await tokenContract.approve(to, tokenId).awaitTransactionSuccessAsync({ from: tokenOwner });
 | 
			
		||||
    }
 | 
			
		||||
    public async transferFromAsync(
 | 
			
		||||
        tokenAddress: string,
 | 
			
		||||
        tokenId: BigNumber,
 | 
			
		||||
        currentOwner: string,
 | 
			
		||||
        userAddress: string,
 | 
			
		||||
    ): Promise<void> {
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
 | 
			
		||||
        await tokenContract.transferFrom(currentOwner, userAddress, tokenId).awaitTransactionSuccessAsync({
 | 
			
		||||
            from: currentOwner,
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    public async mintAsync(tokenAddress: string, tokenId: BigNumber, userAddress: string): Promise<void> {
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
 | 
			
		||||
        await tokenContract.mint(userAddress, tokenId).awaitTransactionSuccessAsync({
 | 
			
		||||
            from: this._contractOwnerAddress,
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    public async burnAsync(tokenAddress: string, tokenId: BigNumber, owner: string): Promise<void> {
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
 | 
			
		||||
        await tokenContract.burn(owner, tokenId).awaitTransactionSuccessAsync({ from: this._contractOwnerAddress });
 | 
			
		||||
    }
 | 
			
		||||
    public async ownerOfAsync(tokenAddress: string, tokenId: BigNumber): Promise<string> {
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
 | 
			
		||||
        const owner = await tokenContract.ownerOf(tokenId).callAsync();
 | 
			
		||||
        return owner;
 | 
			
		||||
    }
 | 
			
		||||
    public async isOwnerAsync(userAddress: string, tokenAddress: string, tokenId: BigNumber): Promise<boolean> {
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
 | 
			
		||||
        const tokenOwner = await tokenContract.ownerOf(tokenId).callAsync();
 | 
			
		||||
        const isOwner = tokenOwner === userAddress;
 | 
			
		||||
        return isOwner;
 | 
			
		||||
    }
 | 
			
		||||
    public async isProxyApprovedForAllAsync(userAddress: string, tokenAddress: string): Promise<boolean> {
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
 | 
			
		||||
        const operator = (this._proxyContract as ERC721ProxyContract).address;
 | 
			
		||||
        const didApproveAll = await tokenContract.isApprovedForAll(userAddress, operator).callAsync();
 | 
			
		||||
        return didApproveAll;
 | 
			
		||||
    }
 | 
			
		||||
    public async isProxyApprovedAsync(tokenAddress: string, tokenId: BigNumber): Promise<boolean> {
 | 
			
		||||
        this._validateProxyContractExistsOrThrow();
 | 
			
		||||
        const tokenContract = this._getTokenContractFromAssetData(tokenAddress);
 | 
			
		||||
        const approvedAddress = await tokenContract.getApproved(tokenId).callAsync();
 | 
			
		||||
        const proxyAddress = (this._proxyContract as ERC721ProxyContract).address;
 | 
			
		||||
        const isProxyAnApprovedOperator = approvedAddress === proxyAddress;
 | 
			
		||||
        return isProxyAnApprovedOperator;
 | 
			
		||||
    }
 | 
			
		||||
    public async getBalancesAsync(): Promise<ERC721TokenIdsByOwner> {
 | 
			
		||||
        this._validateDummyTokenContractsExistOrThrow();
 | 
			
		||||
        this._validateBalancesAndAllowancesSetOrThrow();
 | 
			
		||||
        const tokenIdsByOwner: ERC721TokenIdsByOwner = {};
 | 
			
		||||
        const tokenOwnerAddresses: string[] = [];
 | 
			
		||||
        const tokenInfo: Array<{ tokenId: BigNumber; tokenAddress: string }> = [];
 | 
			
		||||
        for (const dummyTokenContract of this._dummyTokenContracts) {
 | 
			
		||||
            for (const tokenOwnerAddress of this._tokenOwnerAddresses) {
 | 
			
		||||
                const initialTokenOwnerIds = this._initialTokenIdsByOwner[tokenOwnerAddress][
 | 
			
		||||
                    dummyTokenContract.address
 | 
			
		||||
                ];
 | 
			
		||||
                for (const tokenId of initialTokenOwnerIds) {
 | 
			
		||||
                    tokenOwnerAddresses.push(await dummyTokenContract.ownerOf(tokenId).callAsync());
 | 
			
		||||
                    tokenInfo.push({
 | 
			
		||||
                        tokenId,
 | 
			
		||||
                        tokenAddress: dummyTokenContract.address,
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        _.forEach(tokenOwnerAddresses, (tokenOwnerAddress, ownerIndex) => {
 | 
			
		||||
            const tokenAddress = tokenInfo[ownerIndex].tokenAddress;
 | 
			
		||||
            const tokenId = tokenInfo[ownerIndex].tokenId;
 | 
			
		||||
            if (tokenIdsByOwner[tokenOwnerAddress] === undefined) {
 | 
			
		||||
                tokenIdsByOwner[tokenOwnerAddress] = {
 | 
			
		||||
                    [tokenAddress]: [],
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
            if (tokenIdsByOwner[tokenOwnerAddress][tokenAddress] === undefined) {
 | 
			
		||||
                tokenIdsByOwner[tokenOwnerAddress][tokenAddress] = [];
 | 
			
		||||
            }
 | 
			
		||||
            tokenIdsByOwner[tokenOwnerAddress][tokenAddress].push(tokenId);
 | 
			
		||||
        });
 | 
			
		||||
        return tokenIdsByOwner;
 | 
			
		||||
    }
 | 
			
		||||
    public getTokenOwnerAddresses(): string[] {
 | 
			
		||||
        return this._tokenOwnerAddresses;
 | 
			
		||||
    }
 | 
			
		||||
    public getTokenAddresses(): string[] {
 | 
			
		||||
        const tokenAddresses = _.map(this._dummyTokenContracts, dummyTokenContract => dummyTokenContract.address);
 | 
			
		||||
        return tokenAddresses;
 | 
			
		||||
    }
 | 
			
		||||
    private _getTokenContractFromAssetData(tokenAddress: string): DummyERC721TokenContract {
 | 
			
		||||
        const tokenContractIfExists = _.find(this._dummyTokenContracts, c => c.address === tokenAddress);
 | 
			
		||||
        if (tokenContractIfExists === undefined) {
 | 
			
		||||
            throw new Error(`Token: ${tokenAddress} was not deployed through ERC20Wrapper`);
 | 
			
		||||
        }
 | 
			
		||||
        return tokenContractIfExists;
 | 
			
		||||
    }
 | 
			
		||||
    private _validateDummyTokenContractsExistOrThrow(): void {
 | 
			
		||||
        if (this._dummyTokenContracts === undefined) {
 | 
			
		||||
            throw new Error('Dummy ERC721 tokens not yet deployed, please call "deployDummyTokensAsync"');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    private _validateProxyContractExistsOrThrow(): void {
 | 
			
		||||
        if (this._proxyContract === undefined) {
 | 
			
		||||
            throw new Error('ERC721 proxy contract not yet deployed, please call "deployProxyAsync"');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    private _validateBalancesAndAllowancesSetOrThrow(): void {
 | 
			
		||||
        if (_.keys(this._initialTokenIdsByOwner).length === 0) {
 | 
			
		||||
            throw new Error(
 | 
			
		||||
                'Dummy ERC721 balances and allowances not yet set, please call "setBalancesAndAllowancesAsync"',
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										93
									
								
								contracts/asset-proxy/src/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								contracts/asset-proxy/src/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,93 @@
 | 
			
		||||
export { artifacts } from './artifacts';
 | 
			
		||||
export {
 | 
			
		||||
    BalancerBridgeContract,
 | 
			
		||||
    ChaiBridgeContract,
 | 
			
		||||
    ERC1155ProxyContract,
 | 
			
		||||
    ERC20BridgeProxyContract,
 | 
			
		||||
    ERC20ProxyContract,
 | 
			
		||||
    ERC721ProxyContract,
 | 
			
		||||
    Eth2DaiBridgeContract,
 | 
			
		||||
    DydxBridgeContract,
 | 
			
		||||
    IAssetDataContract,
 | 
			
		||||
    IAssetProxyContract,
 | 
			
		||||
    IChaiContract,
 | 
			
		||||
    IDydxContract,
 | 
			
		||||
    KyberBridgeContract,
 | 
			
		||||
    MultiAssetProxyContract,
 | 
			
		||||
    StaticCallProxyContract,
 | 
			
		||||
    TestDydxBridgeContract,
 | 
			
		||||
    TestStaticCallTargetContract,
 | 
			
		||||
    UniswapBridgeContract,
 | 
			
		||||
    DexForwarderBridgeContract,
 | 
			
		||||
} from './wrappers';
 | 
			
		||||
 | 
			
		||||
export { ERC20Wrapper } from './erc20_wrapper';
 | 
			
		||||
export { ERC721Wrapper } from './erc721_wrapper';
 | 
			
		||||
export { ERC1155ProxyWrapper } from './erc1155_proxy_wrapper';
 | 
			
		||||
export { ERC1155MintableContract, Erc1155Wrapper } from '@0x/contracts-erc1155';
 | 
			
		||||
export { DummyERC20TokenContract } from '@0x/contracts-erc20';
 | 
			
		||||
export { DummyERC721TokenContract } from '@0x/contracts-erc721';
 | 
			
		||||
export { AssetProxyId } from '@0x/types';
 | 
			
		||||
export {
 | 
			
		||||
    ERC1155HoldingsByOwner,
 | 
			
		||||
    ERC20BalancesByOwner,
 | 
			
		||||
    ERC721TokenIdsByOwner,
 | 
			
		||||
    ERC1155FungibleHoldingsByOwner,
 | 
			
		||||
    ERC1155NonFungibleHoldingsByOwner,
 | 
			
		||||
} from '@0x/contracts-test-utils';
 | 
			
		||||
export {
 | 
			
		||||
    TransactionReceiptWithDecodedLogs,
 | 
			
		||||
    Provider,
 | 
			
		||||
    ZeroExProvider,
 | 
			
		||||
    JSONRPCRequestPayload,
 | 
			
		||||
    JSONRPCErrorCallback,
 | 
			
		||||
    TransactionReceiptStatus,
 | 
			
		||||
    JSONRPCResponsePayload,
 | 
			
		||||
    JSONRPCResponseError,
 | 
			
		||||
    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';
 | 
			
		||||
 | 
			
		||||
export {
 | 
			
		||||
    decodeERC1155AssetData,
 | 
			
		||||
    decodeERC20AssetData,
 | 
			
		||||
    decodeERC20BridgeAssetData,
 | 
			
		||||
    decodeERC721AssetData,
 | 
			
		||||
    decodeMultiAssetData,
 | 
			
		||||
    decodeStaticCallAssetData,
 | 
			
		||||
    encodeERC1155AssetData,
 | 
			
		||||
    encodeERC20AssetData,
 | 
			
		||||
    encodeERC20BridgeAssetData,
 | 
			
		||||
    encodeERC721AssetData,
 | 
			
		||||
    encodeMultiAssetData,
 | 
			
		||||
    encodeStaticCallAssetData,
 | 
			
		||||
    getAssetDataProxyId,
 | 
			
		||||
} from './asset_data';
 | 
			
		||||
 | 
			
		||||
export * from './dydx_bridge_encoder';
 | 
			
		||||
export * from './dex_forwarder_bridge';
 | 
			
		||||
							
								
								
									
										64
									
								
								contracts/asset-proxy/src/wrappers.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								contracts/asset-proxy/src/wrappers.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
			
		||||
/*
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 * Warning: This file is auto-generated by contracts-gen. Don't edit manually.
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
export * from '../generated-wrappers/balancer_bridge';
 | 
			
		||||
export * from '../generated-wrappers/bancor_bridge';
 | 
			
		||||
export * from '../generated-wrappers/chai_bridge';
 | 
			
		||||
export * from '../generated-wrappers/cream_bridge';
 | 
			
		||||
export * from '../generated-wrappers/crypto_com_bridge';
 | 
			
		||||
export * from '../generated-wrappers/curve_bridge';
 | 
			
		||||
export * from '../generated-wrappers/d_o_d_o_bridge';
 | 
			
		||||
export * from '../generated-wrappers/dex_forwarder_bridge';
 | 
			
		||||
export * from '../generated-wrappers/dydx_bridge';
 | 
			
		||||
export * from '../generated-wrappers/erc1155_proxy';
 | 
			
		||||
export * from '../generated-wrappers/erc20_bridge_proxy';
 | 
			
		||||
export * from '../generated-wrappers/erc20_proxy';
 | 
			
		||||
export * from '../generated-wrappers/erc721_proxy';
 | 
			
		||||
export * from '../generated-wrappers/eth2_dai_bridge';
 | 
			
		||||
export * from '../generated-wrappers/i_asset_data';
 | 
			
		||||
export * from '../generated-wrappers/i_asset_proxy';
 | 
			
		||||
export * from '../generated-wrappers/i_asset_proxy_dispatcher';
 | 
			
		||||
export * from '../generated-wrappers/i_authorizable';
 | 
			
		||||
export * from '../generated-wrappers/i_balancer_pool';
 | 
			
		||||
export * from '../generated-wrappers/i_bancor_network';
 | 
			
		||||
export * from '../generated-wrappers/i_chai';
 | 
			
		||||
export * from '../generated-wrappers/i_curve';
 | 
			
		||||
export * from '../generated-wrappers/i_dydx';
 | 
			
		||||
export * from '../generated-wrappers/i_dydx_bridge';
 | 
			
		||||
export * from '../generated-wrappers/i_erc20_bridge';
 | 
			
		||||
export * from '../generated-wrappers/i_eth2_dai';
 | 
			
		||||
export * from '../generated-wrappers/i_gas_token';
 | 
			
		||||
export * from '../generated-wrappers/i_kyber_network_proxy';
 | 
			
		||||
export * from '../generated-wrappers/i_m_stable';
 | 
			
		||||
export * from '../generated-wrappers/i_mooniswap';
 | 
			
		||||
export * from '../generated-wrappers/i_shell';
 | 
			
		||||
export * from '../generated-wrappers/i_uniswap_exchange';
 | 
			
		||||
export * from '../generated-wrappers/i_uniswap_exchange_factory';
 | 
			
		||||
export * from '../generated-wrappers/i_uniswap_v2_router01';
 | 
			
		||||
export * from '../generated-wrappers/kyber_bridge';
 | 
			
		||||
export * from '../generated-wrappers/m_stable_bridge';
 | 
			
		||||
export * from '../generated-wrappers/mixin_asset_proxy_dispatcher';
 | 
			
		||||
export * from '../generated-wrappers/mixin_authorizable';
 | 
			
		||||
export * from '../generated-wrappers/mixin_gas_token';
 | 
			
		||||
export * from '../generated-wrappers/mooniswap_bridge';
 | 
			
		||||
export * from '../generated-wrappers/multi_asset_proxy';
 | 
			
		||||
export * from '../generated-wrappers/ownable';
 | 
			
		||||
export * from '../generated-wrappers/shell_bridge';
 | 
			
		||||
export * from '../generated-wrappers/snow_swap_bridge';
 | 
			
		||||
export * from '../generated-wrappers/static_call_proxy';
 | 
			
		||||
export * from '../generated-wrappers/sushi_swap_bridge';
 | 
			
		||||
export * from '../generated-wrappers/swerve_bridge';
 | 
			
		||||
export * from '../generated-wrappers/test_bancor_bridge';
 | 
			
		||||
export * from '../generated-wrappers/test_chai_bridge';
 | 
			
		||||
export * from '../generated-wrappers/test_dex_forwarder_bridge';
 | 
			
		||||
export * from '../generated-wrappers/test_dydx_bridge';
 | 
			
		||||
export * from '../generated-wrappers/test_erc20_bridge';
 | 
			
		||||
export * from '../generated-wrappers/test_eth2_dai_bridge';
 | 
			
		||||
export * from '../generated-wrappers/test_kyber_bridge';
 | 
			
		||||
export * from '../generated-wrappers/test_static_call_target';
 | 
			
		||||
export * from '../generated-wrappers/test_uniswap_bridge';
 | 
			
		||||
export * from '../generated-wrappers/test_uniswap_v2_bridge';
 | 
			
		||||
export * from '../generated-wrappers/uniswap_bridge';
 | 
			
		||||
export * from '../generated-wrappers/uniswap_v2_bridge';
 | 
			
		||||
							
								
								
									
										127
									
								
								contracts/asset-proxy/test/artifacts.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								contracts/asset-proxy/test/artifacts.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,127 @@
 | 
			
		||||
/*
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 * Warning: This file is auto-generated by contracts-gen. Don't edit manually.
 | 
			
		||||
 * -----------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
import { ContractArtifact } from 'ethereum-types';
 | 
			
		||||
 | 
			
		||||
import * as BalancerBridge from '../test/generated-artifacts/BalancerBridge.json';
 | 
			
		||||
import * as BancorBridge from '../test/generated-artifacts/BancorBridge.json';
 | 
			
		||||
import * as ChaiBridge from '../test/generated-artifacts/ChaiBridge.json';
 | 
			
		||||
import * as CreamBridge from '../test/generated-artifacts/CreamBridge.json';
 | 
			
		||||
import * as CryptoComBridge from '../test/generated-artifacts/CryptoComBridge.json';
 | 
			
		||||
import * as CurveBridge from '../test/generated-artifacts/CurveBridge.json';
 | 
			
		||||
import * as DexForwarderBridge from '../test/generated-artifacts/DexForwarderBridge.json';
 | 
			
		||||
import * as DODOBridge from '../test/generated-artifacts/DODOBridge.json';
 | 
			
		||||
import * as DydxBridge from '../test/generated-artifacts/DydxBridge.json';
 | 
			
		||||
import * as ERC1155Proxy from '../test/generated-artifacts/ERC1155Proxy.json';
 | 
			
		||||
import * as ERC20BridgeProxy from '../test/generated-artifacts/ERC20BridgeProxy.json';
 | 
			
		||||
import * as ERC20Proxy from '../test/generated-artifacts/ERC20Proxy.json';
 | 
			
		||||
import * as ERC721Proxy from '../test/generated-artifacts/ERC721Proxy.json';
 | 
			
		||||
import * as Eth2DaiBridge from '../test/generated-artifacts/Eth2DaiBridge.json';
 | 
			
		||||
import * as IAssetData from '../test/generated-artifacts/IAssetData.json';
 | 
			
		||||
import * as IAssetProxy from '../test/generated-artifacts/IAssetProxy.json';
 | 
			
		||||
import * as IAssetProxyDispatcher from '../test/generated-artifacts/IAssetProxyDispatcher.json';
 | 
			
		||||
import * as IAuthorizable from '../test/generated-artifacts/IAuthorizable.json';
 | 
			
		||||
import * as IBalancerPool from '../test/generated-artifacts/IBalancerPool.json';
 | 
			
		||||
import * as IBancorNetwork from '../test/generated-artifacts/IBancorNetwork.json';
 | 
			
		||||
import * as IChai from '../test/generated-artifacts/IChai.json';
 | 
			
		||||
import * as ICurve from '../test/generated-artifacts/ICurve.json';
 | 
			
		||||
import * as IDydx from '../test/generated-artifacts/IDydx.json';
 | 
			
		||||
import * as IDydxBridge from '../test/generated-artifacts/IDydxBridge.json';
 | 
			
		||||
import * as IERC20Bridge from '../test/generated-artifacts/IERC20Bridge.json';
 | 
			
		||||
import * as IEth2Dai from '../test/generated-artifacts/IEth2Dai.json';
 | 
			
		||||
import * as IGasToken from '../test/generated-artifacts/IGasToken.json';
 | 
			
		||||
import * as IKyberNetworkProxy from '../test/generated-artifacts/IKyberNetworkProxy.json';
 | 
			
		||||
import * as IMooniswap from '../test/generated-artifacts/IMooniswap.json';
 | 
			
		||||
import * as IMStable from '../test/generated-artifacts/IMStable.json';
 | 
			
		||||
import * as IShell from '../test/generated-artifacts/IShell.json';
 | 
			
		||||
import * as IUniswapExchange from '../test/generated-artifacts/IUniswapExchange.json';
 | 
			
		||||
import * as IUniswapExchangeFactory from '../test/generated-artifacts/IUniswapExchangeFactory.json';
 | 
			
		||||
import * as IUniswapV2Router01 from '../test/generated-artifacts/IUniswapV2Router01.json';
 | 
			
		||||
import * as KyberBridge from '../test/generated-artifacts/KyberBridge.json';
 | 
			
		||||
import * as MixinAssetProxyDispatcher from '../test/generated-artifacts/MixinAssetProxyDispatcher.json';
 | 
			
		||||
import * as MixinAuthorizable from '../test/generated-artifacts/MixinAuthorizable.json';
 | 
			
		||||
import * as MixinGasToken from '../test/generated-artifacts/MixinGasToken.json';
 | 
			
		||||
import * as MooniswapBridge from '../test/generated-artifacts/MooniswapBridge.json';
 | 
			
		||||
import * as MStableBridge from '../test/generated-artifacts/MStableBridge.json';
 | 
			
		||||
import * as MultiAssetProxy from '../test/generated-artifacts/MultiAssetProxy.json';
 | 
			
		||||
import * as Ownable from '../test/generated-artifacts/Ownable.json';
 | 
			
		||||
import * as ShellBridge from '../test/generated-artifacts/ShellBridge.json';
 | 
			
		||||
import * as SnowSwapBridge from '../test/generated-artifacts/SnowSwapBridge.json';
 | 
			
		||||
import * as StaticCallProxy from '../test/generated-artifacts/StaticCallProxy.json';
 | 
			
		||||
import * as SushiSwapBridge from '../test/generated-artifacts/SushiSwapBridge.json';
 | 
			
		||||
import * as SwerveBridge from '../test/generated-artifacts/SwerveBridge.json';
 | 
			
		||||
import * as TestBancorBridge from '../test/generated-artifacts/TestBancorBridge.json';
 | 
			
		||||
import * as TestChaiBridge from '../test/generated-artifacts/TestChaiBridge.json';
 | 
			
		||||
import * as TestDexForwarderBridge from '../test/generated-artifacts/TestDexForwarderBridge.json';
 | 
			
		||||
import * as TestDydxBridge from '../test/generated-artifacts/TestDydxBridge.json';
 | 
			
		||||
import * as TestERC20Bridge from '../test/generated-artifacts/TestERC20Bridge.json';
 | 
			
		||||
import * as TestEth2DaiBridge from '../test/generated-artifacts/TestEth2DaiBridge.json';
 | 
			
		||||
import * as TestKyberBridge from '../test/generated-artifacts/TestKyberBridge.json';
 | 
			
		||||
import * as TestStaticCallTarget from '../test/generated-artifacts/TestStaticCallTarget.json';
 | 
			
		||||
import * as TestUniswapBridge from '../test/generated-artifacts/TestUniswapBridge.json';
 | 
			
		||||
import * as TestUniswapV2Bridge from '../test/generated-artifacts/TestUniswapV2Bridge.json';
 | 
			
		||||
import * as UniswapBridge from '../test/generated-artifacts/UniswapBridge.json';
 | 
			
		||||
import * as UniswapV2Bridge from '../test/generated-artifacts/UniswapV2Bridge.json';
 | 
			
		||||
export const artifacts = {
 | 
			
		||||
    MixinAssetProxyDispatcher: MixinAssetProxyDispatcher as ContractArtifact,
 | 
			
		||||
    MixinAuthorizable: MixinAuthorizable as ContractArtifact,
 | 
			
		||||
    Ownable: Ownable as ContractArtifact,
 | 
			
		||||
    ERC1155Proxy: ERC1155Proxy as ContractArtifact,
 | 
			
		||||
    ERC20BridgeProxy: ERC20BridgeProxy as ContractArtifact,
 | 
			
		||||
    ERC20Proxy: ERC20Proxy as ContractArtifact,
 | 
			
		||||
    ERC721Proxy: ERC721Proxy as ContractArtifact,
 | 
			
		||||
    MultiAssetProxy: MultiAssetProxy as ContractArtifact,
 | 
			
		||||
    StaticCallProxy: StaticCallProxy as ContractArtifact,
 | 
			
		||||
    BalancerBridge: BalancerBridge as ContractArtifact,
 | 
			
		||||
    BancorBridge: BancorBridge as ContractArtifact,
 | 
			
		||||
    ChaiBridge: ChaiBridge as ContractArtifact,
 | 
			
		||||
    CreamBridge: CreamBridge as ContractArtifact,
 | 
			
		||||
    CryptoComBridge: CryptoComBridge as ContractArtifact,
 | 
			
		||||
    CurveBridge: CurveBridge as ContractArtifact,
 | 
			
		||||
    DODOBridge: DODOBridge as ContractArtifact,
 | 
			
		||||
    DexForwarderBridge: DexForwarderBridge as ContractArtifact,
 | 
			
		||||
    DydxBridge: DydxBridge as ContractArtifact,
 | 
			
		||||
    Eth2DaiBridge: Eth2DaiBridge as ContractArtifact,
 | 
			
		||||
    KyberBridge: KyberBridge as ContractArtifact,
 | 
			
		||||
    MStableBridge: MStableBridge as ContractArtifact,
 | 
			
		||||
    MixinGasToken: MixinGasToken as ContractArtifact,
 | 
			
		||||
    MooniswapBridge: MooniswapBridge as ContractArtifact,
 | 
			
		||||
    ShellBridge: ShellBridge as ContractArtifact,
 | 
			
		||||
    SnowSwapBridge: SnowSwapBridge as ContractArtifact,
 | 
			
		||||
    SushiSwapBridge: SushiSwapBridge as ContractArtifact,
 | 
			
		||||
    SwerveBridge: SwerveBridge as ContractArtifact,
 | 
			
		||||
    UniswapBridge: UniswapBridge as ContractArtifact,
 | 
			
		||||
    UniswapV2Bridge: UniswapV2Bridge as ContractArtifact,
 | 
			
		||||
    IAssetData: IAssetData as ContractArtifact,
 | 
			
		||||
    IAssetProxy: IAssetProxy as ContractArtifact,
 | 
			
		||||
    IAssetProxyDispatcher: IAssetProxyDispatcher as ContractArtifact,
 | 
			
		||||
    IAuthorizable: IAuthorizable as ContractArtifact,
 | 
			
		||||
    IBalancerPool: IBalancerPool as ContractArtifact,
 | 
			
		||||
    IBancorNetwork: IBancorNetwork as ContractArtifact,
 | 
			
		||||
    IChai: IChai as ContractArtifact,
 | 
			
		||||
    ICurve: ICurve as ContractArtifact,
 | 
			
		||||
    IDydx: IDydx as ContractArtifact,
 | 
			
		||||
    IDydxBridge: IDydxBridge as ContractArtifact,
 | 
			
		||||
    IERC20Bridge: IERC20Bridge as ContractArtifact,
 | 
			
		||||
    IEth2Dai: IEth2Dai as ContractArtifact,
 | 
			
		||||
    IGasToken: IGasToken as ContractArtifact,
 | 
			
		||||
    IKyberNetworkProxy: IKyberNetworkProxy as ContractArtifact,
 | 
			
		||||
    IMStable: IMStable as ContractArtifact,
 | 
			
		||||
    IMooniswap: IMooniswap as ContractArtifact,
 | 
			
		||||
    IShell: IShell as ContractArtifact,
 | 
			
		||||
    IUniswapExchange: IUniswapExchange as ContractArtifact,
 | 
			
		||||
    IUniswapExchangeFactory: IUniswapExchangeFactory as ContractArtifact,
 | 
			
		||||
    IUniswapV2Router01: IUniswapV2Router01 as ContractArtifact,
 | 
			
		||||
    TestBancorBridge: TestBancorBridge as ContractArtifact,
 | 
			
		||||
    TestChaiBridge: TestChaiBridge as ContractArtifact,
 | 
			
		||||
    TestDexForwarderBridge: TestDexForwarderBridge as ContractArtifact,
 | 
			
		||||
    TestDydxBridge: TestDydxBridge as ContractArtifact,
 | 
			
		||||
    TestERC20Bridge: TestERC20Bridge as ContractArtifact,
 | 
			
		||||
    TestEth2DaiBridge: TestEth2DaiBridge as ContractArtifact,
 | 
			
		||||
    TestKyberBridge: TestKyberBridge as ContractArtifact,
 | 
			
		||||
    TestStaticCallTarget: TestStaticCallTarget as ContractArtifact,
 | 
			
		||||
    TestUniswapBridge: TestUniswapBridge as ContractArtifact,
 | 
			
		||||
    TestUniswapV2Bridge: TestUniswapV2Bridge as ContractArtifact,
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										128
									
								
								contracts/asset-proxy/test/authorizable.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								contracts/asset-proxy/test/authorizable.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,128 @@
 | 
			
		||||
import { blockchainTests, expect, provider, txDefaults, web3Wrapper } from '@0x/contracts-test-utils';
 | 
			
		||||
import { RevertReason } from '@0x/types';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
import { artifacts } from './artifacts';
 | 
			
		||||
 | 
			
		||||
import { MixinAuthorizableContract } from './wrappers';
 | 
			
		||||
 | 
			
		||||
blockchainTests.resets('Authorizable', () => {
 | 
			
		||||
    let owner: string;
 | 
			
		||||
    let notOwner: string;
 | 
			
		||||
    let address: string;
 | 
			
		||||
    let authorizable: MixinAuthorizableContract;
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        const accounts = await web3Wrapper.getAvailableAddressesAsync();
 | 
			
		||||
        [owner, address, notOwner] = accounts.slice(0, 3);
 | 
			
		||||
        authorizable = await MixinAuthorizableContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.MixinAuthorizable,
 | 
			
		||||
            provider,
 | 
			
		||||
            txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('addAuthorizedAddress', () => {
 | 
			
		||||
        it('should revert if not called by owner', async () => {
 | 
			
		||||
            const tx = authorizable.addAuthorizedAddress(notOwner).sendTransactionAsync({ from: notOwner });
 | 
			
		||||
            return expect(tx).to.revertWith(RevertReason.OnlyContractOwner);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should allow owner to add an authorized address', async () => {
 | 
			
		||||
            await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
 | 
			
		||||
            const isAuthorized = await authorizable.authorized(address).callAsync();
 | 
			
		||||
            expect(isAuthorized).to.be.true();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should revert if owner attempts to authorize a duplicate address', async () => {
 | 
			
		||||
            await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
 | 
			
		||||
            const tx = authorizable.addAuthorizedAddress(address).sendTransactionAsync({ from: owner });
 | 
			
		||||
            return expect(tx).to.revertWith(RevertReason.TargetAlreadyAuthorized);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('removeAuthorizedAddress', () => {
 | 
			
		||||
        it('should revert if not called by owner', async () => {
 | 
			
		||||
            await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
 | 
			
		||||
            const tx = authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: notOwner });
 | 
			
		||||
            return expect(tx).to.revertWith(RevertReason.OnlyContractOwner);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should allow owner to remove an authorized address', async () => {
 | 
			
		||||
            await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
 | 
			
		||||
            await authorizable.removeAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
 | 
			
		||||
            const isAuthorized = await authorizable.authorized(address).callAsync();
 | 
			
		||||
            expect(isAuthorized).to.be.false();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should revert if owner attempts to remove an address that is not authorized', async () => {
 | 
			
		||||
            const tx = authorizable.removeAuthorizedAddress(address).sendTransactionAsync({ from: owner });
 | 
			
		||||
            return expect(tx).to.revertWith(RevertReason.TargetNotAuthorized);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('removeAuthorizedAddressAtIndex', () => {
 | 
			
		||||
        it('should revert if not called by owner', async () => {
 | 
			
		||||
            await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
 | 
			
		||||
            const index = new BigNumber(0);
 | 
			
		||||
            const tx = authorizable
 | 
			
		||||
                .removeAuthorizedAddressAtIndex(address, index)
 | 
			
		||||
                .sendTransactionAsync({ from: notOwner });
 | 
			
		||||
            return expect(tx).to.revertWith(RevertReason.OnlyContractOwner);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should revert if index is >= authorities.length', async () => {
 | 
			
		||||
            await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
 | 
			
		||||
            const index = new BigNumber(1);
 | 
			
		||||
            const tx = authorizable
 | 
			
		||||
                .removeAuthorizedAddressAtIndex(address, index)
 | 
			
		||||
                .sendTransactionAsync({ from: owner });
 | 
			
		||||
            return expect(tx).to.revertWith(RevertReason.IndexOutOfBounds);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should revert if owner attempts to remove an address that is not authorized', async () => {
 | 
			
		||||
            const index = new BigNumber(0);
 | 
			
		||||
            const tx = authorizable
 | 
			
		||||
                .removeAuthorizedAddressAtIndex(address, index)
 | 
			
		||||
                .sendTransactionAsync({ from: owner });
 | 
			
		||||
            return expect(tx).to.revertWith(RevertReason.TargetNotAuthorized);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should revert if address at index does not match target', async () => {
 | 
			
		||||
            const address1 = address;
 | 
			
		||||
            const address2 = notOwner;
 | 
			
		||||
            await authorizable.addAuthorizedAddress(address1).awaitTransactionSuccessAsync({ from: owner });
 | 
			
		||||
            await authorizable.addAuthorizedAddress(address2).awaitTransactionSuccessAsync({ from: owner });
 | 
			
		||||
            const address1Index = new BigNumber(0);
 | 
			
		||||
            const tx = authorizable
 | 
			
		||||
                .removeAuthorizedAddressAtIndex(address2, address1Index)
 | 
			
		||||
                .sendTransactionAsync({ from: owner });
 | 
			
		||||
            return expect(tx).to.revertWith(RevertReason.AuthorizedAddressMismatch);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should allow owner to remove an authorized address', async () => {
 | 
			
		||||
            await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
 | 
			
		||||
            const index = new BigNumber(0);
 | 
			
		||||
            await authorizable.removeAuthorizedAddressAtIndex(address, index).awaitTransactionSuccessAsync({
 | 
			
		||||
                from: owner,
 | 
			
		||||
            });
 | 
			
		||||
            const isAuthorized = await authorizable.authorized(address).callAsync();
 | 
			
		||||
            expect(isAuthorized).to.be.false();
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('getAuthorizedAddresses', () => {
 | 
			
		||||
        it('should return all authorized addresses', async () => {
 | 
			
		||||
            const initial = await authorizable.getAuthorizedAddresses().callAsync();
 | 
			
		||||
            expect(initial).to.have.length(0);
 | 
			
		||||
            await authorizable.addAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
 | 
			
		||||
            const afterAdd = await authorizable.getAuthorizedAddresses().callAsync();
 | 
			
		||||
            expect(afterAdd).to.have.length(1);
 | 
			
		||||
            expect(afterAdd).to.include(address);
 | 
			
		||||
            await authorizable.removeAuthorizedAddress(address).awaitTransactionSuccessAsync({ from: owner });
 | 
			
		||||
            const afterRemove = await authorizable.getAuthorizedAddresses().callAsync();
 | 
			
		||||
            expect(afterRemove).to.have.length(0);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										185
									
								
								contracts/asset-proxy/test/bancor_bridge.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										185
									
								
								contracts/asset-proxy/test/bancor_bridge.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,185 @@
 | 
			
		||||
import {
 | 
			
		||||
    blockchainTests,
 | 
			
		||||
    constants,
 | 
			
		||||
    expect,
 | 
			
		||||
    filterLogsToArguments,
 | 
			
		||||
    getRandomInteger,
 | 
			
		||||
    randomAddress,
 | 
			
		||||
} from '@0x/contracts-test-utils';
 | 
			
		||||
import { AssetProxyId } from '@0x/types';
 | 
			
		||||
import { AbiEncoder, BigNumber, hexUtils } from '@0x/utils';
 | 
			
		||||
import { DecodedLogs } from 'ethereum-types';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
import { artifacts } from './artifacts';
 | 
			
		||||
import { TestBancorBridgeContract } from './generated-wrappers/test_bancor_bridge';
 | 
			
		||||
import {
 | 
			
		||||
    TestBancorBridgeConvertByPathInputEventArgs as ConvertByPathArgs,
 | 
			
		||||
    TestBancorBridgeEvents as ContractEvents,
 | 
			
		||||
    TestBancorBridgeTokenApproveEventArgs as TokenApproveArgs,
 | 
			
		||||
} from './wrappers';
 | 
			
		||||
 | 
			
		||||
blockchainTests.resets('Bancor unit tests', env => {
 | 
			
		||||
    const FROM_TOKEN_DECIMALS = 6;
 | 
			
		||||
    const TO_TOKEN_DECIMALS = 18;
 | 
			
		||||
    const FROM_TOKEN_BASE = new BigNumber(10).pow(FROM_TOKEN_DECIMALS);
 | 
			
		||||
    const TO_TOKEN_BASE = new BigNumber(10).pow(TO_TOKEN_DECIMALS);
 | 
			
		||||
    let testContract: TestBancorBridgeContract;
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        testContract = await TestBancorBridgeContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.TestBancorBridge,
 | 
			
		||||
            env.provider,
 | 
			
		||||
            env.txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('isValidSignature()', () => {
 | 
			
		||||
        it('returns success bytes', async () => {
 | 
			
		||||
            const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
 | 
			
		||||
            const result = await testContract
 | 
			
		||||
                .isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32)))
 | 
			
		||||
                .callAsync();
 | 
			
		||||
            expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('bridgeTransferFrom()', () => {
 | 
			
		||||
        interface TransferFromOpts {
 | 
			
		||||
            tokenAddressesPath: string[];
 | 
			
		||||
            toAddress: string;
 | 
			
		||||
            // Amount to pass into `bridgeTransferFrom()`
 | 
			
		||||
            amount: BigNumber;
 | 
			
		||||
            // Token balance of the bridge.
 | 
			
		||||
            fromTokenBalance: BigNumber;
 | 
			
		||||
            // Router reverts with this reason
 | 
			
		||||
            routerRevertReason: string;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        interface TransferFromResult {
 | 
			
		||||
            opts: TransferFromOpts;
 | 
			
		||||
            result: string;
 | 
			
		||||
            logs: DecodedLogs;
 | 
			
		||||
            blocktime: number;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function createTransferFromOpts(opts?: Partial<TransferFromOpts>): TransferFromOpts {
 | 
			
		||||
            const amount = getRandomInteger(1, TO_TOKEN_BASE.times(100));
 | 
			
		||||
            return {
 | 
			
		||||
                tokenAddressesPath: Array(3).fill(constants.NULL_ADDRESS),
 | 
			
		||||
                amount,
 | 
			
		||||
                toAddress: randomAddress(),
 | 
			
		||||
                fromTokenBalance: getRandomInteger(1, FROM_TOKEN_BASE.times(100)),
 | 
			
		||||
                routerRevertReason: '',
 | 
			
		||||
                ...opts,
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const bridgeDataEncoder = AbiEncoder.create('(address[], address)');
 | 
			
		||||
 | 
			
		||||
        async function transferFromAsync(opts?: Partial<TransferFromOpts>): Promise<TransferFromResult> {
 | 
			
		||||
            const _opts = createTransferFromOpts(opts);
 | 
			
		||||
 | 
			
		||||
            for (let i = 0; i < _opts.tokenAddressesPath.length; i++) {
 | 
			
		||||
                const createFromTokenFn = testContract.createToken(_opts.tokenAddressesPath[i]);
 | 
			
		||||
                _opts.tokenAddressesPath[i] = await createFromTokenFn.callAsync();
 | 
			
		||||
                await createFromTokenFn.awaitTransactionSuccessAsync();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Set the token balance for the token we're converting from.
 | 
			
		||||
            await testContract
 | 
			
		||||
                .setTokenBalance(_opts.tokenAddressesPath[0], _opts.fromTokenBalance)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
 | 
			
		||||
            // Set revert reason for the router.
 | 
			
		||||
            await testContract.setNetworkRevertReason(_opts.routerRevertReason).awaitTransactionSuccessAsync();
 | 
			
		||||
 | 
			
		||||
            // Call bridgeTransferFrom().
 | 
			
		||||
            const bridgeTransferFromFn = testContract.bridgeTransferFrom(
 | 
			
		||||
                // Output token
 | 
			
		||||
                _opts.tokenAddressesPath[_opts.tokenAddressesPath.length - 1],
 | 
			
		||||
                // Random maker address.
 | 
			
		||||
                randomAddress(),
 | 
			
		||||
                // Recipient address.
 | 
			
		||||
                _opts.toAddress,
 | 
			
		||||
                // Transfer amount.
 | 
			
		||||
                _opts.amount,
 | 
			
		||||
                // ABI-encode the input token address as the bridge data.
 | 
			
		||||
                bridgeDataEncoder.encode([
 | 
			
		||||
                    _opts.tokenAddressesPath,
 | 
			
		||||
                    await testContract.getNetworkAddress().callAsync(),
 | 
			
		||||
                ]),
 | 
			
		||||
            );
 | 
			
		||||
            const result = await bridgeTransferFromFn.callAsync();
 | 
			
		||||
            const receipt = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
 | 
			
		||||
            return {
 | 
			
		||||
                opts: _opts,
 | 
			
		||||
                result,
 | 
			
		||||
                logs: (receipt.logs as any) as DecodedLogs,
 | 
			
		||||
                blocktime: await env.web3Wrapper.getBlockTimestampAsync(receipt.blockNumber),
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        it('returns magic bytes on success', async () => {
 | 
			
		||||
            const { result } = await transferFromAsync();
 | 
			
		||||
            expect(result).to.eq(AssetProxyId.ERC20Bridge);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        describe('token -> token', async () => {
 | 
			
		||||
            it('calls BancorNetwork.convertByPath()', async () => {
 | 
			
		||||
                const { opts, result, logs } = await transferFromAsync();
 | 
			
		||||
                expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id');
 | 
			
		||||
                const transfers = filterLogsToArguments<ConvertByPathArgs>(logs, ContractEvents.ConvertByPathInput);
 | 
			
		||||
 | 
			
		||||
                expect(transfers.length).to.eq(1);
 | 
			
		||||
                expect(transfers[0].toTokenAddress).to.eq(
 | 
			
		||||
                    opts.tokenAddressesPath[opts.tokenAddressesPath.length - 1],
 | 
			
		||||
                    'output token address',
 | 
			
		||||
                );
 | 
			
		||||
                expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address');
 | 
			
		||||
                expect(transfers[0].amountIn).to.bignumber.eq(opts.fromTokenBalance, 'input token amount');
 | 
			
		||||
                expect(transfers[0].amountOutMin).to.bignumber.eq(opts.amount, 'output token amount');
 | 
			
		||||
                expect(transfers[0].feeRecipient).to.eq(constants.NULL_ADDRESS);
 | 
			
		||||
                expect(transfers[0].feeAmount).to.bignumber.eq(new BigNumber(0));
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('sets allowance for "from" token', async () => {
 | 
			
		||||
                const { logs } = await transferFromAsync();
 | 
			
		||||
                const approvals = filterLogsToArguments<TokenApproveArgs>(logs, ContractEvents.TokenApprove);
 | 
			
		||||
                const networkAddress = await testContract.getNetworkAddress().callAsync();
 | 
			
		||||
                expect(approvals.length).to.eq(1);
 | 
			
		||||
                expect(approvals[0].spender).to.eq(networkAddress);
 | 
			
		||||
                expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            it('fails if the router fails', async () => {
 | 
			
		||||
                const revertReason = 'FOOBAR';
 | 
			
		||||
                const tx = transferFromAsync({
 | 
			
		||||
                    routerRevertReason: revertReason,
 | 
			
		||||
                });
 | 
			
		||||
                return expect(tx).to.eventually.be.rejectedWith(revertReason);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
        describe('token -> token -> token', async () => {
 | 
			
		||||
            it('calls BancorNetwork.convertByPath()', async () => {
 | 
			
		||||
                const { opts, result, logs } = await transferFromAsync({
 | 
			
		||||
                    tokenAddressesPath: Array(5).fill(constants.NULL_ADDRESS),
 | 
			
		||||
                });
 | 
			
		||||
                expect(result).to.eq(AssetProxyId.ERC20Bridge, 'asset proxy id');
 | 
			
		||||
                const transfers = filterLogsToArguments<ConvertByPathArgs>(logs, ContractEvents.ConvertByPathInput);
 | 
			
		||||
 | 
			
		||||
                expect(transfers.length).to.eq(1);
 | 
			
		||||
                expect(transfers[0].toTokenAddress).to.eq(
 | 
			
		||||
                    opts.tokenAddressesPath[opts.tokenAddressesPath.length - 1],
 | 
			
		||||
                    'output token address',
 | 
			
		||||
                );
 | 
			
		||||
                expect(transfers[0].to).to.eq(opts.toAddress, 'recipient address');
 | 
			
		||||
                expect(transfers[0].amountIn).to.bignumber.eq(opts.fromTokenBalance, 'input token amount');
 | 
			
		||||
                expect(transfers[0].amountOutMin).to.bignumber.eq(opts.amount, 'output token amount');
 | 
			
		||||
                expect(transfers[0].feeRecipient).to.eq(constants.NULL_ADDRESS);
 | 
			
		||||
                expect(transfers[0].feeAmount).to.bignumber.eq(new BigNumber(0));
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										60
									
								
								contracts/asset-proxy/test/chai_bridge.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								contracts/asset-proxy/test/chai_bridge.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
			
		||||
import { ERC20TokenContract } from '@0x/contracts-erc20';
 | 
			
		||||
import { blockchainTests, constants, expect, randomAddress } from '@0x/contracts-test-utils';
 | 
			
		||||
import { AssetProxyId, RevertReason } from '@0x/types';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
import { artifacts } from './artifacts';
 | 
			
		||||
import { TestChaiBridgeContract } from './wrappers';
 | 
			
		||||
 | 
			
		||||
blockchainTests.resets('ChaiBridge unit tests', env => {
 | 
			
		||||
    let chaiBridgeContract: TestChaiBridgeContract;
 | 
			
		||||
    let testDaiContract: ERC20TokenContract;
 | 
			
		||||
    let fromAddress: string;
 | 
			
		||||
    let toAddress: string;
 | 
			
		||||
 | 
			
		||||
    const alwaysRevertAddress = '0x0000000000000000000000000000000000000001';
 | 
			
		||||
    const amount = new BigNumber(1);
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        [fromAddress, toAddress] = await env.getAccountAddressesAsync();
 | 
			
		||||
        chaiBridgeContract = await TestChaiBridgeContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.TestChaiBridge,
 | 
			
		||||
            env.provider,
 | 
			
		||||
            env.txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
        const testChaiDaiAddress = await chaiBridgeContract.testChaiDai().callAsync();
 | 
			
		||||
        testDaiContract = new ERC20TokenContract(testChaiDaiAddress, env.provider, env.txDefaults);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('bridgeTransferFrom()', () => {
 | 
			
		||||
        it('fails if not called by ERC20BridgeProxy', async () => {
 | 
			
		||||
            return expect(
 | 
			
		||||
                chaiBridgeContract
 | 
			
		||||
                    .bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES)
 | 
			
		||||
                    .awaitTransactionSuccessAsync({ from: alwaysRevertAddress }),
 | 
			
		||||
            ).to.revertWith(RevertReason.ChaiBridgeOnlyCallableByErc20BridgeProxy);
 | 
			
		||||
        });
 | 
			
		||||
        it('returns magic bytes upon success', async () => {
 | 
			
		||||
            const magicBytes = await chaiBridgeContract
 | 
			
		||||
                .bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES)
 | 
			
		||||
                .callAsync();
 | 
			
		||||
            expect(magicBytes).to.eq(AssetProxyId.ERC20Bridge);
 | 
			
		||||
        });
 | 
			
		||||
        it('should increase the Dai balance of `toAddress` by `amount` if successful', async () => {
 | 
			
		||||
            const initialBalance = await testDaiContract.balanceOf(toAddress).callAsync();
 | 
			
		||||
            await chaiBridgeContract
 | 
			
		||||
                .bridgeTransferFrom(randomAddress(), fromAddress, toAddress, amount, constants.NULL_BYTES)
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            const endBalance = await testDaiContract.balanceOf(toAddress).callAsync();
 | 
			
		||||
            expect(endBalance).to.bignumber.eq(initialBalance.plus(amount));
 | 
			
		||||
        });
 | 
			
		||||
        it('fails if the `chai.draw` call fails', async () => {
 | 
			
		||||
            return expect(
 | 
			
		||||
                chaiBridgeContract
 | 
			
		||||
                    .bridgeTransferFrom(randomAddress(), alwaysRevertAddress, toAddress, amount, constants.NULL_BYTES)
 | 
			
		||||
                    .awaitTransactionSuccessAsync(),
 | 
			
		||||
            ).to.revertWith(RevertReason.ChaiBridgeDrawDaiFailed);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										354
									
								
								contracts/asset-proxy/test/dex_forwarder_bridge.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										354
									
								
								contracts/asset-proxy/test/dex_forwarder_bridge.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,354 @@
 | 
			
		||||
import { ContractTxFunctionObj } from '@0x/contract-wrappers';
 | 
			
		||||
import {
 | 
			
		||||
    blockchainTests,
 | 
			
		||||
    constants,
 | 
			
		||||
    expect,
 | 
			
		||||
    filterLogsToArguments,
 | 
			
		||||
    getRandomInteger,
 | 
			
		||||
    randomAddress,
 | 
			
		||||
    shortZip,
 | 
			
		||||
} from '@0x/contracts-test-utils';
 | 
			
		||||
import { BigNumber, hexUtils, NULL_ADDRESS } from '@0x/utils';
 | 
			
		||||
import { DecodedLogs } from 'ethereum-types';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
import { DexForwarderBridgeCall, dexForwarderBridgeDataEncoder } from '../src/dex_forwarder_bridge';
 | 
			
		||||
 | 
			
		||||
import { artifacts } from './artifacts';
 | 
			
		||||
import {
 | 
			
		||||
    TestDexForwarderBridgeBridgeTransferFromCalledEventArgs as BtfCalledEventArgs,
 | 
			
		||||
    TestDexForwarderBridgeContract,
 | 
			
		||||
    TestDexForwarderBridgeEvents as TestEvents,
 | 
			
		||||
} from './wrappers';
 | 
			
		||||
 | 
			
		||||
const { ZERO_AMOUNT } = constants;
 | 
			
		||||
 | 
			
		||||
blockchainTests.resets('DexForwarderBridge unit tests', env => {
 | 
			
		||||
    let testContract: TestDexForwarderBridgeContract;
 | 
			
		||||
    let inputToken: string;
 | 
			
		||||
    let outputToken: string;
 | 
			
		||||
    const BRIDGE_SUCCESS = '0xdc1600f3';
 | 
			
		||||
    const BRIDGE_FAILURE = '0xffffffff';
 | 
			
		||||
    const BRIDGE_REVERT_ERROR = 'oopsie';
 | 
			
		||||
    const NOT_AUTHORIZED_REVERT = 'DexForwarderBridge/SENDER_NOT_AUTHORIZED';
 | 
			
		||||
    const DEFAULTS = {
 | 
			
		||||
        toAddress: randomAddress(),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        testContract = await TestDexForwarderBridgeContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.TestDexForwarderBridge,
 | 
			
		||||
            env.provider,
 | 
			
		||||
            env.txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
        // Create test tokens.
 | 
			
		||||
        [inputToken, outputToken] = [
 | 
			
		||||
            await callAndTransactAsync(testContract.createToken()),
 | 
			
		||||
            await callAndTransactAsync(testContract.createToken()),
 | 
			
		||||
        ];
 | 
			
		||||
        await callAndTransactAsync(testContract.setAuthorized(env.txDefaults.from as string));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    async function callAndTransactAsync<TResult>(fnCall: ContractTxFunctionObj<TResult>): Promise<TResult> {
 | 
			
		||||
        const result = await fnCall.callAsync();
 | 
			
		||||
        await fnCall.awaitTransactionSuccessAsync({}, { shouldValidate: false });
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function getRandomBridgeCall(
 | 
			
		||||
        bridgeAddress: string,
 | 
			
		||||
        fields: Partial<DexForwarderBridgeCall> = {},
 | 
			
		||||
    ): DexForwarderBridgeCall {
 | 
			
		||||
        return {
 | 
			
		||||
            target: bridgeAddress,
 | 
			
		||||
            inputTokenAmount: getRandomInteger(1, '100e18'),
 | 
			
		||||
            outputTokenAmount: getRandomInteger(1, '100e18'),
 | 
			
		||||
            bridgeData: hexUtils.leftPad(inputToken),
 | 
			
		||||
            ...fields,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    describe('bridgeTransferFrom()', () => {
 | 
			
		||||
        let goodBridgeCalls: DexForwarderBridgeCall[];
 | 
			
		||||
        let revertingBridgeCall: DexForwarderBridgeCall;
 | 
			
		||||
        let failingBridgeCall: DexForwarderBridgeCall;
 | 
			
		||||
        let allBridgeCalls: DexForwarderBridgeCall[];
 | 
			
		||||
        let totalFillableOutputAmount: BigNumber;
 | 
			
		||||
        let totalFillableInputAmount: BigNumber;
 | 
			
		||||
        let recipientOutputBalance: BigNumber;
 | 
			
		||||
 | 
			
		||||
        beforeEach(async () => {
 | 
			
		||||
            goodBridgeCalls = [];
 | 
			
		||||
            for (let i = 0; i < 4; ++i) {
 | 
			
		||||
                goodBridgeCalls.push(await createBridgeCallAsync({ returnCode: BRIDGE_SUCCESS }));
 | 
			
		||||
            }
 | 
			
		||||
            revertingBridgeCall = await createBridgeCallAsync({ revertError: BRIDGE_REVERT_ERROR });
 | 
			
		||||
            failingBridgeCall = await createBridgeCallAsync({ returnCode: BRIDGE_FAILURE });
 | 
			
		||||
            allBridgeCalls = _.shuffle([failingBridgeCall, revertingBridgeCall, ...goodBridgeCalls]);
 | 
			
		||||
 | 
			
		||||
            totalFillableInputAmount = BigNumber.sum(...goodBridgeCalls.map(c => c.inputTokenAmount));
 | 
			
		||||
            totalFillableOutputAmount = BigNumber.sum(...goodBridgeCalls.map(c => c.outputTokenAmount));
 | 
			
		||||
 | 
			
		||||
            // Grant the taker some output tokens.
 | 
			
		||||
            await testContract.setTokenBalance(
 | 
			
		||||
                outputToken,
 | 
			
		||||
                DEFAULTS.toAddress,
 | 
			
		||||
                (recipientOutputBalance = getRandomInteger(1, '100e18')),
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        async function setForwarderInputBalanceAsync(amount: BigNumber): Promise<void> {
 | 
			
		||||
            await testContract
 | 
			
		||||
                .setTokenBalance(inputToken, testContract.address, amount)
 | 
			
		||||
                .awaitTransactionSuccessAsync({}, { shouldValidate: false });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        async function createBridgeCallAsync(
 | 
			
		||||
            opts: Partial<{
 | 
			
		||||
                returnCode: string;
 | 
			
		||||
                revertError: string;
 | 
			
		||||
                callFields: Partial<DexForwarderBridgeCall>;
 | 
			
		||||
                outputFillAmount: BigNumber;
 | 
			
		||||
            }>,
 | 
			
		||||
        ): Promise<DexForwarderBridgeCall> {
 | 
			
		||||
            const { returnCode, revertError, callFields, outputFillAmount } = {
 | 
			
		||||
                returnCode: BRIDGE_SUCCESS,
 | 
			
		||||
                revertError: '',
 | 
			
		||||
                ...opts,
 | 
			
		||||
            };
 | 
			
		||||
            const bridge = await callAndTransactAsync(testContract.createBridge(returnCode, revertError));
 | 
			
		||||
            const call = getRandomBridgeCall(bridge, callFields);
 | 
			
		||||
            await testContract
 | 
			
		||||
                .setBridgeTransferAmount(call.target, outputFillAmount || call.outputTokenAmount)
 | 
			
		||||
                .awaitTransactionSuccessAsync({}, { shouldValidate: false });
 | 
			
		||||
            return call;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        async function callBridgeTransferFromAsync(opts: {
 | 
			
		||||
            bridgeData: string;
 | 
			
		||||
            sellAmount?: BigNumber;
 | 
			
		||||
            buyAmount?: BigNumber;
 | 
			
		||||
        }): Promise<DecodedLogs> {
 | 
			
		||||
            // Fund the forwarder with input tokens to sell.
 | 
			
		||||
            await setForwarderInputBalanceAsync(opts.sellAmount || totalFillableInputAmount);
 | 
			
		||||
            const call = testContract.bridgeTransferFrom(
 | 
			
		||||
                outputToken,
 | 
			
		||||
                testContract.address,
 | 
			
		||||
                DEFAULTS.toAddress,
 | 
			
		||||
                opts.buyAmount || totalFillableOutputAmount,
 | 
			
		||||
                opts.bridgeData,
 | 
			
		||||
            );
 | 
			
		||||
            const returnCode = await call.callAsync();
 | 
			
		||||
            if (returnCode !== BRIDGE_SUCCESS) {
 | 
			
		||||
                throw new Error('Expected BRIDGE_SUCCESS');
 | 
			
		||||
            }
 | 
			
		||||
            const receipt = await call.awaitTransactionSuccessAsync({}, { shouldValidate: false });
 | 
			
		||||
            // tslint:disable-next-line: no-unnecessary-type-assertion
 | 
			
		||||
            return receipt.logs as DecodedLogs;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        it('succeeds with no bridge calls and no input balance', async () => {
 | 
			
		||||
            const bridgeData = dexForwarderBridgeDataEncoder.encode({
 | 
			
		||||
                inputToken,
 | 
			
		||||
                calls: [],
 | 
			
		||||
            });
 | 
			
		||||
            await callBridgeTransferFromAsync({ bridgeData, sellAmount: ZERO_AMOUNT });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('succeeds with bridge calls and no input balance', async () => {
 | 
			
		||||
            const bridgeData = dexForwarderBridgeDataEncoder.encode({
 | 
			
		||||
                inputToken,
 | 
			
		||||
                calls: allBridgeCalls,
 | 
			
		||||
            });
 | 
			
		||||
            await callBridgeTransferFromAsync({ bridgeData, sellAmount: ZERO_AMOUNT });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('succeeds with no bridge calls and an input balance', async () => {
 | 
			
		||||
            const bridgeData = dexForwarderBridgeDataEncoder.encode({
 | 
			
		||||
                inputToken,
 | 
			
		||||
                calls: [],
 | 
			
		||||
            });
 | 
			
		||||
            await callBridgeTransferFromAsync({
 | 
			
		||||
                bridgeData,
 | 
			
		||||
                sellAmount: new BigNumber(1),
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('succeeds if entire input token balance is not consumed', async () => {
 | 
			
		||||
            const bridgeData = dexForwarderBridgeDataEncoder.encode({
 | 
			
		||||
                inputToken,
 | 
			
		||||
                calls: allBridgeCalls,
 | 
			
		||||
            });
 | 
			
		||||
            await callBridgeTransferFromAsync({
 | 
			
		||||
                bridgeData,
 | 
			
		||||
                sellAmount: totalFillableInputAmount.plus(1),
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if not authorized', async () => {
 | 
			
		||||
            const calls = goodBridgeCalls.slice(0, 1);
 | 
			
		||||
            const bridgeData = dexForwarderBridgeDataEncoder.encode({
 | 
			
		||||
                inputToken,
 | 
			
		||||
                calls,
 | 
			
		||||
            });
 | 
			
		||||
            await callAndTransactAsync(testContract.setAuthorized(NULL_ADDRESS));
 | 
			
		||||
            return expect(callBridgeTransferFromAsync({ bridgeData, sellAmount: new BigNumber(1) })).to.revertWith(
 | 
			
		||||
                NOT_AUTHORIZED_REVERT,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('succeeds with one bridge call', async () => {
 | 
			
		||||
            const calls = goodBridgeCalls.slice(0, 1);
 | 
			
		||||
            const bridgeData = dexForwarderBridgeDataEncoder.encode({
 | 
			
		||||
                inputToken,
 | 
			
		||||
                calls,
 | 
			
		||||
            });
 | 
			
		||||
            await callBridgeTransferFromAsync({ bridgeData, sellAmount: calls[0].inputTokenAmount });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('succeeds with many bridge calls', async () => {
 | 
			
		||||
            const calls = goodBridgeCalls;
 | 
			
		||||
            const bridgeData = dexForwarderBridgeDataEncoder.encode({
 | 
			
		||||
                inputToken,
 | 
			
		||||
                calls,
 | 
			
		||||
            });
 | 
			
		||||
            await callBridgeTransferFromAsync({ bridgeData });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('swallows a failing bridge call', async () => {
 | 
			
		||||
            const calls = _.shuffle([...goodBridgeCalls, failingBridgeCall]);
 | 
			
		||||
            const bridgeData = dexForwarderBridgeDataEncoder.encode({
 | 
			
		||||
                inputToken,
 | 
			
		||||
                calls,
 | 
			
		||||
            });
 | 
			
		||||
            await callBridgeTransferFromAsync({ bridgeData });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('consumes input tokens for output tokens', async () => {
 | 
			
		||||
            const calls = allBridgeCalls;
 | 
			
		||||
            const bridgeData = dexForwarderBridgeDataEncoder.encode({
 | 
			
		||||
                inputToken,
 | 
			
		||||
                calls,
 | 
			
		||||
            });
 | 
			
		||||
            await callBridgeTransferFromAsync({ bridgeData });
 | 
			
		||||
            const currentBridgeInputBalance = await testContract
 | 
			
		||||
                .balanceOf(inputToken, testContract.address)
 | 
			
		||||
                .callAsync();
 | 
			
		||||
            expect(currentBridgeInputBalance).to.bignumber.eq(0);
 | 
			
		||||
            const currentRecipientOutputBalance = await testContract
 | 
			
		||||
                .balanceOf(outputToken, DEFAULTS.toAddress)
 | 
			
		||||
                .callAsync();
 | 
			
		||||
            expect(currentRecipientOutputBalance).to.bignumber.eq(totalFillableOutputAmount);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it("transfers only up to each call's input amount to each bridge", async () => {
 | 
			
		||||
            const calls = goodBridgeCalls;
 | 
			
		||||
            const bridgeData = dexForwarderBridgeDataEncoder.encode({
 | 
			
		||||
                inputToken,
 | 
			
		||||
                calls,
 | 
			
		||||
            });
 | 
			
		||||
            const logs = await callBridgeTransferFromAsync({ bridgeData });
 | 
			
		||||
            const btfs = filterLogsToArguments<BtfCalledEventArgs>(logs, TestEvents.BridgeTransferFromCalled);
 | 
			
		||||
            for (const [call, btf] of shortZip(goodBridgeCalls, btfs)) {
 | 
			
		||||
                expect(btf.inputTokenBalance).to.bignumber.eq(call.inputTokenAmount);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('transfers only up to outstanding sell amount to each bridge', async () => {
 | 
			
		||||
            // Prepend an extra bridge call.
 | 
			
		||||
            const calls = [
 | 
			
		||||
                await createBridgeCallAsync({
 | 
			
		||||
                    callFields: {
 | 
			
		||||
                        inputTokenAmount: new BigNumber(1),
 | 
			
		||||
                        outputTokenAmount: new BigNumber(1),
 | 
			
		||||
                    },
 | 
			
		||||
                }),
 | 
			
		||||
                ...goodBridgeCalls,
 | 
			
		||||
            ];
 | 
			
		||||
            const bridgeData = dexForwarderBridgeDataEncoder.encode({
 | 
			
		||||
                inputToken,
 | 
			
		||||
                calls,
 | 
			
		||||
            });
 | 
			
		||||
            const logs = await callBridgeTransferFromAsync({ bridgeData });
 | 
			
		||||
            const btfs = filterLogsToArguments<BtfCalledEventArgs>(logs, TestEvents.BridgeTransferFromCalled);
 | 
			
		||||
            expect(btfs).to.be.length(goodBridgeCalls.length + 1);
 | 
			
		||||
            // The last call will receive 1 less token.
 | 
			
		||||
            const lastCall = calls.slice(-1)[0];
 | 
			
		||||
            const lastBtf = btfs.slice(-1)[0];
 | 
			
		||||
            expect(lastBtf.inputTokenBalance).to.bignumber.eq(lastCall.inputTokenAmount.minus(1));
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('recoups funds from a bridge that fails', async () => {
 | 
			
		||||
            // Prepend a call that will take the whole input amount but will
 | 
			
		||||
            // fail.
 | 
			
		||||
            const badCall = await createBridgeCallAsync({
 | 
			
		||||
                callFields: { inputTokenAmount: totalFillableInputAmount },
 | 
			
		||||
                returnCode: BRIDGE_FAILURE,
 | 
			
		||||
            });
 | 
			
		||||
            const calls = [badCall, ...goodBridgeCalls];
 | 
			
		||||
            const bridgeData = dexForwarderBridgeDataEncoder.encode({
 | 
			
		||||
                inputToken,
 | 
			
		||||
                calls,
 | 
			
		||||
            });
 | 
			
		||||
            const logs = await callBridgeTransferFromAsync({ bridgeData });
 | 
			
		||||
            const btfs = filterLogsToArguments<BtfCalledEventArgs>(logs, TestEvents.BridgeTransferFromCalled);
 | 
			
		||||
            expect(btfs).to.be.length(goodBridgeCalls.length);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('recoups funds from a bridge that reverts', async () => {
 | 
			
		||||
            // Prepend a call that will take the whole input amount but will
 | 
			
		||||
            // revert.
 | 
			
		||||
            const badCall = await createBridgeCallAsync({
 | 
			
		||||
                callFields: { inputTokenAmount: totalFillableInputAmount },
 | 
			
		||||
                revertError: BRIDGE_REVERT_ERROR,
 | 
			
		||||
            });
 | 
			
		||||
            const calls = [badCall, ...goodBridgeCalls];
 | 
			
		||||
            const bridgeData = dexForwarderBridgeDataEncoder.encode({
 | 
			
		||||
                inputToken,
 | 
			
		||||
                calls,
 | 
			
		||||
            });
 | 
			
		||||
            const logs = await callBridgeTransferFromAsync({ bridgeData });
 | 
			
		||||
            const btfs = filterLogsToArguments<BtfCalledEventArgs>(logs, TestEvents.BridgeTransferFromCalled);
 | 
			
		||||
            expect(btfs).to.be.length(goodBridgeCalls.length);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('recoups funds from a bridge that under-pays', async () => {
 | 
			
		||||
            // Prepend a call that will take the whole input amount but will
 | 
			
		||||
            // underpay the output amount..
 | 
			
		||||
            const badCall = await createBridgeCallAsync({
 | 
			
		||||
                callFields: {
 | 
			
		||||
                    inputTokenAmount: totalFillableInputAmount,
 | 
			
		||||
                    outputTokenAmount: new BigNumber(2),
 | 
			
		||||
                },
 | 
			
		||||
                outputFillAmount: new BigNumber(1),
 | 
			
		||||
            });
 | 
			
		||||
            const calls = [badCall, ...goodBridgeCalls];
 | 
			
		||||
            const bridgeData = dexForwarderBridgeDataEncoder.encode({
 | 
			
		||||
                inputToken,
 | 
			
		||||
                calls,
 | 
			
		||||
            });
 | 
			
		||||
            const logs = await callBridgeTransferFromAsync({ bridgeData });
 | 
			
		||||
            const btfs = filterLogsToArguments<BtfCalledEventArgs>(logs, TestEvents.BridgeTransferFromCalled);
 | 
			
		||||
            expect(btfs).to.be.length(goodBridgeCalls.length);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('executeBridgeCall()', () => {
 | 
			
		||||
        it('cannot be called externally', async () => {
 | 
			
		||||
            return expect(
 | 
			
		||||
                testContract
 | 
			
		||||
                    .executeBridgeCall(
 | 
			
		||||
                        randomAddress(),
 | 
			
		||||
                        randomAddress(),
 | 
			
		||||
                        randomAddress(),
 | 
			
		||||
                        randomAddress(),
 | 
			
		||||
                        new BigNumber(1),
 | 
			
		||||
                        new BigNumber(1),
 | 
			
		||||
                        constants.NULL_BYTES,
 | 
			
		||||
                    )
 | 
			
		||||
                    .callAsync(),
 | 
			
		||||
            ).to.revertWith('DexForwarderBridge/ONLY_SELF');
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										399
									
								
								contracts/asset-proxy/test/dydx_bridge.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										399
									
								
								contracts/asset-proxy/test/dydx_bridge.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,399 @@
 | 
			
		||||
import { LibMathRevertErrors } from '@0x/contracts-exchange-libs';
 | 
			
		||||
import { blockchainTests, constants, expect, verifyEventsFromLogs } from '@0x/contracts-test-utils';
 | 
			
		||||
import { AssetProxyId, RevertReason } from '@0x/types';
 | 
			
		||||
import { BigNumber } from '@0x/utils';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
import { DydxBridgeActionType, DydxBridgeData, dydxBridgeDataEncoder } from '../src/dydx_bridge_encoder';
 | 
			
		||||
import { ERC20BridgeProxyContract, IAssetDataContract } from '../src/wrappers';
 | 
			
		||||
 | 
			
		||||
import { artifacts } from './artifacts';
 | 
			
		||||
import { TestDydxBridgeContract, TestDydxBridgeEvents } from './wrappers';
 | 
			
		||||
 | 
			
		||||
blockchainTests.resets('DydxBridge unit tests', env => {
 | 
			
		||||
    const defaultAccountNumber = new BigNumber(1);
 | 
			
		||||
    const marketId = new BigNumber(2);
 | 
			
		||||
    const defaultAmount = new BigNumber(4);
 | 
			
		||||
    const notAuthorized = '0x0000000000000000000000000000000000000001';
 | 
			
		||||
    const defaultDepositAction = {
 | 
			
		||||
        actionType: DydxBridgeActionType.Deposit,
 | 
			
		||||
        accountIdx: constants.ZERO_AMOUNT,
 | 
			
		||||
        marketId,
 | 
			
		||||
        conversionRateNumerator: constants.ZERO_AMOUNT,
 | 
			
		||||
        conversionRateDenominator: constants.ZERO_AMOUNT,
 | 
			
		||||
    };
 | 
			
		||||
    const defaultWithdrawAction = {
 | 
			
		||||
        actionType: DydxBridgeActionType.Withdraw,
 | 
			
		||||
        accountIdx: constants.ZERO_AMOUNT,
 | 
			
		||||
        marketId,
 | 
			
		||||
        conversionRateNumerator: constants.ZERO_AMOUNT,
 | 
			
		||||
        conversionRateDenominator: constants.ZERO_AMOUNT,
 | 
			
		||||
    };
 | 
			
		||||
    let testContract: TestDydxBridgeContract;
 | 
			
		||||
    let testProxyContract: ERC20BridgeProxyContract;
 | 
			
		||||
    let assetDataEncoder: IAssetDataContract;
 | 
			
		||||
    let owner: string;
 | 
			
		||||
    let authorized: string;
 | 
			
		||||
    let accountOwner: string;
 | 
			
		||||
    let receiver: string;
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        // Get accounts
 | 
			
		||||
        const accounts = await env.web3Wrapper.getAvailableAddressesAsync();
 | 
			
		||||
        [owner, authorized, accountOwner, receiver] = accounts;
 | 
			
		||||
 | 
			
		||||
        // Deploy dydx bridge
 | 
			
		||||
        testContract = await TestDydxBridgeContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.TestDydxBridge,
 | 
			
		||||
            env.provider,
 | 
			
		||||
            env.txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
            [accountOwner, receiver],
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Deploy test erc20 bridge proxy
 | 
			
		||||
        testProxyContract = await ERC20BridgeProxyContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.ERC20BridgeProxy,
 | 
			
		||||
            env.provider,
 | 
			
		||||
            env.txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
        await testProxyContract.addAuthorizedAddress(authorized).awaitTransactionSuccessAsync({ from: owner });
 | 
			
		||||
 | 
			
		||||
        // Setup asset data encoder
 | 
			
		||||
        assetDataEncoder = new IAssetDataContract(constants.NULL_ADDRESS, env.provider);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('bridgeTransferFrom()', () => {
 | 
			
		||||
        const callBridgeTransferFrom = async (
 | 
			
		||||
            from: string,
 | 
			
		||||
            to: string,
 | 
			
		||||
            amount: BigNumber,
 | 
			
		||||
            bridgeData: DydxBridgeData,
 | 
			
		||||
            sender: string,
 | 
			
		||||
        ): Promise<string> => {
 | 
			
		||||
            const returnValue = await testContract
 | 
			
		||||
                .bridgeTransferFrom(
 | 
			
		||||
                    constants.NULL_ADDRESS,
 | 
			
		||||
                    from,
 | 
			
		||||
                    to,
 | 
			
		||||
                    amount,
 | 
			
		||||
                    dydxBridgeDataEncoder.encode({ bridgeData }),
 | 
			
		||||
                )
 | 
			
		||||
                .callAsync({ from: sender });
 | 
			
		||||
            return returnValue;
 | 
			
		||||
        };
 | 
			
		||||
        const executeBridgeTransferFromAndVerifyEvents = async (
 | 
			
		||||
            from: string,
 | 
			
		||||
            to: string,
 | 
			
		||||
            amount: BigNumber,
 | 
			
		||||
            bridgeData: DydxBridgeData,
 | 
			
		||||
            sender: string,
 | 
			
		||||
        ): Promise<void> => {
 | 
			
		||||
            // Execute transaction.
 | 
			
		||||
            const txReceipt = await testContract
 | 
			
		||||
                .bridgeTransferFrom(
 | 
			
		||||
                    constants.NULL_ADDRESS,
 | 
			
		||||
                    from,
 | 
			
		||||
                    to,
 | 
			
		||||
                    amount,
 | 
			
		||||
                    dydxBridgeDataEncoder.encode({ bridgeData }),
 | 
			
		||||
                )
 | 
			
		||||
                .awaitTransactionSuccessAsync({ from: sender });
 | 
			
		||||
 | 
			
		||||
            // Verify `OperateAccount` event.
 | 
			
		||||
            const expectedOperateAccountEvents = [];
 | 
			
		||||
            for (const accountNumber of bridgeData.accountNumbers) {
 | 
			
		||||
                expectedOperateAccountEvents.push({
 | 
			
		||||
                    owner: accountOwner,
 | 
			
		||||
                    number: accountNumber,
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            verifyEventsFromLogs(txReceipt.logs, expectedOperateAccountEvents, TestDydxBridgeEvents.OperateAccount);
 | 
			
		||||
 | 
			
		||||
            // Verify `OperateAction` event.
 | 
			
		||||
            const weiDenomination = 0;
 | 
			
		||||
            const deltaAmountRef = 0;
 | 
			
		||||
            const expectedOperateActionEvents = [];
 | 
			
		||||
            for (const action of bridgeData.actions) {
 | 
			
		||||
                expectedOperateActionEvents.push({
 | 
			
		||||
                    actionType: action.actionType as number,
 | 
			
		||||
                    accountIdx: action.accountIdx,
 | 
			
		||||
                    amountSign: action.actionType === DydxBridgeActionType.Deposit ? true : false,
 | 
			
		||||
                    amountDenomination: weiDenomination,
 | 
			
		||||
                    amountRef: deltaAmountRef,
 | 
			
		||||
                    amountValue: action.conversionRateDenominator.gt(0)
 | 
			
		||||
                        ? amount
 | 
			
		||||
                              .times(action.conversionRateNumerator)
 | 
			
		||||
                              .dividedToIntegerBy(action.conversionRateDenominator)
 | 
			
		||||
                        : amount,
 | 
			
		||||
                    primaryMarketId: marketId,
 | 
			
		||||
                    secondaryMarketId: constants.ZERO_AMOUNT,
 | 
			
		||||
                    otherAddress: action.actionType === DydxBridgeActionType.Deposit ? from : to,
 | 
			
		||||
                    otherAccountId: constants.ZERO_AMOUNT,
 | 
			
		||||
                    data: '0x',
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            verifyEventsFromLogs(txReceipt.logs, expectedOperateActionEvents, TestDydxBridgeEvents.OperateAction);
 | 
			
		||||
        };
 | 
			
		||||
        it('succeeds when calling with zero amount', async () => {
 | 
			
		||||
            const bridgeData = {
 | 
			
		||||
                accountNumbers: [defaultAccountNumber],
 | 
			
		||||
                actions: [defaultDepositAction],
 | 
			
		||||
            };
 | 
			
		||||
            await executeBridgeTransferFromAndVerifyEvents(
 | 
			
		||||
                accountOwner,
 | 
			
		||||
                receiver,
 | 
			
		||||
                constants.ZERO_AMOUNT,
 | 
			
		||||
                bridgeData,
 | 
			
		||||
                authorized,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('succeeds when calling with no accounts', async () => {
 | 
			
		||||
            const bridgeData = {
 | 
			
		||||
                accountNumbers: [],
 | 
			
		||||
                actions: [defaultDepositAction],
 | 
			
		||||
            };
 | 
			
		||||
            await executeBridgeTransferFromAndVerifyEvents(
 | 
			
		||||
                accountOwner,
 | 
			
		||||
                receiver,
 | 
			
		||||
                defaultAmount,
 | 
			
		||||
                bridgeData,
 | 
			
		||||
                authorized,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('succeeds when calling with no actions', async () => {
 | 
			
		||||
            const bridgeData = {
 | 
			
		||||
                accountNumbers: [defaultAccountNumber],
 | 
			
		||||
                actions: [],
 | 
			
		||||
            };
 | 
			
		||||
            await executeBridgeTransferFromAndVerifyEvents(
 | 
			
		||||
                accountOwner,
 | 
			
		||||
                receiver,
 | 
			
		||||
                defaultAmount,
 | 
			
		||||
                bridgeData,
 | 
			
		||||
                authorized,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('succeeds when calling `operate` with the `deposit` action and a single account', async () => {
 | 
			
		||||
            const bridgeData = {
 | 
			
		||||
                accountNumbers: [defaultAccountNumber],
 | 
			
		||||
                actions: [defaultDepositAction],
 | 
			
		||||
            };
 | 
			
		||||
            await executeBridgeTransferFromAndVerifyEvents(
 | 
			
		||||
                accountOwner,
 | 
			
		||||
                receiver,
 | 
			
		||||
                defaultAmount,
 | 
			
		||||
                bridgeData,
 | 
			
		||||
                authorized,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('succeeds when calling `operate` with the `deposit` action and multiple accounts', async () => {
 | 
			
		||||
            const bridgeData = {
 | 
			
		||||
                accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)],
 | 
			
		||||
                actions: [defaultDepositAction],
 | 
			
		||||
            };
 | 
			
		||||
            await executeBridgeTransferFromAndVerifyEvents(
 | 
			
		||||
                accountOwner,
 | 
			
		||||
                receiver,
 | 
			
		||||
                defaultAmount,
 | 
			
		||||
                bridgeData,
 | 
			
		||||
                authorized,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('succeeds when calling `operate` with the `withdraw` action and a single account', async () => {
 | 
			
		||||
            const bridgeData = {
 | 
			
		||||
                accountNumbers: [defaultAccountNumber],
 | 
			
		||||
                actions: [defaultWithdrawAction],
 | 
			
		||||
            };
 | 
			
		||||
            await executeBridgeTransferFromAndVerifyEvents(
 | 
			
		||||
                accountOwner,
 | 
			
		||||
                receiver,
 | 
			
		||||
                defaultAmount,
 | 
			
		||||
                bridgeData,
 | 
			
		||||
                authorized,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('succeeds when calling `operate` with the `withdraw` action and multiple accounts', async () => {
 | 
			
		||||
            const bridgeData = {
 | 
			
		||||
                accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)],
 | 
			
		||||
                actions: [defaultWithdrawAction],
 | 
			
		||||
            };
 | 
			
		||||
            await executeBridgeTransferFromAndVerifyEvents(
 | 
			
		||||
                accountOwner,
 | 
			
		||||
                receiver,
 | 
			
		||||
                defaultAmount,
 | 
			
		||||
                bridgeData,
 | 
			
		||||
                authorized,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('succeeds when calling `operate` with the `deposit` action and multiple accounts', async () => {
 | 
			
		||||
            const bridgeData = {
 | 
			
		||||
                accountNumbers: [defaultAccountNumber, defaultAccountNumber.plus(1)],
 | 
			
		||||
                actions: [defaultWithdrawAction, defaultDepositAction],
 | 
			
		||||
            };
 | 
			
		||||
            await executeBridgeTransferFromAndVerifyEvents(
 | 
			
		||||
                accountOwner,
 | 
			
		||||
                receiver,
 | 
			
		||||
                defaultAmount,
 | 
			
		||||
                bridgeData,
 | 
			
		||||
                authorized,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('succeeds when calling `operate` with multiple actions under a single account', async () => {
 | 
			
		||||
            const bridgeData = {
 | 
			
		||||
                accountNumbers: [defaultAccountNumber],
 | 
			
		||||
                actions: [defaultWithdrawAction, defaultDepositAction],
 | 
			
		||||
            };
 | 
			
		||||
            await executeBridgeTransferFromAndVerifyEvents(
 | 
			
		||||
                accountOwner,
 | 
			
		||||
                receiver,
 | 
			
		||||
                defaultAmount,
 | 
			
		||||
                bridgeData,
 | 
			
		||||
                authorized,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('succeeds when scaling the `amount` to deposit', async () => {
 | 
			
		||||
            const conversionRateNumerator = new BigNumber(1);
 | 
			
		||||
            const conversionRateDenominator = new BigNumber(2);
 | 
			
		||||
            const bridgeData = {
 | 
			
		||||
                accountNumbers: [defaultAccountNumber],
 | 
			
		||||
                actions: [
 | 
			
		||||
                    defaultWithdrawAction,
 | 
			
		||||
                    {
 | 
			
		||||
                        ...defaultDepositAction,
 | 
			
		||||
                        conversionRateNumerator,
 | 
			
		||||
                        conversionRateDenominator,
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
            };
 | 
			
		||||
            await executeBridgeTransferFromAndVerifyEvents(
 | 
			
		||||
                accountOwner,
 | 
			
		||||
                receiver,
 | 
			
		||||
                defaultAmount,
 | 
			
		||||
                bridgeData,
 | 
			
		||||
                authorized,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('succeeds when scaling the `amount` to withdraw', async () => {
 | 
			
		||||
            const conversionRateNumerator = new BigNumber(1);
 | 
			
		||||
            const conversionRateDenominator = new BigNumber(2);
 | 
			
		||||
            const bridgeData = {
 | 
			
		||||
                accountNumbers: [defaultAccountNumber],
 | 
			
		||||
                actions: [
 | 
			
		||||
                    defaultDepositAction,
 | 
			
		||||
                    {
 | 
			
		||||
                        ...defaultWithdrawAction,
 | 
			
		||||
                        conversionRateNumerator,
 | 
			
		||||
                        conversionRateDenominator,
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
            };
 | 
			
		||||
            await executeBridgeTransferFromAndVerifyEvents(
 | 
			
		||||
                accountOwner,
 | 
			
		||||
                receiver,
 | 
			
		||||
                defaultAmount,
 | 
			
		||||
                bridgeData,
 | 
			
		||||
                authorized,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
        it('reverts if not called by the ERC20 Bridge Proxy', async () => {
 | 
			
		||||
            const bridgeData = {
 | 
			
		||||
                accountNumbers: [defaultAccountNumber],
 | 
			
		||||
                actions: [defaultDepositAction],
 | 
			
		||||
            };
 | 
			
		||||
            const callBridgeTransferFromPromise = callBridgeTransferFrom(
 | 
			
		||||
                accountOwner,
 | 
			
		||||
                receiver,
 | 
			
		||||
                defaultAmount,
 | 
			
		||||
                bridgeData,
 | 
			
		||||
                notAuthorized,
 | 
			
		||||
            );
 | 
			
		||||
            const expectedError = RevertReason.DydxBridgeOnlyCallableByErc20BridgeProxy;
 | 
			
		||||
            return expect(callBridgeTransferFromPromise).to.revertWith(expectedError);
 | 
			
		||||
        });
 | 
			
		||||
        it('should return magic bytes if call succeeds', async () => {
 | 
			
		||||
            const bridgeData = {
 | 
			
		||||
                accountNumbers: [defaultAccountNumber],
 | 
			
		||||
                actions: [defaultDepositAction],
 | 
			
		||||
            };
 | 
			
		||||
            const returnValue = await callBridgeTransferFrom(
 | 
			
		||||
                accountOwner,
 | 
			
		||||
                receiver,
 | 
			
		||||
                defaultAmount,
 | 
			
		||||
                bridgeData,
 | 
			
		||||
                authorized,
 | 
			
		||||
            );
 | 
			
		||||
            expect(returnValue).to.equal(AssetProxyId.ERC20Bridge);
 | 
			
		||||
        });
 | 
			
		||||
        it('should revert when `Operate` reverts', async () => {
 | 
			
		||||
            // Set revert flag.
 | 
			
		||||
            await testContract.setRevertOnOperate(true).awaitTransactionSuccessAsync();
 | 
			
		||||
 | 
			
		||||
            // Execute transfer.
 | 
			
		||||
            const bridgeData = {
 | 
			
		||||
                accountNumbers: [defaultAccountNumber],
 | 
			
		||||
                actions: [defaultDepositAction],
 | 
			
		||||
            };
 | 
			
		||||
            const tx = callBridgeTransferFrom(accountOwner, receiver, defaultAmount, bridgeData, authorized);
 | 
			
		||||
            const expectedError = 'TestDydxBridge/SHOULD_REVERT_ON_OPERATE';
 | 
			
		||||
            return expect(tx).to.revertWith(expectedError);
 | 
			
		||||
        });
 | 
			
		||||
        it('should revert when there is a rounding error', async () => {
 | 
			
		||||
            // Setup a rounding error
 | 
			
		||||
            const conversionRateNumerator = new BigNumber(5318);
 | 
			
		||||
            const conversionRateDenominator = new BigNumber(47958);
 | 
			
		||||
            const amount = new BigNumber(9000);
 | 
			
		||||
            const bridgeData = {
 | 
			
		||||
                accountNumbers: [defaultAccountNumber],
 | 
			
		||||
                actions: [
 | 
			
		||||
                    defaultDepositAction,
 | 
			
		||||
                    {
 | 
			
		||||
                        ...defaultWithdrawAction,
 | 
			
		||||
                        conversionRateNumerator,
 | 
			
		||||
                        conversionRateDenominator,
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            // Execute transfer and assert error.
 | 
			
		||||
            const tx = callBridgeTransferFrom(accountOwner, receiver, amount, bridgeData, authorized);
 | 
			
		||||
            const expectedError = new LibMathRevertErrors.RoundingError(
 | 
			
		||||
                conversionRateNumerator,
 | 
			
		||||
                conversionRateDenominator,
 | 
			
		||||
                amount,
 | 
			
		||||
            );
 | 
			
		||||
            return expect(tx).to.revertWith(expectedError);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('ERC20BridgeProxy.transferFrom()', () => {
 | 
			
		||||
        const bridgeData = {
 | 
			
		||||
            accountNumbers: [defaultAccountNumber],
 | 
			
		||||
            actions: [defaultWithdrawAction],
 | 
			
		||||
        };
 | 
			
		||||
        let assetData: string;
 | 
			
		||||
 | 
			
		||||
        before(async () => {
 | 
			
		||||
            const testTokenAddress = await testContract.getTestToken().callAsync();
 | 
			
		||||
            assetData = assetDataEncoder
 | 
			
		||||
                .ERC20Bridge(testTokenAddress, testContract.address, dydxBridgeDataEncoder.encode({ bridgeData }))
 | 
			
		||||
                .getABIEncodedTransactionData();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('should succeed if `bridgeTransferFrom` succeeds', async () => {
 | 
			
		||||
            await testProxyContract
 | 
			
		||||
                .transferFrom(assetData, accountOwner, receiver, defaultAmount)
 | 
			
		||||
                .awaitTransactionSuccessAsync({ from: authorized });
 | 
			
		||||
        });
 | 
			
		||||
        it('should revert if `bridgeTransferFrom` reverts', async () => {
 | 
			
		||||
            // Set revert flag.
 | 
			
		||||
            await testContract.setRevertOnOperate(true).awaitTransactionSuccessAsync();
 | 
			
		||||
            const tx = testProxyContract
 | 
			
		||||
                .transferFrom(assetData, accountOwner, receiver, defaultAmount)
 | 
			
		||||
                .awaitTransactionSuccessAsync({ from: authorized });
 | 
			
		||||
            const expectedError = 'TestDydxBridge/SHOULD_REVERT_ON_OPERATE';
 | 
			
		||||
            return expect(tx).to.revertWith(expectedError);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										1849
									
								
								contracts/asset-proxy/test/erc1155_proxy.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1849
									
								
								contracts/asset-proxy/test/erc1155_proxy.ts
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										287
									
								
								contracts/asset-proxy/test/erc20bridge_proxy.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										287
									
								
								contracts/asset-proxy/test/erc20bridge_proxy.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,287 @@
 | 
			
		||||
import {
 | 
			
		||||
    blockchainTests,
 | 
			
		||||
    constants,
 | 
			
		||||
    expect,
 | 
			
		||||
    getRandomInteger,
 | 
			
		||||
    Numberish,
 | 
			
		||||
    randomAddress,
 | 
			
		||||
} from '@0x/contracts-test-utils';
 | 
			
		||||
import { AuthorizableRevertErrors } from '@0x/contracts-utils';
 | 
			
		||||
import { AssetProxyId } from '@0x/types';
 | 
			
		||||
import { AbiEncoder, BigNumber, hexUtils, StringRevertError } from '@0x/utils';
 | 
			
		||||
import { DecodedLogs } from 'ethereum-types';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
import { artifacts } from './artifacts';
 | 
			
		||||
 | 
			
		||||
import { ERC20BridgeProxyContract, TestERC20BridgeContract } from './wrappers';
 | 
			
		||||
 | 
			
		||||
blockchainTests.resets('ERC20BridgeProxy unit tests', env => {
 | 
			
		||||
    const PROXY_ID = AssetProxyId.ERC20Bridge;
 | 
			
		||||
    const BRIDGE_SUCCESS_RETURN_DATA = hexUtils.rightPad(PROXY_ID);
 | 
			
		||||
    let owner: string;
 | 
			
		||||
    let badCaller: string;
 | 
			
		||||
    let assetProxy: ERC20BridgeProxyContract;
 | 
			
		||||
    let bridgeContract: TestERC20BridgeContract;
 | 
			
		||||
    let testTokenAddress: string;
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        [owner, badCaller] = await env.getAccountAddressesAsync();
 | 
			
		||||
        assetProxy = await ERC20BridgeProxyContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.ERC20BridgeProxy,
 | 
			
		||||
            env.provider,
 | 
			
		||||
            env.txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
        bridgeContract = await TestERC20BridgeContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.TestERC20Bridge,
 | 
			
		||||
            env.provider,
 | 
			
		||||
            env.txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
        testTokenAddress = await bridgeContract.testToken().callAsync();
 | 
			
		||||
        await assetProxy.addAuthorizedAddress(owner).awaitTransactionSuccessAsync();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    interface AssetDataOpts {
 | 
			
		||||
        tokenAddress: string;
 | 
			
		||||
        bridgeAddress: string;
 | 
			
		||||
        bridgeData: BridgeDataOpts;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    interface BridgeDataOpts {
 | 
			
		||||
        transferAmount: Numberish;
 | 
			
		||||
        revertError?: string;
 | 
			
		||||
        returnData: string;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function createAssetData(opts?: Partial<AssetDataOpts>): AssetDataOpts {
 | 
			
		||||
        return _.merge(
 | 
			
		||||
            {
 | 
			
		||||
                tokenAddress: testTokenAddress,
 | 
			
		||||
                bridgeAddress: bridgeContract.address,
 | 
			
		||||
                bridgeData: createBridgeData(),
 | 
			
		||||
            },
 | 
			
		||||
            opts,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function createBridgeData(opts?: Partial<BridgeDataOpts>): BridgeDataOpts {
 | 
			
		||||
        return _.merge(
 | 
			
		||||
            {
 | 
			
		||||
                transferAmount: constants.ZERO_AMOUNT,
 | 
			
		||||
                returnData: BRIDGE_SUCCESS_RETURN_DATA,
 | 
			
		||||
            },
 | 
			
		||||
            opts,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function encodeAssetData(opts: AssetDataOpts): string {
 | 
			
		||||
        const encoder = AbiEncoder.createMethod('ERC20BridgeProxy', [
 | 
			
		||||
            { name: 'tokenAddress', type: 'address' },
 | 
			
		||||
            { name: 'bridgeAddress', type: 'address' },
 | 
			
		||||
            { name: 'bridgeData', type: 'bytes' },
 | 
			
		||||
        ]);
 | 
			
		||||
        return encoder.encode([opts.tokenAddress, opts.bridgeAddress, encodeBridgeData(opts.bridgeData)]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function encodeBridgeData(opts: BridgeDataOpts): string {
 | 
			
		||||
        const encoder = AbiEncoder.create([
 | 
			
		||||
            { name: 'transferAmount', type: 'int256' },
 | 
			
		||||
            { name: 'revertData', type: 'bytes' },
 | 
			
		||||
            { name: 'returnData', type: 'bytes' },
 | 
			
		||||
        ]);
 | 
			
		||||
        const revertErrorBytes =
 | 
			
		||||
            opts.revertError !== undefined ? new StringRevertError(opts.revertError).encode() : '0x';
 | 
			
		||||
        return encoder.encode([new BigNumber(opts.transferAmount), revertErrorBytes, opts.returnData]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async function setTestTokenBalanceAsync(_owner: string, balance: Numberish): Promise<void> {
 | 
			
		||||
        await bridgeContract.setTestTokenBalance(_owner, new BigNumber(balance)).awaitTransactionSuccessAsync();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    describe('transferFrom()', () => {
 | 
			
		||||
        interface TransferFromOpts {
 | 
			
		||||
            assetData: AssetDataOpts;
 | 
			
		||||
            from: string;
 | 
			
		||||
            to: string;
 | 
			
		||||
            amount: Numberish;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function createTransferFromOpts(opts?: Partial<TransferFromOpts>): TransferFromOpts {
 | 
			
		||||
            const transferAmount = _.get(opts, ['amount'], getRandomInteger(1, 100e18)) as BigNumber;
 | 
			
		||||
            return _.merge(
 | 
			
		||||
                {
 | 
			
		||||
                    assetData: createAssetData({
 | 
			
		||||
                        bridgeData: createBridgeData({
 | 
			
		||||
                            transferAmount,
 | 
			
		||||
                        }),
 | 
			
		||||
                    }),
 | 
			
		||||
                    from: randomAddress(),
 | 
			
		||||
                    to: randomAddress(),
 | 
			
		||||
                    amount: transferAmount,
 | 
			
		||||
                },
 | 
			
		||||
                opts,
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        async function transferFromAsync(opts?: Partial<TransferFromOpts>, caller?: string): Promise<DecodedLogs> {
 | 
			
		||||
            const _opts = createTransferFromOpts(opts);
 | 
			
		||||
            const { logs } = await assetProxy
 | 
			
		||||
                .transferFrom(encodeAssetData(_opts.assetData), _opts.from, _opts.to, new BigNumber(_opts.amount))
 | 
			
		||||
                .awaitTransactionSuccessAsync({ from: caller });
 | 
			
		||||
            return (logs as any) as DecodedLogs;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        it('succeeds if the bridge succeeds and balance increases by `amount`', async () => {
 | 
			
		||||
            const tx = transferFromAsync();
 | 
			
		||||
            return expect(tx).to.be.fulfilled('');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('succeeds if balance increases more than `amount`', async () => {
 | 
			
		||||
            const amount = getRandomInteger(1, 100e18);
 | 
			
		||||
            const tx = transferFromAsync({
 | 
			
		||||
                amount,
 | 
			
		||||
                assetData: createAssetData({
 | 
			
		||||
                    bridgeData: createBridgeData({
 | 
			
		||||
                        transferAmount: amount.plus(1),
 | 
			
		||||
                    }),
 | 
			
		||||
                }),
 | 
			
		||||
            });
 | 
			
		||||
            return expect(tx).to.be.fulfilled('');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('passes the correct arguments to the bridge contract', async () => {
 | 
			
		||||
            const opts = createTransferFromOpts();
 | 
			
		||||
            const logs = await transferFromAsync(opts);
 | 
			
		||||
            expect(logs.length).to.eq(1);
 | 
			
		||||
            const args = logs[0].args;
 | 
			
		||||
            expect(args.tokenAddress).to.eq(opts.assetData.tokenAddress);
 | 
			
		||||
            expect(args.from).to.eq(opts.from);
 | 
			
		||||
            expect(args.to).to.eq(opts.to);
 | 
			
		||||
            expect(args.amount).to.bignumber.eq(opts.amount);
 | 
			
		||||
            expect(args.bridgeData).to.eq(encodeBridgeData(opts.assetData.bridgeData));
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if not called by an authorized address', async () => {
 | 
			
		||||
            const tx = transferFromAsync({}, badCaller);
 | 
			
		||||
            return expect(tx).to.revertWith(new AuthorizableRevertErrors.SenderNotAuthorizedError(badCaller));
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if asset data is truncated', async () => {
 | 
			
		||||
            const opts = createTransferFromOpts();
 | 
			
		||||
            const truncatedAssetData = hexUtils.slice(encodeAssetData(opts.assetData), 0, -1);
 | 
			
		||||
            const tx = assetProxy
 | 
			
		||||
                .transferFrom(truncatedAssetData, opts.from, opts.to, new BigNumber(opts.amount))
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            return expect(tx).to.be.rejected();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if bridge returns nothing', async () => {
 | 
			
		||||
            const tx = transferFromAsync({
 | 
			
		||||
                assetData: createAssetData({
 | 
			
		||||
                    bridgeData: createBridgeData({
 | 
			
		||||
                        returnData: '0x',
 | 
			
		||||
                    }),
 | 
			
		||||
                }),
 | 
			
		||||
            });
 | 
			
		||||
            // This will actually revert when the AP tries to decode the return
 | 
			
		||||
            // value.
 | 
			
		||||
            return expect(tx).to.be.rejected();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if bridge returns true', async () => {
 | 
			
		||||
            const tx = transferFromAsync({
 | 
			
		||||
                assetData: createAssetData({
 | 
			
		||||
                    bridgeData: createBridgeData({
 | 
			
		||||
                        returnData: hexUtils.leftPad('0x1'),
 | 
			
		||||
                    }),
 | 
			
		||||
                }),
 | 
			
		||||
            });
 | 
			
		||||
            // This will actually revert when the AP tries to decode the return
 | 
			
		||||
            // value.
 | 
			
		||||
            return expect(tx).to.be.rejected();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if bridge returns 0x1', async () => {
 | 
			
		||||
            const tx = transferFromAsync({
 | 
			
		||||
                assetData: createAssetData({
 | 
			
		||||
                    bridgeData: createBridgeData({
 | 
			
		||||
                        returnData: hexUtils.rightPad('0x1'),
 | 
			
		||||
                    }),
 | 
			
		||||
                }),
 | 
			
		||||
            });
 | 
			
		||||
            return expect(tx).to.revertWith('BRIDGE_FAILED');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if bridge is an EOA', async () => {
 | 
			
		||||
            const tx = transferFromAsync({
 | 
			
		||||
                assetData: createAssetData({
 | 
			
		||||
                    bridgeAddress: randomAddress(),
 | 
			
		||||
                }),
 | 
			
		||||
            });
 | 
			
		||||
            // This will actually revert when the AP tries to decode the return
 | 
			
		||||
            // value.
 | 
			
		||||
            return expect(tx).to.be.rejected();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if bridge reverts', async () => {
 | 
			
		||||
            const revertError = 'FOOBAR';
 | 
			
		||||
            const tx = transferFromAsync({
 | 
			
		||||
                assetData: createAssetData({
 | 
			
		||||
                    bridgeData: createBridgeData({
 | 
			
		||||
                        revertError,
 | 
			
		||||
                    }),
 | 
			
		||||
                }),
 | 
			
		||||
            });
 | 
			
		||||
            return expect(tx).to.revertWith(revertError);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if balance of `to` increases by less than `amount`', async () => {
 | 
			
		||||
            const amount = getRandomInteger(1, 100e18);
 | 
			
		||||
            const tx = transferFromAsync({
 | 
			
		||||
                amount,
 | 
			
		||||
                assetData: createAssetData({
 | 
			
		||||
                    bridgeData: createBridgeData({
 | 
			
		||||
                        transferAmount: amount.minus(1),
 | 
			
		||||
                    }),
 | 
			
		||||
                }),
 | 
			
		||||
            });
 | 
			
		||||
            return expect(tx).to.revertWith('BRIDGE_UNDERPAY');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if balance of `to` decreases', async () => {
 | 
			
		||||
            const toAddress = randomAddress();
 | 
			
		||||
            await setTestTokenBalanceAsync(toAddress, 1e18);
 | 
			
		||||
            const tx = transferFromAsync({
 | 
			
		||||
                to: toAddress,
 | 
			
		||||
                assetData: createAssetData({
 | 
			
		||||
                    bridgeData: createBridgeData({
 | 
			
		||||
                        transferAmount: -1,
 | 
			
		||||
                    }),
 | 
			
		||||
                }),
 | 
			
		||||
            });
 | 
			
		||||
            return expect(tx).to.revertWith('BRIDGE_UNDERPAY');
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('balanceOf()', () => {
 | 
			
		||||
        it('retrieves the balance of the encoded token', async () => {
 | 
			
		||||
            const _owner = randomAddress();
 | 
			
		||||
            const balance = getRandomInteger(1, 100e18);
 | 
			
		||||
            await bridgeContract.setTestTokenBalance(_owner, balance).awaitTransactionSuccessAsync();
 | 
			
		||||
            const assetData = createAssetData({
 | 
			
		||||
                tokenAddress: testTokenAddress,
 | 
			
		||||
            });
 | 
			
		||||
            const actualBalance = await assetProxy.balanceOf(encodeAssetData(assetData), _owner).callAsync();
 | 
			
		||||
            expect(actualBalance).to.bignumber.eq(balance);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('getProxyId()', () => {
 | 
			
		||||
        it('returns the correct proxy ID', async () => {
 | 
			
		||||
            const proxyId = await assetProxy.getProxyId().callAsync();
 | 
			
		||||
            expect(proxyId).to.eq(PROXY_ID);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										191
									
								
								contracts/asset-proxy/test/eth2dai_bridge.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								contracts/asset-proxy/test/eth2dai_bridge.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,191 @@
 | 
			
		||||
import {
 | 
			
		||||
    blockchainTests,
 | 
			
		||||
    constants,
 | 
			
		||||
    expect,
 | 
			
		||||
    filterLogsToArguments,
 | 
			
		||||
    getRandomInteger,
 | 
			
		||||
    Numberish,
 | 
			
		||||
    randomAddress,
 | 
			
		||||
} from '@0x/contracts-test-utils';
 | 
			
		||||
import { AssetProxyId } from '@0x/types';
 | 
			
		||||
import { BigNumber, hexUtils, RawRevertError } from '@0x/utils';
 | 
			
		||||
import { DecodedLogs } from 'ethereum-types';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
import { artifacts } from './artifacts';
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
    TestEth2DaiBridgeContract,
 | 
			
		||||
    TestEth2DaiBridgeEvents,
 | 
			
		||||
    TestEth2DaiBridgeSellAllAmountEventArgs,
 | 
			
		||||
    TestEth2DaiBridgeTokenApproveEventArgs,
 | 
			
		||||
    TestEth2DaiBridgeTokenTransferEventArgs,
 | 
			
		||||
} from './wrappers';
 | 
			
		||||
 | 
			
		||||
blockchainTests.resets('Eth2DaiBridge unit tests', env => {
 | 
			
		||||
    let testContract: TestEth2DaiBridgeContract;
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        testContract = await TestEth2DaiBridgeContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.TestEth2DaiBridge,
 | 
			
		||||
            env.provider,
 | 
			
		||||
            env.txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('isValidSignature()', () => {
 | 
			
		||||
        it('returns success bytes', async () => {
 | 
			
		||||
            const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
 | 
			
		||||
            const result = await testContract
 | 
			
		||||
                .isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32)))
 | 
			
		||||
                .callAsync();
 | 
			
		||||
            expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('bridgeTransferFrom()', () => {
 | 
			
		||||
        interface WithdrawToOpts {
 | 
			
		||||
            toTokenAddress?: string;
 | 
			
		||||
            fromTokenAddress?: string;
 | 
			
		||||
            toAddress: string;
 | 
			
		||||
            amount: Numberish;
 | 
			
		||||
            fromTokenBalance: Numberish;
 | 
			
		||||
            revertReason: string;
 | 
			
		||||
            fillAmount: Numberish;
 | 
			
		||||
            toTokentransferRevertReason: string;
 | 
			
		||||
            toTokenTransferReturnData: string;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        interface WithdrawToResult {
 | 
			
		||||
            opts: WithdrawToOpts;
 | 
			
		||||
            result: string;
 | 
			
		||||
            logs: DecodedLogs;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function createWithdrawToOpts(opts?: Partial<WithdrawToOpts>): WithdrawToOpts {
 | 
			
		||||
            return {
 | 
			
		||||
                toAddress: randomAddress(),
 | 
			
		||||
                amount: getRandomInteger(1, 100e18),
 | 
			
		||||
                revertReason: '',
 | 
			
		||||
                fillAmount: getRandomInteger(1, 100e18),
 | 
			
		||||
                fromTokenBalance: getRandomInteger(1, 100e18),
 | 
			
		||||
                toTokentransferRevertReason: '',
 | 
			
		||||
                toTokenTransferReturnData: hexUtils.leftPad(1),
 | 
			
		||||
                ...opts,
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        async function withdrawToAsync(opts?: Partial<WithdrawToOpts>): Promise<WithdrawToResult> {
 | 
			
		||||
            const _opts = createWithdrawToOpts(opts);
 | 
			
		||||
            // Set the fill behavior.
 | 
			
		||||
            await testContract
 | 
			
		||||
                .setFillBehavior(_opts.revertReason, new BigNumber(_opts.fillAmount))
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            // Create tokens and balances.
 | 
			
		||||
            if (_opts.fromTokenAddress === undefined) {
 | 
			
		||||
                const createTokenFn = testContract.createToken(new BigNumber(_opts.fromTokenBalance));
 | 
			
		||||
                _opts.fromTokenAddress = await createTokenFn.callAsync();
 | 
			
		||||
                await createTokenFn.awaitTransactionSuccessAsync();
 | 
			
		||||
            }
 | 
			
		||||
            if (_opts.toTokenAddress === undefined) {
 | 
			
		||||
                const createTokenFn = testContract.createToken(constants.ZERO_AMOUNT);
 | 
			
		||||
                _opts.toTokenAddress = await createTokenFn.callAsync();
 | 
			
		||||
                await createTokenFn.awaitTransactionSuccessAsync();
 | 
			
		||||
            }
 | 
			
		||||
            // Set the transfer behavior of `toTokenAddress`.
 | 
			
		||||
            await testContract
 | 
			
		||||
                .setTransferBehavior(
 | 
			
		||||
                    _opts.toTokenAddress,
 | 
			
		||||
                    _opts.toTokentransferRevertReason,
 | 
			
		||||
                    _opts.toTokenTransferReturnData,
 | 
			
		||||
                )
 | 
			
		||||
                .awaitTransactionSuccessAsync();
 | 
			
		||||
            // Call bridgeTransferFrom().
 | 
			
		||||
            const bridgeTransferFromFn = testContract.bridgeTransferFrom(
 | 
			
		||||
                // "to" token address
 | 
			
		||||
                _opts.toTokenAddress,
 | 
			
		||||
                // Random from address.
 | 
			
		||||
                randomAddress(),
 | 
			
		||||
                // To address.
 | 
			
		||||
                _opts.toAddress,
 | 
			
		||||
                new BigNumber(_opts.amount),
 | 
			
		||||
                // ABI-encode the "from" token address as the bridge data.
 | 
			
		||||
                hexUtils.leftPad(_opts.fromTokenAddress as string),
 | 
			
		||||
            );
 | 
			
		||||
            const result = await bridgeTransferFromFn.callAsync();
 | 
			
		||||
            const { logs } = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
 | 
			
		||||
            return {
 | 
			
		||||
                opts: _opts,
 | 
			
		||||
                result,
 | 
			
		||||
                logs: (logs as any) as DecodedLogs,
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        it('returns magic bytes on success', async () => {
 | 
			
		||||
            const BRIDGE_SUCCESS_RETURN_DATA = AssetProxyId.ERC20Bridge;
 | 
			
		||||
            const { result } = await withdrawToAsync();
 | 
			
		||||
            expect(result).to.eq(BRIDGE_SUCCESS_RETURN_DATA);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('calls `Eth2Dai.sellAllAmount()`', async () => {
 | 
			
		||||
            const { opts, logs } = await withdrawToAsync();
 | 
			
		||||
            const transfers = filterLogsToArguments<TestEth2DaiBridgeSellAllAmountEventArgs>(
 | 
			
		||||
                logs,
 | 
			
		||||
                TestEth2DaiBridgeEvents.SellAllAmount,
 | 
			
		||||
            );
 | 
			
		||||
            expect(transfers.length).to.eq(1);
 | 
			
		||||
            expect(transfers[0].sellToken).to.eq(opts.fromTokenAddress);
 | 
			
		||||
            expect(transfers[0].buyToken).to.eq(opts.toTokenAddress);
 | 
			
		||||
            expect(transfers[0].sellTokenAmount).to.bignumber.eq(opts.fromTokenBalance);
 | 
			
		||||
            expect(transfers[0].minimumFillAmount).to.bignumber.eq(opts.amount);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('sets an unlimited allowance on the `fromTokenAddress` token', async () => {
 | 
			
		||||
            const { opts, logs } = await withdrawToAsync();
 | 
			
		||||
            const approvals = filterLogsToArguments<TestEth2DaiBridgeTokenApproveEventArgs>(
 | 
			
		||||
                logs,
 | 
			
		||||
                TestEth2DaiBridgeEvents.TokenApprove,
 | 
			
		||||
            );
 | 
			
		||||
            expect(approvals.length).to.eq(1);
 | 
			
		||||
            expect(approvals[0].token).to.eq(opts.fromTokenAddress);
 | 
			
		||||
            expect(approvals[0].spender).to.eq(testContract.address);
 | 
			
		||||
            expect(approvals[0].allowance).to.bignumber.eq(constants.MAX_UINT256);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('transfers filled amount to `to`', async () => {
 | 
			
		||||
            const { opts, logs } = await withdrawToAsync();
 | 
			
		||||
            const transfers = filterLogsToArguments<TestEth2DaiBridgeTokenTransferEventArgs>(
 | 
			
		||||
                logs,
 | 
			
		||||
                TestEth2DaiBridgeEvents.TokenTransfer,
 | 
			
		||||
            );
 | 
			
		||||
            expect(transfers.length).to.eq(1);
 | 
			
		||||
            expect(transfers[0].token).to.eq(opts.toTokenAddress);
 | 
			
		||||
            expect(transfers[0].from).to.eq(testContract.address);
 | 
			
		||||
            expect(transfers[0].to).to.eq(opts.toAddress);
 | 
			
		||||
            expect(transfers[0].amount).to.bignumber.eq(opts.fillAmount);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if `Eth2Dai.sellAllAmount()` reverts', async () => {
 | 
			
		||||
            const opts = createWithdrawToOpts({ revertReason: 'FOOBAR' });
 | 
			
		||||
            const tx = withdrawToAsync(opts);
 | 
			
		||||
            return expect(tx).to.revertWith(opts.revertReason);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if `toTokenAddress.transfer()` reverts', async () => {
 | 
			
		||||
            const opts = createWithdrawToOpts({ toTokentransferRevertReason: 'FOOBAR' });
 | 
			
		||||
            const tx = withdrawToAsync(opts);
 | 
			
		||||
            return expect(tx).to.revertWith(opts.toTokentransferRevertReason);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('fails if `toTokenAddress.transfer()` returns false', async () => {
 | 
			
		||||
            const opts = createWithdrawToOpts({ toTokenTransferReturnData: hexUtils.leftPad(0) });
 | 
			
		||||
            const tx = withdrawToAsync(opts);
 | 
			
		||||
            return expect(tx).to.revertWith(new RawRevertError(hexUtils.leftPad(0)));
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('succeeds if `toTokenAddress.transfer()` returns true', async () => {
 | 
			
		||||
            await withdrawToAsync({ toTokenTransferReturnData: hexUtils.leftPad(1) });
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										19
									
								
								contracts/asset-proxy/test/global_hooks.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								contracts/asset-proxy/test/global_hooks.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
import { env, EnvVars } from '@0x/dev-utils';
 | 
			
		||||
 | 
			
		||||
import { coverage, profiler, provider } from '@0x/contracts-test-utils';
 | 
			
		||||
import { providerUtils } from '@0x/utils';
 | 
			
		||||
 | 
			
		||||
before('start web3 provider', () => {
 | 
			
		||||
    providerUtils.startProviderEngine(provider);
 | 
			
		||||
});
 | 
			
		||||
after('generate coverage report', async () => {
 | 
			
		||||
    if (env.parseBoolean(EnvVars.SolidityCoverage)) {
 | 
			
		||||
        const coverageSubprovider = coverage.getCoverageSubproviderSingleton();
 | 
			
		||||
        await coverageSubprovider.writeCoverageAsync();
 | 
			
		||||
    }
 | 
			
		||||
    if (env.parseBoolean(EnvVars.SolidityProfiler)) {
 | 
			
		||||
        const profilerSubprovider = profiler.getProfilerSubproviderSingleton();
 | 
			
		||||
        await profilerSubprovider.writeProfilerOutputAsync();
 | 
			
		||||
    }
 | 
			
		||||
    provider.stop();
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										284
									
								
								contracts/asset-proxy/test/kyber_bridge.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										284
									
								
								contracts/asset-proxy/test/kyber_bridge.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,284 @@
 | 
			
		||||
import {
 | 
			
		||||
    blockchainTests,
 | 
			
		||||
    constants,
 | 
			
		||||
    expect,
 | 
			
		||||
    getRandomInteger,
 | 
			
		||||
    getRandomPortion,
 | 
			
		||||
    randomAddress,
 | 
			
		||||
    verifyEventsFromLogs,
 | 
			
		||||
} from '@0x/contracts-test-utils';
 | 
			
		||||
import { AssetProxyId } from '@0x/types';
 | 
			
		||||
import { BigNumber, hexUtils } from '@0x/utils';
 | 
			
		||||
import { DecodedLogs } from 'ethereum-types';
 | 
			
		||||
import * as _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
import { artifacts } from './artifacts';
 | 
			
		||||
 | 
			
		||||
import { TestKyberBridgeContract, TestKyberBridgeEvents } from './wrappers';
 | 
			
		||||
 | 
			
		||||
// TODO(dorothy-zbornak): Tests need to be updated.
 | 
			
		||||
blockchainTests.resets.skip('KyberBridge unit tests', env => {
 | 
			
		||||
    const KYBER_ETH_ADDRESS = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee';
 | 
			
		||||
    const FROM_TOKEN_DECIMALS = 6;
 | 
			
		||||
    const TO_TOKEN_DECIMALS = 18;
 | 
			
		||||
    const FROM_TOKEN_BASE = new BigNumber(10).pow(FROM_TOKEN_DECIMALS);
 | 
			
		||||
    const TO_TOKEN_BASE = new BigNumber(10).pow(TO_TOKEN_DECIMALS);
 | 
			
		||||
    const WETH_BASE = new BigNumber(10).pow(18);
 | 
			
		||||
    const KYBER_RATE_BASE = WETH_BASE;
 | 
			
		||||
    let testContract: TestKyberBridgeContract;
 | 
			
		||||
 | 
			
		||||
    before(async () => {
 | 
			
		||||
        testContract = await TestKyberBridgeContract.deployFrom0xArtifactAsync(
 | 
			
		||||
            artifacts.TestKyberBridge,
 | 
			
		||||
            env.provider,
 | 
			
		||||
            env.txDefaults,
 | 
			
		||||
            artifacts,
 | 
			
		||||
        );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('isValidSignature()', () => {
 | 
			
		||||
        it('returns success bytes', async () => {
 | 
			
		||||
            const LEGACY_WALLET_MAGIC_VALUE = '0xb0671381';
 | 
			
		||||
            const result = await testContract
 | 
			
		||||
                .isValidSignature(hexUtils.random(), hexUtils.random(_.random(0, 32)))
 | 
			
		||||
                .callAsync();
 | 
			
		||||
            expect(result).to.eq(LEGACY_WALLET_MAGIC_VALUE);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    describe('bridgeTransferFrom()', () => {
 | 
			
		||||
        let fromTokenAddress: string;
 | 
			
		||||
        let toTokenAddress: string;
 | 
			
		||||
        let wethAddress: string;
 | 
			
		||||
 | 
			
		||||
        before(async () => {
 | 
			
		||||
            wethAddress = await testContract.weth().callAsync();
 | 
			
		||||
            fromTokenAddress = await testContract.createToken(FROM_TOKEN_DECIMALS).callAsync();
 | 
			
		||||
            await testContract.createToken(FROM_TOKEN_DECIMALS).awaitTransactionSuccessAsync();
 | 
			
		||||
            toTokenAddress = await testContract.createToken(TO_TOKEN_DECIMALS).callAsync();
 | 
			
		||||
            await testContract.createToken(TO_TOKEN_DECIMALS).awaitTransactionSuccessAsync();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        const STATIC_KYBER_TRADE_ARGS = {
 | 
			
		||||
            maxBuyTokenAmount: constants.MAX_UINT256,
 | 
			
		||||
            walletId: constants.NULL_ADDRESS,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        interface TransferFromOpts {
 | 
			
		||||
            toTokenAddress: string;
 | 
			
		||||
            fromTokenAddress: string;
 | 
			
		||||
            toAddress: string;
 | 
			
		||||
            // Amount to pass into `bridgeTransferFrom()`
 | 
			
		||||
            amount: BigNumber;
 | 
			
		||||
            // Amount to convert in `trade()`.
 | 
			
		||||
            fillAmount: BigNumber;
 | 
			
		||||
            // Token balance of the bridge.
 | 
			
		||||
            fromTokenBalance: BigNumber;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        interface TransferFromResult {
 | 
			
		||||
            opts: TransferFromOpts;
 | 
			
		||||
            result: string;
 | 
			
		||||
            logs: DecodedLogs;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function createTransferFromOpts(opts?: Partial<TransferFromOpts>): TransferFromOpts {
 | 
			
		||||
            const amount = getRandomInteger(1, TO_TOKEN_BASE.times(100));
 | 
			
		||||
            return {
 | 
			
		||||
                fromTokenAddress,
 | 
			
		||||
                toTokenAddress,
 | 
			
		||||
                amount,
 | 
			
		||||
                toAddress: randomAddress(),
 | 
			
		||||
                fillAmount: getRandomPortion(amount),
 | 
			
		||||
                fromTokenBalance: getRandomInteger(1, FROM_TOKEN_BASE.times(100)),
 | 
			
		||||
                ...opts,
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        async function withdrawToAsync(opts?: Partial<TransferFromOpts>): Promise<TransferFromResult> {
 | 
			
		||||
            const _opts = createTransferFromOpts(opts);
 | 
			
		||||
            // Fund the contract with input tokens.
 | 
			
		||||
            await testContract
 | 
			
		||||
                .grantTokensTo(_opts.fromTokenAddress, testContract.address, _opts.fromTokenBalance)
 | 
			
		||||
                .awaitTransactionSuccessAsync({ value: _opts.fromTokenBalance });
 | 
			
		||||
            // Fund the contract with output tokens.
 | 
			
		||||
            await testContract.setNextFillAmount(_opts.fillAmount).awaitTransactionSuccessAsync({
 | 
			
		||||
                value: _opts.toTokenAddress === wethAddress ? _opts.fillAmount : constants.ZERO_AMOUNT,
 | 
			
		||||
            });
 | 
			
		||||
            // Call bridgeTransferFrom().
 | 
			
		||||
            const bridgeTransferFromFn = testContract.bridgeTransferFrom(
 | 
			
		||||
                // Output token
 | 
			
		||||
                _opts.toTokenAddress,
 | 
			
		||||
                // Random maker address.
 | 
			
		||||
                randomAddress(),
 | 
			
		||||
                // Recipient address.
 | 
			
		||||
                _opts.toAddress,
 | 
			
		||||
                // Transfer amount.
 | 
			
		||||
                _opts.amount,
 | 
			
		||||
                // ABI-encode the input token address as the bridge data.
 | 
			
		||||
                hexUtils.concat(hexUtils.leftPad(_opts.fromTokenAddress), hexUtils.leftPad(32), hexUtils.leftPad(0)),
 | 
			
		||||
            );
 | 
			
		||||
            const result = await bridgeTransferFromFn.callAsync();
 | 
			
		||||
            const { logs } = await bridgeTransferFromFn.awaitTransactionSuccessAsync();
 | 
			
		||||
            return {
 | 
			
		||||
                opts: _opts,
 | 
			
		||||
                result,
 | 
			
		||||
                logs: (logs as any) as DecodedLogs,
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function getMinimumConversionRate(opts: TransferFromOpts): BigNumber {
 | 
			
		||||
            const fromBase = opts.fromTokenAddress === wethAddress ? WETH_BASE : FROM_TOKEN_BASE;
 | 
			
		||||
            const toBase = opts.toTokenAddress === wethAddress ? WETH_BASE : TO_TOKEN_BASE;
 | 
			
		||||
            return opts.amount
 | 
			
		||||
                .div(toBase)
 | 
			
		||||
                .div(opts.fromTokenBalance.div(fromBase))
 | 
			
		||||
                .times(KYBER_RATE_BASE)
 | 
			
		||||
                .integerValue(BigNumber.ROUND_DOWN);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        it('returns magic bytes on success', async () => {
 | 
			
		||||
            const BRIDGE_SUCCESS_RETURN_DATA = AssetProxyId.ERC20Bridge;
 | 
			
		||||
            const { result } = await withdrawToAsync();
 | 
			
		||||
            expect(result).to.eq(BRIDGE_SUCCESS_RETURN_DATA);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('can trade token -> token', async () => {
 | 
			
		||||
            const { opts, logs } = await withdrawToAsync();
 | 
			
		||||
            verifyEventsFromLogs(
 | 
			
		||||
                logs,
 | 
			
		||||
                [
 | 
			
		||||
                    {
 | 
			
		||||
                        sellTokenAddress: opts.fromTokenAddress,
 | 
			
		||||
                        buyTokenAddress: opts.toTokenAddress,
 | 
			
		||||
                        sellAmount: opts.fromTokenBalance,
 | 
			
		||||
                        recipientAddress: opts.toAddress,
 | 
			
		||||
                        minConversionRate: getMinimumConversionRate(opts),
 | 
			
		||||
                        msgValue: constants.ZERO_AMOUNT,
 | 
			
		||||
                        ...STATIC_KYBER_TRADE_ARGS,
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
                TestKyberBridgeEvents.KyberBridgeTrade,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('can trade token -> ETH', async () => {
 | 
			
		||||
            const { opts, logs } = await withdrawToAsync({
 | 
			
		||||
                toTokenAddress: wethAddress,
 | 
			
		||||
            });
 | 
			
		||||
            verifyEventsFromLogs(
 | 
			
		||||
                logs,
 | 
			
		||||
                [
 | 
			
		||||
                    {
 | 
			
		||||
                        sellTokenAddress: opts.fromTokenAddress,
 | 
			
		||||
                        buyTokenAddress: KYBER_ETH_ADDRESS,
 | 
			
		||||
                        sellAmount: opts.fromTokenBalance,
 | 
			
		||||
                        recipientAddress: testContract.address,
 | 
			
		||||
                        minConversionRate: getMinimumConversionRate(opts),
 | 
			
		||||
                        msgValue: constants.ZERO_AMOUNT,
 | 
			
		||||
                        ...STATIC_KYBER_TRADE_ARGS,
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
                TestKyberBridgeEvents.KyberBridgeTrade,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('can trade ETH -> token', async () => {
 | 
			
		||||
            const { opts, logs } = await withdrawToAsync({
 | 
			
		||||
                fromTokenAddress: wethAddress,
 | 
			
		||||
            });
 | 
			
		||||
            verifyEventsFromLogs(
 | 
			
		||||
                logs,
 | 
			
		||||
                [
 | 
			
		||||
                    {
 | 
			
		||||
                        sellTokenAddress: KYBER_ETH_ADDRESS,
 | 
			
		||||
                        buyTokenAddress: opts.toTokenAddress,
 | 
			
		||||
                        sellAmount: opts.fromTokenBalance,
 | 
			
		||||
                        recipientAddress: opts.toAddress,
 | 
			
		||||
                        minConversionRate: getMinimumConversionRate(opts),
 | 
			
		||||
                        msgValue: opts.fromTokenBalance,
 | 
			
		||||
                        ...STATIC_KYBER_TRADE_ARGS,
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
                TestKyberBridgeEvents.KyberBridgeTrade,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('does nothing if bridge has no token balance', async () => {
 | 
			
		||||
            const { logs } = await withdrawToAsync({
 | 
			
		||||
                fromTokenBalance: constants.ZERO_AMOUNT,
 | 
			
		||||
            });
 | 
			
		||||
            expect(logs).to.be.length(0);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('only transfers the token if trading the same token', async () => {
 | 
			
		||||
            const { opts, logs } = await withdrawToAsync({
 | 
			
		||||
                toTokenAddress: fromTokenAddress,
 | 
			
		||||
            });
 | 
			
		||||
            verifyEventsFromLogs(
 | 
			
		||||
                logs,
 | 
			
		||||
                [
 | 
			
		||||
                    {
 | 
			
		||||
                        tokenAddress: fromTokenAddress,
 | 
			
		||||
                        ownerAddress: testContract.address,
 | 
			
		||||
                        recipientAddress: opts.toAddress,
 | 
			
		||||
                        amount: opts.fromTokenBalance,
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
                TestKyberBridgeEvents.KyberBridgeTokenTransfer,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('grants Kyber an allowance when selling non-WETH', async () => {
 | 
			
		||||
            const { opts, logs } = await withdrawToAsync();
 | 
			
		||||
            verifyEventsFromLogs(
 | 
			
		||||
                logs,
 | 
			
		||||
                [
 | 
			
		||||
                    {
 | 
			
		||||
                        tokenAddress: opts.fromTokenAddress,
 | 
			
		||||
                        ownerAddress: testContract.address,
 | 
			
		||||
                        spenderAddress: testContract.address,
 | 
			
		||||
                        allowance: constants.MAX_UINT256,
 | 
			
		||||
                    },
 | 
			
		||||
                ],
 | 
			
		||||
                TestKyberBridgeEvents.KyberBridgeTokenApprove,
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('does not grant Kyber an allowance when selling WETH', async () => {
 | 
			
		||||
            const { logs } = await withdrawToAsync({
 | 
			
		||||
                fromTokenAddress: wethAddress,
 | 
			
		||||
            });
 | 
			
		||||
            verifyEventsFromLogs(logs, [], TestKyberBridgeEvents.KyberBridgeTokenApprove);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('withdraws WETH and passes it to Kyber when selling WETH', async () => {
 | 
			
		||||
            const { opts, logs } = await withdrawToAsync({
 | 
			
		||||
                fromTokenAddress: wethAddress,
 | 
			
		||||
            });
 | 
			
		||||
            expect(logs[0].event).to.eq(TestKyberBridgeEvents.KyberBridgeWethWithdraw);
 | 
			
		||||
            expect(logs[0].args).to.deep.eq({
 | 
			
		||||
                ownerAddress: testContract.address,
 | 
			
		||||
                amount: opts.fromTokenBalance,
 | 
			
		||||
            });
 | 
			
		||||
            expect(logs[1].event).to.eq(TestKyberBridgeEvents.KyberBridgeTrade);
 | 
			
		||||
            expect(logs[1].args.msgValue).to.bignumber.eq(opts.fromTokenBalance);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        it('wraps WETH and transfers it to the recipient when buyng WETH', async () => {
 | 
			
		||||
            const { opts, logs } = await withdrawToAsync({
 | 
			
		||||
                toTokenAddress: wethAddress,
 | 
			
		||||
            });
 | 
			
		||||
            expect(logs[0].event).to.eq(TestKyberBridgeEvents.KyberBridgeTokenApprove);
 | 
			
		||||
            expect(logs[0].args.tokenAddress).to.eq(opts.fromTokenAddress);
 | 
			
		||||
            expect(logs[1].event).to.eq(TestKyberBridgeEvents.KyberBridgeTrade);
 | 
			
		||||
            expect(logs[1].args.recipientAddress).to.eq(testContract.address);
 | 
			
		||||
            expect(logs[2].event).to.eq(TestKyberBridgeEvents.KyberBridgeWethDeposit);
 | 
			
		||||
            expect(logs[2].args).to.deep.eq({
 | 
			
		||||
                msgValue: opts.fillAmount,
 | 
			
		||||
                ownerAddress: testContract.address,
 | 
			
		||||
                amount: opts.fillAmount,
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user