Compare commits
	
		
			34 Commits
		
	
	
		
			@0x/contra
			...
			protocol@b
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | bb04726e7f | ||
|  | 220ca370c2 | ||
|  | 63af4e3e98 | ||
|  | 9754e12d82 | ||
|  | d72ebed246 | ||
|  | 587fc71058 | ||
|  | 7d34e09a12 | ||
|  | 7d15baad0f | ||
|  | 1e6476ada7 | ||
|  | 1d6ca5f6b5 | ||
|  | fb249f02fc | ||
|  | fdf04ef275 | ||
|  | b0f5f634f2 | ||
|  | 6ee0108565 | ||
|  | c73097e688 | ||
|  | a2d42b07b5 | ||
|  | f9a794af93 | ||
|  | a2643674ca | ||
|  | c00ce9daac | ||
|  | c68b5d7844 | ||
|  | 09ed106d4c | ||
|  | a6b92fc658 | ||
|  | 4be4a1a30b | ||
|  | 9bede5d331 | ||
|  | b50d4aee6d | ||
|  | 55bc367bd6 | ||
|  | 7a59b7eafe | ||
|  | 9e59d41e44 | ||
|  | 475e6c7bca | ||
|  | dbc5a5293e | ||
|  | f4bd2bd0d8 | ||
|  | f1782a83ba | ||
|  | cbade0d558 | ||
|  | fe0c26387c | 
| @@ -1,25 +1,25 @@ | ||||
| version: 2 | ||||
| version: 2.1 | ||||
|  | ||||
| jobs: | ||||
|     build: | ||||
|         resource_class: medium+ | ||||
|         resource_class: large | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs10 | ||||
|             - image: node:12 | ||||
|         environment: | ||||
|             CONTRACTS_COMMIT_HASH: '9ed05f5' | ||||
|             NODE_OPTIONS: '--max-old-space-size=6442' | ||||
|         working_directory: ~/repo | ||||
|         steps: | ||||
|             - checkout | ||||
|             - run: echo 'export PATH=$HOME/CIRCLE_PROJECT_REPONAME/node_modules/.bin:$PATH' >> $BASH_ENV | ||||
|             - run: | ||||
|                   name: install-yarn | ||||
|                   command: npm install --force --global yarn@1.17.0 | ||||
|                   command: npm install --force --global yarn@1.22.0 | ||||
|             - run: | ||||
|                   name: yarn | ||||
|                   command: yarn --frozen-lockfile --ignore-engines install || yarn --frozen-lockfile --ignore-engines install | ||||
|             - setup_remote_docker | ||||
|             - run: yarn build:ci | ||||
|             - run: yarn build:ts | ||||
|             - run: yarn build:ci || yarn build:ci || yarn build:ci | ||||
|             - run: yarn build:ts || yarn build:ts || yarn build:ts | ||||
|             - save_cache: | ||||
|                   key: repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
| @@ -31,57 +31,59 @@ jobs: | ||||
|     test-exchange-ganache: | ||||
|         resource_class: medium+ | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs10 | ||||
|             - image: node:12 | ||||
|         working_directory: ~/repo | ||||
|         steps: | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - run: yarn wsrun test:circleci @0x/contracts-exchange | ||||
|             - run: yarn wsrun -p @0x/contracts-exchange -m --serial -c test:circleci | ||||
|     test-integrations-ganache: | ||||
|         resource_class: medium+ | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs10 | ||||
|             - image: node:12 | ||||
|         working_directory: ~/repo | ||||
|         steps: | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - run: yarn wsrun test:circleci @0x/contracts-integrations | ||||
|             - run: yarn wsrun -p @0x/contracts-integrations -m --serial -c test:circleci | ||||
|     test-contracts-staking-ganache: | ||||
|         resource_class: medium+ | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs10 | ||||
|             - image: node:12 | ||||
|         working_directory: ~/repo | ||||
|         steps: | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - run: yarn wsrun test:circleci @0x/contracts-staking | ||||
|             - run: yarn wsrun -p @0x/contracts-staking -m --serial -c test:circleci | ||||
|     test-contracts-extra-ganache: | ||||
|         resource_class: medium+ | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs10 | ||||
|             - image: node:12 | ||||
|         working_directory: ~/repo | ||||
|         steps: | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - run: yarn wsrun test:circleci @0x/contracts-exchange-forwarder @0x/contracts-coordinator | ||||
|             - run: yarn wsrun -p @0x/contracts-exchange-forwarder -p @0x/contracts-coordinator -m --serial -c test:circleci | ||||
|     test-contracts-rest-ganache: | ||||
|         resource_class: medium+ | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs10 | ||||
|             - image: node:12 | ||||
|         working_directory: ~/repo | ||||
|         steps: | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - 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 | ||||
|             - 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-publish: | ||||
|         resource_class: medium+ | ||||
|         resource_class: large | ||||
|         environment: | ||||
|             NODE_OPTIONS: '--max-old-space-size=6442' | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs10 | ||||
|             - image: node:12 | ||||
|             - image: 0xorg/verdaccio | ||||
|         working_directory: ~/repo | ||||
|         steps: | ||||
| @@ -95,7 +97,7 @@ jobs: | ||||
|                   path: ~/.npm/_logs | ||||
|     test-doc-generation: | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs10 | ||||
|             - image: node:12 | ||||
|         working_directory: ~/repo | ||||
|         steps: | ||||
|             - restore_cache: | ||||
| @@ -106,18 +108,18 @@ jobs: | ||||
|                   no_output_timeout: 1200 | ||||
|     test-rest: | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs10 | ||||
|             - image: node:12 | ||||
|         working_directory: ~/repo | ||||
|         steps: | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
|                       - repo-{{ .Environment.CIRCLE_SHA1 }} | ||||
|             - run: yarn wsrun test:circleci @0x/contracts-test-utils | ||||
|             - run: yarn wsrun test:circleci @0x/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 | ||||
|             - run: yarn wsrun -p @0x/contracts-test-utils -m --serial -c test:circleci | ||||
|             - run: yarn wsrun -p @0x/contract-artifacts -m --serial -c test:circleci | ||||
|             - run: yarn wsrun -p @0x/contract-wrappers-test -m --serial -c test:circleci | ||||
|             - run: yarn wsrun -p @0x/migrations -m --serial -c test:circleci | ||||
|             - run: yarn wsrun -p @0x/order-utils -m --serial -c test:circleci | ||||
|             - run: yarn wsrun -p @0x/asset-swapper -m --serial -c test:circleci | ||||
|             - save_cache: | ||||
|                   key: coverage-contract-wrappers-test-{{ .Environment.CIRCLE_SHA1 }} | ||||
|                   paths: | ||||
| @@ -134,7 +136,7 @@ jobs: | ||||
|         resource_class: large | ||||
|         working_directory: ~/repo | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs10 | ||||
|             - image: node:12 | ||||
|         steps: | ||||
|             - restore_cache: | ||||
|                   keys: | ||||
| @@ -145,7 +147,7 @@ jobs: | ||||
|             - run: yarn diff_md_docs:ci | ||||
|     submit-coverage: | ||||
|         docker: | ||||
|             - image: nikolaik/python-nodejs:python3.7-nodejs10 | ||||
|             - image: node:12 | ||||
|         working_directory: ~/repo | ||||
|         steps: | ||||
|             - restore_cache: | ||||
|   | ||||
| @@ -1,4 +1,13 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1620214333, | ||||
|         "version": "3.7.11", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1619596077, | ||||
|         "version": "3.7.10", | ||||
|   | ||||
| @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v3.7.11 - _May 5, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.7.10 - _April 28, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-asset-proxy", | ||||
|     "version": "3.7.10", | ||||
|     "version": "3.7.11", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -51,13 +51,13 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.5.2", | ||||
|         "@0x/contract-wrappers": "^13.16.0", | ||||
|         "@0x/contracts-gen": "^2.0.37", | ||||
|         "@0x/contracts-test-utils": "^5.3.25", | ||||
|         "@0x/contracts-utils": "^4.7.7", | ||||
|         "@0x/dev-utils": "^4.2.6", | ||||
|         "@0x/sol-compiler": "^4.7.2", | ||||
|         "@0x/abi-gen": "^5.6.0", | ||||
|         "@0x/contract-wrappers": "^13.16.1", | ||||
|         "@0x/contracts-gen": "^2.0.38", | ||||
|         "@0x/contracts-test-utils": "^5.4.0", | ||||
|         "@0x/contracts-utils": "^4.7.8", | ||||
|         "@0x/dev-utils": "^4.2.7", | ||||
|         "@0x/sol-compiler": "^4.7.3", | ||||
|         "@0x/ts-doc-gen": "^0.0.28", | ||||
|         "@0x/tslint-config": "^4.1.4", | ||||
|         "@types/lodash": "4.14.104", | ||||
| @@ -79,16 +79,16 @@ | ||||
|         "typescript": "4.2.2" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.3.2", | ||||
|         "@0x/contracts-erc1155": "^2.1.28", | ||||
|         "@0x/contracts-erc20": "^3.3.7", | ||||
|         "@0x/contracts-erc721": "^3.1.28", | ||||
|         "@0x/contracts-exchange-libs": "^4.3.28", | ||||
|         "@0x/order-utils": "^10.4.20", | ||||
|         "@0x/base-contract": "^6.4.0", | ||||
|         "@0x/contracts-erc1155": "^2.1.29", | ||||
|         "@0x/contracts-erc20": "^3.3.8", | ||||
|         "@0x/contracts-erc721": "^3.1.29", | ||||
|         "@0x/contracts-exchange-libs": "^4.3.29", | ||||
|         "@0x/order-utils": "^10.4.21", | ||||
|         "@0x/types": "^3.3.3", | ||||
|         "@0x/typescript-typings": "^5.2.0", | ||||
|         "@0x/utils": "^6.4.2", | ||||
|         "@0x/web3-wrapper": "^7.5.2", | ||||
|         "@0x/utils": "^6.4.3", | ||||
|         "@0x/web3-wrapper": "^7.5.3", | ||||
|         "ethereum-types": "^3.5.0", | ||||
|         "lodash": "^4.17.11" | ||||
|     }, | ||||
|   | ||||
| @@ -1,4 +1,13 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1620214333, | ||||
|         "version": "1.1.29", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1619596077, | ||||
|         "version": "1.1.28", | ||||
|   | ||||
| @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v1.1.29 - _May 5, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.1.28 - _April 28, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-broker", | ||||
|     "version": "1.1.28", | ||||
|     "version": "1.1.29", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -51,20 +51,20 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.5.2", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.10", | ||||
|         "@0x/contracts-erc20": "^3.3.7", | ||||
|         "@0x/contracts-erc721": "^3.1.28", | ||||
|         "@0x/contracts-exchange": "^3.2.29", | ||||
|         "@0x/contracts-exchange-libs": "^4.3.28", | ||||
|         "@0x/contracts-gen": "^2.0.37", | ||||
|         "@0x/contracts-test-utils": "^5.3.25", | ||||
|         "@0x/contracts-utils": "^4.7.7", | ||||
|         "@0x/sol-compiler": "^4.7.2", | ||||
|         "@0x/abi-gen": "^5.6.0", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.11", | ||||
|         "@0x/contracts-erc20": "^3.3.8", | ||||
|         "@0x/contracts-erc721": "^3.1.29", | ||||
|         "@0x/contracts-exchange": "^3.2.30", | ||||
|         "@0x/contracts-exchange-libs": "^4.3.29", | ||||
|         "@0x/contracts-gen": "^2.0.38", | ||||
|         "@0x/contracts-test-utils": "^5.4.0", | ||||
|         "@0x/contracts-utils": "^4.7.8", | ||||
|         "@0x/sol-compiler": "^4.7.3", | ||||
|         "@0x/ts-doc-gen": "^0.0.28", | ||||
|         "@0x/tslint-config": "^4.1.4", | ||||
|         "@0x/types": "^3.3.3", | ||||
|         "@0x/web3-wrapper": "^7.5.2", | ||||
|         "@0x/web3-wrapper": "^7.5.3", | ||||
|         "@types/lodash": "4.14.104", | ||||
|         "@types/mocha": "^5.2.7", | ||||
|         "@types/node": "12.12.54", | ||||
| @@ -84,10 +84,10 @@ | ||||
|         "typescript": "4.2.2" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.3.2", | ||||
|         "@0x/order-utils": "^10.4.20", | ||||
|         "@0x/base-contract": "^6.4.0", | ||||
|         "@0x/order-utils": "^10.4.21", | ||||
|         "@0x/typescript-typings": "^5.2.0", | ||||
|         "@0x/utils": "^6.4.2", | ||||
|         "@0x/utils": "^6.4.3", | ||||
|         "ethereum-types": "^3.5.0" | ||||
|     }, | ||||
|     "publishConfig": { | ||||
|   | ||||
| @@ -1,4 +1,13 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1620214333, | ||||
|         "version": "3.1.30", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1619596077, | ||||
|         "version": "3.1.29", | ||||
|   | ||||
| @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v3.1.30 - _May 5, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.1.29 - _April 28, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-coordinator", | ||||
|     "version": "3.1.29", | ||||
|     "version": "3.1.30", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -52,17 +52,17 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.5.2", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.10", | ||||
|         "@0x/contracts-dev-utils": "^1.3.27", | ||||
|         "@0x/contracts-erc20": "^3.3.7", | ||||
|         "@0x/contracts-gen": "^2.0.37", | ||||
|         "@0x/dev-utils": "^4.2.6", | ||||
|         "@0x/order-utils": "^10.4.20", | ||||
|         "@0x/sol-compiler": "^4.7.2", | ||||
|         "@0x/abi-gen": "^5.6.0", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.11", | ||||
|         "@0x/contracts-dev-utils": "^1.3.28", | ||||
|         "@0x/contracts-erc20": "^3.3.8", | ||||
|         "@0x/contracts-gen": "^2.0.38", | ||||
|         "@0x/dev-utils": "^4.2.7", | ||||
|         "@0x/order-utils": "^10.4.21", | ||||
|         "@0x/sol-compiler": "^4.7.3", | ||||
|         "@0x/ts-doc-gen": "^0.0.28", | ||||
|         "@0x/tslint-config": "^4.1.4", | ||||
|         "@0x/web3-wrapper": "^7.5.2", | ||||
|         "@0x/web3-wrapper": "^7.5.3", | ||||
|         "@types/lodash": "4.14.104", | ||||
|         "@types/mocha": "^5.2.7", | ||||
|         "@types/node": "12.12.54", | ||||
| @@ -82,16 +82,16 @@ | ||||
|         "typescript": "4.2.2" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/assert": "^3.0.26", | ||||
|         "@0x/base-contract": "^6.3.2", | ||||
|         "@0x/contract-addresses": "^6.0.0", | ||||
|         "@0x/contracts-exchange": "^3.2.29", | ||||
|         "@0x/contracts-test-utils": "^5.3.25", | ||||
|         "@0x/contracts-utils": "^4.7.7", | ||||
|         "@0x/json-schemas": "^6.1.2", | ||||
|         "@0x/assert": "^3.0.27", | ||||
|         "@0x/base-contract": "^6.4.0", | ||||
|         "@0x/contract-addresses": "^6.1.0", | ||||
|         "@0x/contracts-exchange": "^3.2.30", | ||||
|         "@0x/contracts-test-utils": "^5.4.0", | ||||
|         "@0x/contracts-utils": "^4.7.8", | ||||
|         "@0x/json-schemas": "^6.1.3", | ||||
|         "@0x/types": "^3.3.3", | ||||
|         "@0x/typescript-typings": "^5.2.0", | ||||
|         "@0x/utils": "^6.4.2", | ||||
|         "@0x/utils": "^6.4.3", | ||||
|         "ethereum-types": "^3.5.0", | ||||
|         "http-status-codes": "^1.3.2" | ||||
|     }, | ||||
|   | ||||
| @@ -1,4 +1,13 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1620214333, | ||||
|         "version": "1.3.28", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1619596077, | ||||
|         "version": "1.3.27", | ||||
|   | ||||
| @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v1.3.28 - _May 5, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.3.27 - _April 28, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-dev-utils", | ||||
|     "version": "1.3.27", | ||||
|     "version": "1.3.28", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -41,17 +41,17 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/dev-utils", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.5.2", | ||||
|         "@0x/assert": "^3.0.26", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.10", | ||||
|         "@0x/contracts-erc20": "^3.3.7", | ||||
|         "@0x/contracts-gen": "^2.0.37", | ||||
|         "@0x/contracts-test-utils": "^5.3.25", | ||||
|         "@0x/sol-compiler": "^4.7.2", | ||||
|         "@0x/abi-gen": "^5.6.0", | ||||
|         "@0x/assert": "^3.0.27", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.11", | ||||
|         "@0x/contracts-erc20": "^3.3.8", | ||||
|         "@0x/contracts-gen": "^2.0.38", | ||||
|         "@0x/contracts-test-utils": "^5.4.0", | ||||
|         "@0x/sol-compiler": "^4.7.3", | ||||
|         "@0x/ts-doc-gen": "^0.0.28", | ||||
|         "@0x/tslint-config": "^4.1.4", | ||||
|         "@0x/types": "^3.3.3", | ||||
|         "@0x/utils": "^6.4.2", | ||||
|         "@0x/utils": "^6.4.3", | ||||
|         "ethereum-types": "^3.5.0", | ||||
|         "ethers": "~4.0.4", | ||||
|         "npm-run-all": "^4.1.2", | ||||
| @@ -63,7 +63,7 @@ | ||||
|         "typescript": "4.2.2" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.3.2", | ||||
|         "@0x/base-contract": "^6.4.0", | ||||
|         "@types/node": "12.12.54" | ||||
|     }, | ||||
|     "publishConfig": { | ||||
|   | ||||
| @@ -1,4 +1,13 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1620214333, | ||||
|         "version": "2.1.29", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1619596077, | ||||
|         "version": "2.1.28", | ||||
|   | ||||
| @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v2.1.29 - _May 5, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v2.1.28 - _April 28, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-erc1155", | ||||
|     "version": "2.1.28", | ||||
|     "version": "2.1.29", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -52,11 +52,11 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.5.2", | ||||
|         "@0x/contracts-gen": "^2.0.37", | ||||
|         "@0x/contracts-utils": "^4.7.7", | ||||
|         "@0x/dev-utils": "^4.2.6", | ||||
|         "@0x/sol-compiler": "^4.7.2", | ||||
|         "@0x/abi-gen": "^5.6.0", | ||||
|         "@0x/contracts-gen": "^2.0.38", | ||||
|         "@0x/contracts-utils": "^4.7.8", | ||||
|         "@0x/dev-utils": "^4.2.7", | ||||
|         "@0x/sol-compiler": "^4.7.3", | ||||
|         "@0x/ts-doc-gen": "^0.0.28", | ||||
|         "@0x/tslint-config": "^4.1.4", | ||||
|         "@0x/types": "^3.3.3", | ||||
| @@ -80,10 +80,10 @@ | ||||
|         "typescript": "4.2.2" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.3.2", | ||||
|         "@0x/contracts-test-utils": "^5.3.25", | ||||
|         "@0x/utils": "^6.4.2", | ||||
|         "@0x/web3-wrapper": "^7.5.2", | ||||
|         "@0x/base-contract": "^6.4.0", | ||||
|         "@0x/contracts-test-utils": "^5.4.0", | ||||
|         "@0x/utils": "^6.4.3", | ||||
|         "@0x/web3-wrapper": "^7.5.3", | ||||
|         "lodash": "^4.17.11" | ||||
|     }, | ||||
|     "publishConfig": { | ||||
|   | ||||
| @@ -1,4 +1,13 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1620214333, | ||||
|         "version": "3.3.8", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1619596077, | ||||
|         "version": "3.3.7", | ||||
|   | ||||
| @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v3.3.8 - _May 5, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.3.7 - _April 28, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-erc20", | ||||
|     "version": "3.3.7", | ||||
|     "version": "3.3.8", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -51,18 +51,18 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.5.2", | ||||
|         "@0x/contracts-gen": "^2.0.37", | ||||
|         "@0x/contracts-test-utils": "^5.3.25", | ||||
|         "@0x/contracts-utils": "^4.7.7", | ||||
|         "@0x/dev-utils": "^4.2.6", | ||||
|         "@0x/sol-compiler": "^4.7.2", | ||||
|         "@0x/abi-gen": "^5.6.0", | ||||
|         "@0x/contracts-gen": "^2.0.38", | ||||
|         "@0x/contracts-test-utils": "^5.4.0", | ||||
|         "@0x/contracts-utils": "^4.7.8", | ||||
|         "@0x/dev-utils": "^4.2.7", | ||||
|         "@0x/sol-compiler": "^4.7.3", | ||||
|         "@0x/ts-doc-gen": "^0.0.28", | ||||
|         "@0x/tslint-config": "^4.1.4", | ||||
|         "@0x/types": "^3.3.3", | ||||
|         "@0x/typescript-typings": "^5.2.0", | ||||
|         "@0x/utils": "^6.4.2", | ||||
|         "@0x/web3-wrapper": "^7.5.2", | ||||
|         "@0x/utils": "^6.4.3", | ||||
|         "@0x/web3-wrapper": "^7.5.3", | ||||
|         "@types/lodash": "4.14.104", | ||||
|         "@types/mocha": "^5.2.7", | ||||
|         "@types/node": "12.12.54", | ||||
| @@ -82,7 +82,7 @@ | ||||
|         "typescript": "4.2.2" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.3.2" | ||||
|         "@0x/base-contract": "^6.4.0" | ||||
|     }, | ||||
|     "publishConfig": { | ||||
|         "access": "public" | ||||
|   | ||||
| @@ -1,4 +1,13 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1620214333, | ||||
|         "version": "3.1.29", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1619596077, | ||||
|         "version": "3.1.28", | ||||
|   | ||||
| @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v3.1.29 - _May 5, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.1.28 - _April 28, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-erc721", | ||||
|     "version": "3.1.28", | ||||
|     "version": "3.1.29", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -52,18 +52,18 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.5.2", | ||||
|         "@0x/contracts-gen": "^2.0.37", | ||||
|         "@0x/contracts-test-utils": "^5.3.25", | ||||
|         "@0x/contracts-utils": "^4.7.7", | ||||
|         "@0x/dev-utils": "^4.2.6", | ||||
|         "@0x/sol-compiler": "^4.7.2", | ||||
|         "@0x/abi-gen": "^5.6.0", | ||||
|         "@0x/contracts-gen": "^2.0.38", | ||||
|         "@0x/contracts-test-utils": "^5.4.0", | ||||
|         "@0x/contracts-utils": "^4.7.8", | ||||
|         "@0x/dev-utils": "^4.2.7", | ||||
|         "@0x/sol-compiler": "^4.7.3", | ||||
|         "@0x/ts-doc-gen": "^0.0.28", | ||||
|         "@0x/tslint-config": "^4.1.4", | ||||
|         "@0x/types": "^3.3.3", | ||||
|         "@0x/typescript-typings": "^5.2.0", | ||||
|         "@0x/utils": "^6.4.2", | ||||
|         "@0x/web3-wrapper": "^7.5.2", | ||||
|         "@0x/utils": "^6.4.3", | ||||
|         "@0x/web3-wrapper": "^7.5.3", | ||||
|         "@types/lodash": "4.14.104", | ||||
|         "@types/mocha": "^5.2.7", | ||||
|         "@types/node": "12.12.54", | ||||
| @@ -84,7 +84,7 @@ | ||||
|         "typescript": "4.2.2" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.3.2" | ||||
|         "@0x/base-contract": "^6.4.0" | ||||
|     }, | ||||
|     "publishConfig": { | ||||
|         "access": "public" | ||||
|   | ||||
| @@ -1,4 +1,13 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1620214333, | ||||
|         "version": "4.2.30", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1619596077, | ||||
|         "version": "4.2.29", | ||||
|   | ||||
| @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v4.2.30 - _May 5, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v4.2.29 - _April 28, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-exchange-forwarder", | ||||
|     "version": "4.2.29", | ||||
|     "version": "4.2.30", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -52,25 +52,25 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.5.2", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.10", | ||||
|         "@0x/contracts-dev-utils": "^1.3.27", | ||||
|         "@0x/contracts-erc1155": "^2.1.28", | ||||
|         "@0x/contracts-erc20": "^3.3.7", | ||||
|         "@0x/contracts-erc721": "^3.1.28", | ||||
|         "@0x/contracts-exchange": "^3.2.29", | ||||
|         "@0x/contracts-exchange-libs": "^4.3.28", | ||||
|         "@0x/contracts-gen": "^2.0.37", | ||||
|         "@0x/contracts-test-utils": "^5.3.25", | ||||
|         "@0x/contracts-utils": "^4.7.7", | ||||
|         "@0x/dev-utils": "^4.2.6", | ||||
|         "@0x/order-utils": "^10.4.20", | ||||
|         "@0x/sol-compiler": "^4.7.2", | ||||
|         "@0x/abi-gen": "^5.6.0", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.11", | ||||
|         "@0x/contracts-dev-utils": "^1.3.28", | ||||
|         "@0x/contracts-erc1155": "^2.1.29", | ||||
|         "@0x/contracts-erc20": "^3.3.8", | ||||
|         "@0x/contracts-erc721": "^3.1.29", | ||||
|         "@0x/contracts-exchange": "^3.2.30", | ||||
|         "@0x/contracts-exchange-libs": "^4.3.29", | ||||
|         "@0x/contracts-gen": "^2.0.38", | ||||
|         "@0x/contracts-test-utils": "^5.4.0", | ||||
|         "@0x/contracts-utils": "^4.7.8", | ||||
|         "@0x/dev-utils": "^4.2.7", | ||||
|         "@0x/order-utils": "^10.4.21", | ||||
|         "@0x/sol-compiler": "^4.7.3", | ||||
|         "@0x/ts-doc-gen": "^0.0.28", | ||||
|         "@0x/tslint-config": "^4.1.4", | ||||
|         "@0x/types": "^3.3.3", | ||||
|         "@0x/utils": "^6.4.2", | ||||
|         "@0x/web3-wrapper": "^7.5.2", | ||||
|         "@0x/utils": "^6.4.3", | ||||
|         "@0x/web3-wrapper": "^7.5.3", | ||||
|         "@types/lodash": "4.14.104", | ||||
|         "@types/mocha": "^5.2.7", | ||||
|         "@types/node": "12.12.54", | ||||
| @@ -90,7 +90,7 @@ | ||||
|         "typescript": "4.2.2" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.3.2", | ||||
|         "@0x/base-contract": "^6.4.0", | ||||
|         "@0x/typescript-typings": "^5.2.0", | ||||
|         "ethereum-types": "^3.5.0" | ||||
|     }, | ||||
|   | ||||
| @@ -1,4 +1,13 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1620214333, | ||||
|         "version": "4.3.29", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1619596077, | ||||
|         "version": "4.3.28", | ||||
|   | ||||
| @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v4.3.29 - _May 5, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v4.3.28 - _April 28, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-exchange-libs", | ||||
|     "version": "4.3.28", | ||||
|     "version": "4.3.29", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -52,14 +52,14 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/libs", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.5.2", | ||||
|         "@0x/contracts-gen": "^2.0.37", | ||||
|         "@0x/dev-utils": "^4.2.6", | ||||
|         "@0x/sol-compiler": "^4.7.2", | ||||
|         "@0x/subproviders": "^6.5.2", | ||||
|         "@0x/abi-gen": "^5.6.0", | ||||
|         "@0x/contracts-gen": "^2.0.38", | ||||
|         "@0x/dev-utils": "^4.2.7", | ||||
|         "@0x/sol-compiler": "^4.7.3", | ||||
|         "@0x/subproviders": "^6.5.3", | ||||
|         "@0x/ts-doc-gen": "^0.0.28", | ||||
|         "@0x/tslint-config": "^4.1.4", | ||||
|         "@0x/web3-wrapper": "^7.5.2", | ||||
|         "@0x/web3-wrapper": "^7.5.3", | ||||
|         "@types/lodash": "4.14.104", | ||||
|         "@types/mocha": "^5.2.7", | ||||
|         "@types/node": "12.12.54", | ||||
| @@ -80,13 +80,13 @@ | ||||
|         "typescript": "4.2.2" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.3.2", | ||||
|         "@0x/contracts-test-utils": "^5.3.25", | ||||
|         "@0x/contracts-utils": "^4.7.7", | ||||
|         "@0x/order-utils": "^10.4.20", | ||||
|         "@0x/base-contract": "^6.4.0", | ||||
|         "@0x/contracts-test-utils": "^5.4.0", | ||||
|         "@0x/contracts-utils": "^4.7.8", | ||||
|         "@0x/order-utils": "^10.4.21", | ||||
|         "@0x/types": "^3.3.3", | ||||
|         "@0x/typescript-typings": "^5.2.0", | ||||
|         "@0x/utils": "^6.4.2", | ||||
|         "@0x/utils": "^6.4.3", | ||||
|         "ethereum-types": "^3.5.0" | ||||
|     }, | ||||
|     "publishConfig": { | ||||
|   | ||||
| @@ -1,4 +1,13 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1620214333, | ||||
|         "version": "3.2.30", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1619596077, | ||||
|         "version": "3.2.29", | ||||
|   | ||||
| @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v3.2.30 - _May 5, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v3.2.29 - _April 28, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-exchange", | ||||
|     "version": "3.2.29", | ||||
|     "version": "3.2.30", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -52,21 +52,21 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/protocol", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.5.2", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.10", | ||||
|         "@0x/contracts-exchange-libs": "^4.3.28", | ||||
|         "@0x/contracts-gen": "^2.0.37", | ||||
|         "@0x/contracts-multisig": "^4.1.29", | ||||
|         "@0x/contracts-staking": "^2.0.36", | ||||
|         "@0x/contracts-test-utils": "^5.3.25", | ||||
|         "@0x/contracts-utils": "^4.7.7", | ||||
|         "@0x/dev-utils": "^4.2.6", | ||||
|         "@0x/sol-compiler": "^4.7.2", | ||||
|         "@0x/abi-gen": "^5.6.0", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.11", | ||||
|         "@0x/contracts-exchange-libs": "^4.3.29", | ||||
|         "@0x/contracts-gen": "^2.0.38", | ||||
|         "@0x/contracts-multisig": "^4.1.30", | ||||
|         "@0x/contracts-staking": "^2.0.37", | ||||
|         "@0x/contracts-test-utils": "^5.4.0", | ||||
|         "@0x/contracts-utils": "^4.7.8", | ||||
|         "@0x/dev-utils": "^4.2.7", | ||||
|         "@0x/sol-compiler": "^4.7.3", | ||||
|         "@0x/ts-doc-gen": "^0.0.28", | ||||
|         "@0x/tslint-config": "^4.1.4", | ||||
|         "@0x/types": "^3.3.3", | ||||
|         "@0x/typescript-typings": "^5.2.0", | ||||
|         "@0x/web3-wrapper": "^7.5.2", | ||||
|         "@0x/web3-wrapper": "^7.5.3", | ||||
|         "@types/lodash": "4.14.104", | ||||
|         "@types/mocha": "^5.2.7", | ||||
|         "@types/node": "12.12.54", | ||||
| @@ -88,13 +88,13 @@ | ||||
|         "typescript": "4.2.2" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.3.2", | ||||
|         "@0x/contracts-dev-utils": "^1.3.27", | ||||
|         "@0x/contracts-erc1155": "^2.1.28", | ||||
|         "@0x/contracts-erc20": "^3.3.7", | ||||
|         "@0x/contracts-erc721": "^3.1.28", | ||||
|         "@0x/order-utils": "^10.4.20", | ||||
|         "@0x/utils": "^6.4.2", | ||||
|         "@0x/base-contract": "^6.4.0", | ||||
|         "@0x/contracts-dev-utils": "^1.3.28", | ||||
|         "@0x/contracts-erc1155": "^2.1.29", | ||||
|         "@0x/contracts-erc20": "^3.3.8", | ||||
|         "@0x/contracts-erc721": "^3.1.29", | ||||
|         "@0x/order-utils": "^10.4.21", | ||||
|         "@0x/utils": "^6.4.3", | ||||
|         "lodash": "^4.17.11" | ||||
|     }, | ||||
|     "publishConfig": { | ||||
|   | ||||
| @@ -1,4 +1,13 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1620214333, | ||||
|         "version": "6.2.24", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1619596077, | ||||
|         "version": "6.2.23", | ||||
|   | ||||
| @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v6.2.24 - _May 5, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v6.2.23 - _April 28, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-extensions", | ||||
|     "version": "6.2.23", | ||||
|     "version": "6.2.24", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -52,23 +52,23 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.5.2", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.10", | ||||
|         "@0x/contracts-dev-utils": "^1.3.27", | ||||
|         "@0x/contracts-erc20": "^3.3.7", | ||||
|         "@0x/contracts-erc721": "^3.1.28", | ||||
|         "@0x/contracts-exchange": "^3.2.29", | ||||
|         "@0x/contracts-exchange-libs": "^4.3.28", | ||||
|         "@0x/contracts-gen": "^2.0.37", | ||||
|         "@0x/contracts-utils": "^4.7.7", | ||||
|         "@0x/dev-utils": "^4.2.6", | ||||
|         "@0x/order-utils": "^10.4.20", | ||||
|         "@0x/sol-compiler": "^4.7.2", | ||||
|         "@0x/abi-gen": "^5.6.0", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.11", | ||||
|         "@0x/contracts-dev-utils": "^1.3.28", | ||||
|         "@0x/contracts-erc20": "^3.3.8", | ||||
|         "@0x/contracts-erc721": "^3.1.29", | ||||
|         "@0x/contracts-exchange": "^3.2.30", | ||||
|         "@0x/contracts-exchange-libs": "^4.3.29", | ||||
|         "@0x/contracts-gen": "^2.0.38", | ||||
|         "@0x/contracts-utils": "^4.7.8", | ||||
|         "@0x/dev-utils": "^4.2.7", | ||||
|         "@0x/order-utils": "^10.4.21", | ||||
|         "@0x/sol-compiler": "^4.7.3", | ||||
|         "@0x/ts-doc-gen": "^0.0.28", | ||||
|         "@0x/tslint-config": "^4.1.4", | ||||
|         "@0x/types": "^3.3.3", | ||||
|         "@0x/utils": "^6.4.2", | ||||
|         "@0x/web3-wrapper": "^7.5.2", | ||||
|         "@0x/utils": "^6.4.3", | ||||
|         "@0x/web3-wrapper": "^7.5.3", | ||||
|         "@types/lodash": "4.14.104", | ||||
|         "@types/mocha": "^5.2.7", | ||||
|         "@types/node": "12.12.54", | ||||
| @@ -90,8 +90,8 @@ | ||||
|         "typescript": "4.2.2" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.3.2", | ||||
|         "@0x/contracts-test-utils": "^5.3.25", | ||||
|         "@0x/base-contract": "^6.4.0", | ||||
|         "@0x/contracts-test-utils": "^5.4.0", | ||||
|         "@0x/typescript-typings": "^5.2.0", | ||||
|         "ethereum-types": "^3.5.0" | ||||
|     }, | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-integrations", | ||||
|     "version": "2.7.37", | ||||
|     "version": "2.7.42", | ||||
|     "private": true, | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
| @@ -52,25 +52,25 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/extensions", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.5.2", | ||||
|         "@0x/contract-addresses": "^6.0.0", | ||||
|         "@0x/contract-wrappers": "^13.16.0", | ||||
|         "@0x/contracts-broker": "^1.1.28", | ||||
|         "@0x/contracts-coordinator": "^3.1.29", | ||||
|         "@0x/contracts-dev-utils": "^1.3.27", | ||||
|         "@0x/contracts-exchange-forwarder": "^4.2.29", | ||||
|         "@0x/contracts-exchange-libs": "^4.3.28", | ||||
|         "@0x/contracts-extensions": "^6.2.23", | ||||
|         "@0x/contracts-gen": "^2.0.37", | ||||
|         "@0x/contracts-utils": "^4.7.7", | ||||
|         "@0x/abi-gen": "^5.6.0", | ||||
|         "@0x/contract-addresses": "^6.1.0", | ||||
|         "@0x/contract-wrappers": "^13.16.1", | ||||
|         "@0x/contracts-broker": "^1.1.29", | ||||
|         "@0x/contracts-coordinator": "^3.1.30", | ||||
|         "@0x/contracts-dev-utils": "^1.3.28", | ||||
|         "@0x/contracts-exchange-forwarder": "^4.2.30", | ||||
|         "@0x/contracts-exchange-libs": "^4.3.29", | ||||
|         "@0x/contracts-extensions": "^6.2.24", | ||||
|         "@0x/contracts-gen": "^2.0.38", | ||||
|         "@0x/contracts-utils": "^4.7.8", | ||||
|         "@0x/coordinator-server": "^1.0.5", | ||||
|         "@0x/dev-utils": "^4.2.6", | ||||
|         "@0x/migrations": "^8.0.3", | ||||
|         "@0x/order-utils": "^10.4.20", | ||||
|         "@0x/protocol-utils": "^1.5.1", | ||||
|         "@0x/sol-compiler": "^4.7.2", | ||||
|         "@0x/dev-utils": "^4.2.7", | ||||
|         "@0x/migrations": "^8.0.6", | ||||
|         "@0x/order-utils": "^10.4.21", | ||||
|         "@0x/protocol-utils": "^1.6.0", | ||||
|         "@0x/sol-compiler": "^4.7.3", | ||||
|         "@0x/tslint-config": "^4.1.4", | ||||
|         "@0x/web3-wrapper": "^7.5.2", | ||||
|         "@0x/web3-wrapper": "^7.5.3", | ||||
|         "@azure/core-asynciterator-polyfill": "^1.0.0", | ||||
|         "@types/lodash": "4.14.104", | ||||
|         "@types/mocha": "^5.2.7", | ||||
| @@ -93,21 +93,21 @@ | ||||
|         "typescript": "4.2.2" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/asset-swapper": "^6.8.0", | ||||
|         "@0x/base-contract": "^6.3.2", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.10", | ||||
|         "@0x/contracts-erc1155": "^2.1.28", | ||||
|         "@0x/contracts-erc20": "^3.3.7", | ||||
|         "@0x/contracts-erc721": "^3.1.28", | ||||
|         "@0x/contracts-exchange": "^3.2.29", | ||||
|         "@0x/contracts-multisig": "^4.1.29", | ||||
|         "@0x/contracts-staking": "^2.0.36", | ||||
|         "@0x/contracts-test-utils": "^5.3.25", | ||||
|         "@0x/contracts-zero-ex": "^0.22.1", | ||||
|         "@0x/subproviders": "^6.5.2", | ||||
|         "@0x/asset-swapper": "^6.12.0", | ||||
|         "@0x/base-contract": "^6.4.0", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.11", | ||||
|         "@0x/contracts-erc1155": "^2.1.29", | ||||
|         "@0x/contracts-erc20": "^3.3.8", | ||||
|         "@0x/contracts-erc721": "^3.1.29", | ||||
|         "@0x/contracts-exchange": "^3.2.30", | ||||
|         "@0x/contracts-multisig": "^4.1.30", | ||||
|         "@0x/contracts-staking": "^2.0.37", | ||||
|         "@0x/contracts-test-utils": "^5.4.0", | ||||
|         "@0x/contracts-zero-ex": "^0.23.0", | ||||
|         "@0x/subproviders": "^6.5.3", | ||||
|         "@0x/types": "^3.3.3", | ||||
|         "@0x/typescript-typings": "^5.2.0", | ||||
|         "@0x/utils": "^6.4.2", | ||||
|         "@0x/utils": "^6.4.3", | ||||
|         "ethereum-types": "^3.5.0", | ||||
|         "ethereumjs-util": "^7.0.10", | ||||
|         "lodash": "^4.17.11" | ||||
|   | ||||
| @@ -1,4 +1,13 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1620214333, | ||||
|         "version": "4.1.30", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1619596077, | ||||
|         "version": "4.1.29", | ||||
|   | ||||
| @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v4.1.30 - _May 5, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v4.1.29 - _April 28, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-multisig", | ||||
|     "version": "4.1.29", | ||||
|     "version": "4.1.30", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -49,18 +49,18 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/multisig", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.5.2", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.10", | ||||
|         "@0x/contracts-erc20": "^3.3.7", | ||||
|         "@0x/contracts-gen": "^2.0.37", | ||||
|         "@0x/contracts-test-utils": "^5.3.25", | ||||
|         "@0x/contracts-utils": "^4.7.7", | ||||
|         "@0x/dev-utils": "^4.2.6", | ||||
|         "@0x/sol-compiler": "^4.7.2", | ||||
|         "@0x/abi-gen": "^5.6.0", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.11", | ||||
|         "@0x/contracts-erc20": "^3.3.8", | ||||
|         "@0x/contracts-gen": "^2.0.38", | ||||
|         "@0x/contracts-test-utils": "^5.4.0", | ||||
|         "@0x/contracts-utils": "^4.7.8", | ||||
|         "@0x/dev-utils": "^4.2.7", | ||||
|         "@0x/sol-compiler": "^4.7.3", | ||||
|         "@0x/tslint-config": "^4.1.4", | ||||
|         "@0x/types": "^3.3.3", | ||||
|         "@0x/utils": "^6.4.2", | ||||
|         "@0x/web3-wrapper": "^7.5.2", | ||||
|         "@0x/utils": "^6.4.3", | ||||
|         "@0x/web3-wrapper": "^7.5.3", | ||||
|         "@types/lodash": "4.14.104", | ||||
|         "@types/mocha": "^5.2.7", | ||||
|         "@types/node": "12.12.54", | ||||
| @@ -78,7 +78,7 @@ | ||||
|         "typescript": "4.2.2" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.3.2", | ||||
|         "@0x/base-contract": "^6.4.0", | ||||
|         "@0x/typescript-typings": "^5.2.0", | ||||
|         "ethereum-types": "^3.5.0" | ||||
|     }, | ||||
|   | ||||
| @@ -1,4 +1,14 @@ | ||||
| [ | ||||
|     { | ||||
|         "version": "2.0.37", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Patch epoch finalization issue", | ||||
|                 "pr": 221 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1620214333 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1619596077, | ||||
|         "version": "2.0.36", | ||||
|   | ||||
| @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v2.0.37 - _May 5, 2021_ | ||||
|  | ||||
|     * Patch epoch finalization issue (#221) | ||||
|  | ||||
| ## v2.0.36 - _April 28, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
							
								
								
									
										55
									
								
								contracts/staking/contracts/src/StakingPatch.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								contracts/staking/contracts/src/StakingPatch.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -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.9; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "./interfaces/IStaking.sol"; | ||||
| import "./sys/MixinParams.sol"; | ||||
| import "./stake/MixinStake.sol"; | ||||
| import "./fees/MixinExchangeFees.sol"; | ||||
|  | ||||
|  | ||||
| contract StakingPatch is | ||||
|     IStaking, | ||||
|     MixinParams, | ||||
|     MixinStake, | ||||
|     MixinExchangeFees | ||||
| { | ||||
|     /// @dev Initialize storage owned by this contract. | ||||
|     ///      This function should not be called directly. | ||||
|     ///      The StakingProxy contract will call it in `attachStakingContract()`. | ||||
|     function init() | ||||
|         public | ||||
|         onlyAuthorized | ||||
|     { | ||||
|         uint256 currentEpoch_ = currentEpoch; | ||||
|         uint256 prevEpoch = currentEpoch_.safeSub(1); | ||||
|  | ||||
|         // Patch corrupted state | ||||
|         aggregatedStatsByEpoch[prevEpoch].numPoolsToFinalize = 0; | ||||
|         this.endEpoch(); | ||||
|  | ||||
|         uint256 lastPoolId_ = 57; | ||||
|         for (uint256 i = 1; i <= lastPoolId_; i++) { | ||||
|             this.finalizePool(bytes32(i)); | ||||
|         } | ||||
|         // Ensure that current epoch's state is not corrupted | ||||
|         aggregatedStatsByEpoch[currentEpoch_].numPoolsToFinalize = 0; | ||||
|     } | ||||
| } | ||||
| @@ -53,6 +53,10 @@ contract MixinExchangeFees is | ||||
|     { | ||||
|         _assertValidProtocolFee(protocolFee); | ||||
|  | ||||
|         if (protocolFee == 0) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // Transfer the protocol fee to this address if it should be paid in | ||||
|         // WETH. | ||||
|         if (msg.value == 0) { | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-staking", | ||||
|     "version": "2.0.36", | ||||
|     "version": "2.0.37", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -41,7 +41,7 @@ | ||||
|     "config": { | ||||
|         "publicInterfaceContracts": "IStaking,IStakingEvents,IStakingProxy,IZrxVault,LibStakingRichErrors,Staking,StakingProxy,ZrxVault,TestStaking", | ||||
|         "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", | ||||
|         "abis": "./test/generated-artifacts/@(IStaking|IStakingEvents|IStakingProxy|IStorage|IStorageInit|IStructs|IZrxVault|LibCobbDouglas|LibFixedMath|LibFixedMathRichErrors|LibSafeDowncast|LibStakingRichErrors|MixinAbstract|MixinConstants|MixinCumulativeRewards|MixinDeploymentConstants|MixinExchangeFees|MixinExchangeManager|MixinFinalizer|MixinParams|MixinScheduler|MixinStake|MixinStakeBalances|MixinStakeStorage|MixinStakingPool|MixinStakingPoolRewards|MixinStorage|Staking|StakingProxy|TestAssertStorageParams|TestCobbDouglas|TestCumulativeRewardTracking|TestDelegatorRewards|TestExchangeManager|TestFinalizer|TestInitTarget|TestLibFixedMath|TestLibSafeDowncast|TestMixinCumulativeRewards|TestMixinParams|TestMixinScheduler|TestMixinStake|TestMixinStakeBalances|TestMixinStakeStorage|TestMixinStakingPool|TestMixinStakingPoolRewards|TestProtocolFees|TestProxyDestination|TestStaking|TestStakingNoWETH|TestStakingProxy|TestStakingProxyUnit|TestStorageLayoutAndConstants|ZrxVault).json" | ||||
|         "abis": "./test/generated-artifacts/@(IStaking|IStakingEvents|IStakingProxy|IStorage|IStorageInit|IStructs|IZrxVault|LibCobbDouglas|LibFixedMath|LibFixedMathRichErrors|LibSafeDowncast|LibStakingRichErrors|MixinAbstract|MixinConstants|MixinCumulativeRewards|MixinDeploymentConstants|MixinExchangeFees|MixinExchangeManager|MixinFinalizer|MixinParams|MixinScheduler|MixinStake|MixinStakeBalances|MixinStakeStorage|MixinStakingPool|MixinStakingPoolRewards|MixinStorage|Staking|StakingPatch|StakingProxy|TestAssertStorageParams|TestCobbDouglas|TestCumulativeRewardTracking|TestDelegatorRewards|TestExchangeManager|TestFinalizer|TestInitTarget|TestLibFixedMath|TestLibSafeDowncast|TestMixinCumulativeRewards|TestMixinParams|TestMixinScheduler|TestMixinStake|TestMixinStakeBalances|TestMixinStakeStorage|TestMixinStakingPool|TestMixinStakingPoolRewards|TestProtocolFees|TestProxyDestination|TestStaking|TestStakingNoWETH|TestStakingProxy|TestStakingProxyUnit|TestStorageLayoutAndConstants|ZrxVault).json" | ||||
|     }, | ||||
|     "repository": { | ||||
|         "type": "git", | ||||
| @@ -53,20 +53,20 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/tokens", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.5.2", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.10", | ||||
|         "@0x/contracts-dev-utils": "^1.3.27", | ||||
|         "@0x/contracts-erc20": "^3.3.7", | ||||
|         "@0x/contracts-exchange-libs": "^4.3.28", | ||||
|         "@0x/contracts-gen": "^2.0.37", | ||||
|         "@0x/contracts-utils": "^4.7.7", | ||||
|         "@0x/dev-utils": "^4.2.6", | ||||
|         "@0x/order-utils": "^10.4.20", | ||||
|         "@0x/sol-compiler": "^4.7.2", | ||||
|         "@0x/abi-gen": "^5.6.0", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.11", | ||||
|         "@0x/contracts-dev-utils": "^1.3.28", | ||||
|         "@0x/contracts-erc20": "^3.3.8", | ||||
|         "@0x/contracts-exchange-libs": "^4.3.29", | ||||
|         "@0x/contracts-gen": "^2.0.38", | ||||
|         "@0x/contracts-utils": "^4.7.8", | ||||
|         "@0x/dev-utils": "^4.2.7", | ||||
|         "@0x/order-utils": "^10.4.21", | ||||
|         "@0x/sol-compiler": "^4.7.3", | ||||
|         "@0x/ts-doc-gen": "^0.0.28", | ||||
|         "@0x/tslint-config": "^4.1.4", | ||||
|         "@0x/types": "^3.3.3", | ||||
|         "@0x/web3-wrapper": "^7.5.2", | ||||
|         "@0x/web3-wrapper": "^7.5.3", | ||||
|         "@types/lodash": "4.14.104", | ||||
|         "@types/node": "12.12.54", | ||||
|         "chai": "^4.0.1", | ||||
| @@ -87,10 +87,10 @@ | ||||
|         "typescript": "4.2.2" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.3.2", | ||||
|         "@0x/contracts-test-utils": "^5.3.25", | ||||
|         "@0x/base-contract": "^6.4.0", | ||||
|         "@0x/contracts-test-utils": "^5.4.0", | ||||
|         "@0x/typescript-typings": "^5.2.0", | ||||
|         "@0x/utils": "^6.4.2", | ||||
|         "@0x/utils": "^6.4.3", | ||||
|         "ethereum-types": "^3.5.0", | ||||
|         "ethereumjs-util": "^7.0.10" | ||||
|     }, | ||||
|   | ||||
| @@ -33,6 +33,7 @@ import * as MixinStakingPool from '../test/generated-artifacts/MixinStakingPool. | ||||
| import * as MixinStakingPoolRewards from '../test/generated-artifacts/MixinStakingPoolRewards.json'; | ||||
| import * as MixinStorage from '../test/generated-artifacts/MixinStorage.json'; | ||||
| import * as Staking from '../test/generated-artifacts/Staking.json'; | ||||
| import * as StakingPatch from '../test/generated-artifacts/StakingPatch.json'; | ||||
| import * as StakingProxy from '../test/generated-artifacts/StakingProxy.json'; | ||||
| import * as TestAssertStorageParams from '../test/generated-artifacts/TestAssertStorageParams.json'; | ||||
| import * as TestCobbDouglas from '../test/generated-artifacts/TestCobbDouglas.json'; | ||||
| @@ -61,6 +62,7 @@ import * as TestStorageLayoutAndConstants from '../test/generated-artifacts/Test | ||||
| import * as ZrxVault from '../test/generated-artifacts/ZrxVault.json'; | ||||
| export const artifacts = { | ||||
|     Staking: Staking as ContractArtifact, | ||||
|     StakingPatch: StakingPatch as ContractArtifact, | ||||
|     StakingProxy: StakingProxy as ContractArtifact, | ||||
|     ZrxVault: ZrxVault as ContractArtifact, | ||||
|     MixinExchangeFees: MixinExchangeFees as ContractArtifact, | ||||
|   | ||||
							
								
								
									
										66
									
								
								contracts/staking/test/patch_mainnet_test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								contracts/staking/test/patch_mainnet_test.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| import { blockchainTests, constants, expect, filterLogsToArguments } from '@0x/contracts-test-utils'; | ||||
| import { BigNumber, logUtils } from '@0x/utils'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { artifacts } from './artifacts'; | ||||
| import { StakingEvents, StakingPatchContract, StakingProxyContract, StakingProxyEvents } from './wrappers'; | ||||
|  | ||||
| const abis = _.mapValues(artifacts, v => v.compilerOutput.abi); | ||||
| const STAKING_PROXY = '0xa26e80e7dea86279c6d778d702cc413e6cffa777'; | ||||
| const STAKING_OWNER = '0x7d3455421bbc5ed534a83c88fd80387dc8271392'; | ||||
| const EXCHANGE_PROXY = '0xdef1c0ded9bec7f1a1670819833240f027b25eff'; | ||||
| blockchainTests.configure({ | ||||
|     fork: { | ||||
|         unlockedAccounts: [STAKING_OWNER, EXCHANGE_PROXY], | ||||
|     }, | ||||
| }); | ||||
|  | ||||
| blockchainTests.fork('Staking patch mainnet fork tests', env => { | ||||
|     let stakingProxyContract: StakingProxyContract; | ||||
|     let patchedStakingPatchContract: StakingPatchContract; | ||||
|  | ||||
|     before(async () => { | ||||
|         stakingProxyContract = new StakingProxyContract(STAKING_PROXY, env.provider, undefined, abis); | ||||
|         patchedStakingPatchContract = await StakingPatchContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.Staking, | ||||
|             env.provider, | ||||
|             env.txDefaults, | ||||
|             artifacts, | ||||
|         ); | ||||
|     }); | ||||
|  | ||||
|     it('Staking proxy successfully attaches to patched logic', async () => { | ||||
|         const tx = await stakingProxyContract | ||||
|             .attachStakingContract(patchedStakingPatchContract.address) | ||||
|             .awaitTransactionSuccessAsync({ from: STAKING_OWNER, gasPrice: 0 }, { shouldValidate: false }); | ||||
|         expect(filterLogsToArguments(tx.logs, StakingProxyEvents.StakingContractAttachedToProxy)).to.deep.equal([ | ||||
|             { | ||||
|                 newStakingPatchContractAddress: patchedStakingPatchContract.address, | ||||
|             }, | ||||
|         ]); | ||||
|         expect(filterLogsToArguments(tx.logs, StakingEvents.EpochEnded).length).to.equal(1); | ||||
|         expect(filterLogsToArguments(tx.logs, StakingEvents.EpochFinalized).length).to.equal(1); | ||||
|         logUtils.log(`${tx.gasUsed} gas used`); | ||||
|     }); | ||||
|  | ||||
|     it('Patched staking handles 0 gas protocol fees', async () => { | ||||
|         const staking = new StakingPatchContract(STAKING_PROXY, env.provider, undefined, abis); | ||||
|         const maker = '0x7b1886e49ab5433bb46f7258548092dc8cdca28b'; | ||||
|         const zeroFeeTx = await staking | ||||
|             .payProtocolFee(maker, constants.NULL_ADDRESS, constants.ZERO_AMOUNT) | ||||
|             .awaitTransactionSuccessAsync({ from: EXCHANGE_PROXY, gasPrice: 0 }, { shouldValidate: false }); | ||||
|         // StakingPoolEarnedRewardsInEpoch should _not_ be emitted for a zero protocol fee. | ||||
|         // tslint:disable-next-line:no-unused-expression | ||||
|         expect(filterLogsToArguments(zeroFeeTx.logs, StakingEvents.StakingPoolEarnedRewardsInEpoch)).to.be.empty; | ||||
|  | ||||
|         // Coincidentally there's some ETH in the ExchangeProxy | ||||
|         const nonZeroFeeTx = await staking | ||||
|             .payProtocolFee(maker, constants.NULL_ADDRESS, new BigNumber(1)) | ||||
|             .awaitTransactionSuccessAsync({ from: EXCHANGE_PROXY, gasPrice: 0, value: 1 }, { shouldValidate: false }); | ||||
|         // StakingPoolEarnedRewardsInEpoch _should_ be emitted for a non-zero protocol fee. | ||||
|         expect( | ||||
|             filterLogsToArguments(nonZeroFeeTx.logs, StakingEvents.StakingPoolEarnedRewardsInEpoch), | ||||
|         ).to.have.lengthOf(1); | ||||
|     }); | ||||
| }); | ||||
| // tslint:enable:no-unnecessary-type-assertion | ||||
| @@ -31,6 +31,7 @@ export * from '../test/generated-wrappers/mixin_staking_pool'; | ||||
| export * from '../test/generated-wrappers/mixin_staking_pool_rewards'; | ||||
| export * from '../test/generated-wrappers/mixin_storage'; | ||||
| export * from '../test/generated-wrappers/staking'; | ||||
| export * from '../test/generated-wrappers/staking_patch'; | ||||
| export * from '../test/generated-wrappers/staking_proxy'; | ||||
| export * from '../test/generated-wrappers/test_assert_storage_params'; | ||||
| export * from '../test/generated-wrappers/test_cobb_douglas'; | ||||
|   | ||||
| @@ -40,6 +40,7 @@ | ||||
|         "test/generated-artifacts/MixinStakingPoolRewards.json", | ||||
|         "test/generated-artifacts/MixinStorage.json", | ||||
|         "test/generated-artifacts/Staking.json", | ||||
|         "test/generated-artifacts/StakingPatch.json", | ||||
|         "test/generated-artifacts/StakingProxy.json", | ||||
|         "test/generated-artifacts/TestAssertStorageParams.json", | ||||
|         "test/generated-artifacts/TestCobbDouglas.json", | ||||
|   | ||||
| @@ -1,4 +1,14 @@ | ||||
| [ | ||||
|     { | ||||
|         "version": "5.4.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Set default ganache gas limit to 100e6", | ||||
|                 "pr": 197 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1620214333 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1619596077, | ||||
|         "version": "5.3.25", | ||||
|   | ||||
| @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v5.4.0 - _May 5, 2021_ | ||||
|  | ||||
|     * Set default ganache gas limit to 100e6 (#197) | ||||
|  | ||||
| ## v5.3.25 - _April 28, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-test-utils", | ||||
|     "version": "5.3.25", | ||||
|     "version": "5.4.0", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -34,7 +34,7 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/test-utils", | ||||
|     "devDependencies": { | ||||
|         "@0x/sol-compiler": "^4.7.2", | ||||
|         "@0x/sol-compiler": "^4.7.3", | ||||
|         "@0x/tslint-config": "^4.1.4", | ||||
|         "npm-run-all": "^4.1.2", | ||||
|         "shx": "^0.2.2", | ||||
| @@ -42,20 +42,20 @@ | ||||
|         "typescript": "4.2.2" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/assert": "^3.0.26", | ||||
|         "@0x/base-contract": "^6.3.2", | ||||
|         "@0x/contract-addresses": "^6.0.0", | ||||
|         "@0x/dev-utils": "^4.2.6", | ||||
|         "@0x/json-schemas": "^6.1.2", | ||||
|         "@0x/order-utils": "^10.4.20", | ||||
|         "@0x/sol-coverage": "^4.0.36", | ||||
|         "@0x/sol-profiler": "^4.1.26", | ||||
|         "@0x/sol-trace": "^3.0.36", | ||||
|         "@0x/subproviders": "^6.5.2", | ||||
|         "@0x/assert": "^3.0.27", | ||||
|         "@0x/base-contract": "^6.4.0", | ||||
|         "@0x/contract-addresses": "^6.1.0", | ||||
|         "@0x/dev-utils": "^4.2.7", | ||||
|         "@0x/json-schemas": "^6.1.3", | ||||
|         "@0x/order-utils": "^10.4.21", | ||||
|         "@0x/sol-coverage": "^4.0.37", | ||||
|         "@0x/sol-profiler": "^4.1.27", | ||||
|         "@0x/sol-trace": "^3.0.37", | ||||
|         "@0x/subproviders": "^6.5.3", | ||||
|         "@0x/types": "^3.3.3", | ||||
|         "@0x/typescript-typings": "^5.2.0", | ||||
|         "@0x/utils": "^6.4.2", | ||||
|         "@0x/web3-wrapper": "^7.5.2", | ||||
|         "@0x/utils": "^6.4.3", | ||||
|         "@0x/web3-wrapper": "^7.5.3", | ||||
|         "@types/bn.js": "^4.11.0", | ||||
|         "@types/js-combinatorics": "^0.5.29", | ||||
|         "@types/lodash": "4.14.104", | ||||
|   | ||||
| @@ -20,6 +20,7 @@ export let providerConfigs: Web3Config = { | ||||
|     shouldUseInProcessGanache: true, | ||||
|     shouldAllowUnlimitedContractSize: true, | ||||
|     hardfork: 'istanbul', | ||||
|     gasLimit: 100e6, | ||||
|     unlocked_accounts: [ | ||||
|         '0x6cc5f688a315f3dc28a7781717a9a798a59fda7b', | ||||
|         '0x55dc8f21d20d4c6ed3c82916a438a413ca68e335', | ||||
|   | ||||
| @@ -1,4 +1,23 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1620214333, | ||||
|         "version": "1.1.6", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "1.1.5", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Patched votingPower logic", | ||||
|                 "pr": 214 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1619825976 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1619596077, | ||||
|         "version": "1.1.4", | ||||
|   | ||||
| @@ -5,6 +5,14 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v1.1.6 - _May 5, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v1.1.5 - _April 30, 2021_ | ||||
|  | ||||
|     * Patched votingPower logic (#214) | ||||
|  | ||||
| ## v1.1.4 - _April 28, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -30,6 +30,7 @@ interface IZrxTreasury { | ||||
|         uint256 votingPeriod; | ||||
|         uint256 proposalThreshold; | ||||
|         uint256 quorumThreshold; | ||||
|         bytes32 defaultPoolId; | ||||
|     } | ||||
|  | ||||
|     struct ProposedAction { | ||||
|   | ||||
| @@ -20,8 +20,6 @@ | ||||
| pragma solidity ^0.6.12; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/v06/LibBytesV06.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol"; | ||||
| @@ -32,7 +30,6 @@ import "./IZrxTreasury.sol"; | ||||
| contract ZrxTreasury is | ||||
|     IZrxTreasury | ||||
| { | ||||
|     using LibERC20TokenV06 for IERC20TokenV06; | ||||
|     using LibSafeMathV06 for uint256; | ||||
|     using LibRichErrorsV06 for bytes; | ||||
|     using LibBytesV06 for bytes; | ||||
| @@ -52,11 +49,9 @@ contract ZrxTreasury is | ||||
|     /// @dev Initializes the ZRX treasury and creates the default | ||||
|     ///      staking pool. | ||||
|     /// @param stakingProxy_ The 0x staking proxy contract. | ||||
|     /// @param weth_ The WETH token contract. | ||||
|     /// @param params Immutable treasury parameters. | ||||
|     constructor( | ||||
|         IStaking stakingProxy_, | ||||
|         IERC20TokenV06 weth_, | ||||
|         TreasuryParameters memory params | ||||
|     ) | ||||
|         public | ||||
| @@ -66,15 +61,12 @@ contract ZrxTreasury is | ||||
|             "VOTING_PERIOD_TOO_LONG" | ||||
|         ); | ||||
|         stakingProxy = stakingProxy_; | ||||
|         DefaultPoolOperator defaultPoolOperator_ = new DefaultPoolOperator( | ||||
|             stakingProxy_, | ||||
|             weth_ | ||||
|         ); | ||||
|         defaultPoolOperator = defaultPoolOperator_; | ||||
|         defaultPoolId = defaultPoolOperator_.poolId(); | ||||
|         votingPeriod = params.votingPeriod; | ||||
|         proposalThreshold = params.proposalThreshold; | ||||
|         quorumThreshold = params.quorumThreshold; | ||||
|         defaultPoolId = params.defaultPoolId; | ||||
|         IStaking.Pool memory defaultPool = stakingProxy_.getStakingPool(params.defaultPoolId); | ||||
|         defaultPoolOperator = DefaultPoolOperator(defaultPool.operator); | ||||
|     } | ||||
|  | ||||
|     // solhint-disable | ||||
| @@ -286,6 +278,12 @@ contract ZrxTreasury is | ||||
|  | ||||
|         // Add voting power for operated staking pools. | ||||
|         for (uint256 i = 0; i != operatedPoolIds.length; i++) { | ||||
|             for (uint256 j = 0; j != i; j++) { | ||||
|                 require( | ||||
|                     operatedPoolIds[i] != operatedPoolIds[j], | ||||
|                     "getVotingPower/DUPLICATE_POOL_ID" | ||||
|                 ); | ||||
|             } | ||||
|             IStaking.Pool memory pool = stakingProxy.getStakingPool(operatedPoolIds[i]); | ||||
|             require( | ||||
|                 pool.operator == account, | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-treasury", | ||||
|     "version": "1.1.4", | ||||
|     "version": "1.1.6", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -46,14 +46,14 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/treasury", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.5.2", | ||||
|         "@0x/contract-addresses": "^6.0.0", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.10", | ||||
|         "@0x/contracts-erc20": "^3.3.7", | ||||
|         "@0x/contracts-gen": "^2.0.37", | ||||
|         "@0x/contracts-staking": "^2.0.36", | ||||
|         "@0x/contracts-test-utils": "^5.3.25", | ||||
|         "@0x/sol-compiler": "^4.7.2", | ||||
|         "@0x/abi-gen": "^5.6.0", | ||||
|         "@0x/contract-addresses": "^6.1.0", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.11", | ||||
|         "@0x/contracts-erc20": "^3.3.8", | ||||
|         "@0x/contracts-gen": "^2.0.38", | ||||
|         "@0x/contracts-staking": "^2.0.37", | ||||
|         "@0x/contracts-test-utils": "^5.4.0", | ||||
|         "@0x/sol-compiler": "^4.7.3", | ||||
|         "@0x/ts-doc-gen": "^0.0.28", | ||||
|         "@0x/tslint-config": "^4.1.4", | ||||
|         "@types/isomorphic-fetch": "^0.0.35", | ||||
| @@ -72,13 +72,13 @@ | ||||
|         "typescript": "4.2.2" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.3.2", | ||||
|         "@0x/protocol-utils": "^1.5.1", | ||||
|         "@0x/subproviders": "^6.5.2", | ||||
|         "@0x/base-contract": "^6.4.0", | ||||
|         "@0x/protocol-utils": "^1.6.0", | ||||
|         "@0x/subproviders": "^6.5.3", | ||||
|         "@0x/types": "^3.3.3", | ||||
|         "@0x/typescript-typings": "^5.2.0", | ||||
|         "@0x/utils": "^6.4.2", | ||||
|         "@0x/web3-wrapper": "^7.5.2", | ||||
|         "@0x/utils": "^6.4.3", | ||||
|         "@0x/web3-wrapper": "^7.5.3", | ||||
|         "ethereum-types": "^3.5.0", | ||||
|         "ethereumjs-util": "^7.0.10" | ||||
|     }, | ||||
|   | ||||
| @@ -28,6 +28,7 @@ blockchainTests.resets('Treasury governance', env => { | ||||
|         votingPeriod: new BigNumber(3).times(stakingConstants.ONE_DAY_IN_SECONDS), | ||||
|         proposalThreshold: new BigNumber(100), | ||||
|         quorumThreshold: new BigNumber(1000), | ||||
|         defaultPoolId: stakingConstants.INITIAL_POOL_ID, | ||||
|     }; | ||||
|     const PROPOSAL_DESCRIPTION = 'A very compelling proposal!'; | ||||
|     const TREASURY_BALANCE = constants.INITIAL_ERC20_BALANCE; | ||||
| @@ -135,6 +136,16 @@ blockchainTests.resets('Treasury governance', env => { | ||||
|             .approve(erc20ProxyContract.address, constants.INITIAL_ERC20_ALLOWANCE) | ||||
|             .awaitTransactionSuccessAsync({ from: delegator }); | ||||
|  | ||||
|         defaultPoolOperator = await DefaultPoolOperatorContract.deployFrom0xArtifactAsync( | ||||
|             artifacts.DefaultPoolOperator, | ||||
|             env.provider, | ||||
|             env.txDefaults, | ||||
|             { ...artifacts, ...erc20Artifacts }, | ||||
|             staking.address, | ||||
|             weth.address, | ||||
|         ); | ||||
|         defaultPoolId = stakingConstants.INITIAL_POOL_ID; | ||||
|  | ||||
|         const createStakingPoolTx = staking.createStakingPool(stakingConstants.PPM, false); | ||||
|         nonDefaultPoolId = await createStakingPoolTx.callAsync({ from: poolOperator }); | ||||
|         await createStakingPoolTx.awaitTransactionSuccessAsync({ from: poolOperator }); | ||||
| @@ -145,9 +156,9 @@ blockchainTests.resets('Treasury governance', env => { | ||||
|             env.txDefaults, | ||||
|             { ...artifacts, ...erc20Artifacts }, | ||||
|             staking.address, | ||||
|             weth.address, | ||||
|             TREASURY_PARAMS, | ||||
|         ); | ||||
|  | ||||
|         await zrx.mint(TREASURY_BALANCE).awaitTransactionSuccessAsync(); | ||||
|         await zrx.transfer(treasury.address, TREASURY_BALANCE).awaitTransactionSuccessAsync(); | ||||
|         actions = [ | ||||
| @@ -166,10 +177,6 @@ blockchainTests.resets('Treasury governance', env => { | ||||
|                 value: constants.ZERO_AMOUNT, | ||||
|             }, | ||||
|         ]; | ||||
|  | ||||
|         defaultPoolId = await treasury.defaultPoolId().callAsync(); | ||||
|         const defaultPoolOperatorAddress = await treasury.defaultPoolOperator().callAsync(); | ||||
|         defaultPoolOperator = new DefaultPoolOperatorContract(defaultPoolOperatorAddress, env.provider, env.txDefaults); | ||||
|     }); | ||||
|     describe('getVotingPower()', () => { | ||||
|         it('Unstaked ZRX has no voting power', async () => { | ||||
| @@ -222,6 +229,19 @@ blockchainTests.resets('Treasury governance', env => { | ||||
|             const operatorVotingPower = await treasury.getVotingPower(poolOperator, [nonDefaultPoolId]).callAsync(); | ||||
|             expect(operatorVotingPower).to.bignumber.equal(TREASURY_PARAMS.proposalThreshold.dividedBy(2)); | ||||
|         }); | ||||
|         it('Reverts if given duplicate pool IDs', async () => { | ||||
|             await staking.stake(TREASURY_PARAMS.proposalThreshold).awaitTransactionSuccessAsync({ from: delegator }); | ||||
|             await staking | ||||
|                 .moveStake( | ||||
|                     new StakeInfo(StakeStatus.Undelegated), | ||||
|                     new StakeInfo(StakeStatus.Delegated, nonDefaultPoolId), | ||||
|                     TREASURY_PARAMS.proposalThreshold, | ||||
|                 ) | ||||
|                 .awaitTransactionSuccessAsync({ from: delegator }); | ||||
|             await fastForwardToNextEpochAsync(); | ||||
|             const tx = treasury.getVotingPower(poolOperator, [nonDefaultPoolId, nonDefaultPoolId]).callAsync(); | ||||
|             return expect(tx).to.revertWith('getVotingPower/DUPLICATE_POOL_ID'); | ||||
|         }); | ||||
|         it('Correctly sums voting power delegated to multiple pools', async () => { | ||||
|             await staking | ||||
|                 .stake(TREASURY_PARAMS.proposalThreshold.times(2)) | ||||
|   | ||||
| @@ -1,4 +1,13 @@ | ||||
| [ | ||||
|     { | ||||
|         "timestamp": 1620214333, | ||||
|         "version": "4.7.8", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1619596077, | ||||
|         "version": "4.7.7", | ||||
|   | ||||
| @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v4.7.8 - _May 5, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v4.7.7 - _April 28, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-utils", | ||||
|     "version": "4.7.7", | ||||
|     "version": "4.7.8", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -50,15 +50,15 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/utils", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.5.2", | ||||
|         "@0x/contracts-gen": "^2.0.37", | ||||
|         "@0x/contracts-test-utils": "^5.3.25", | ||||
|         "@0x/dev-utils": "^4.2.6", | ||||
|         "@0x/order-utils": "^10.4.20", | ||||
|         "@0x/sol-compiler": "^4.7.2", | ||||
|         "@0x/abi-gen": "^5.6.0", | ||||
|         "@0x/contracts-gen": "^2.0.38", | ||||
|         "@0x/contracts-test-utils": "^5.4.0", | ||||
|         "@0x/dev-utils": "^4.2.7", | ||||
|         "@0x/order-utils": "^10.4.21", | ||||
|         "@0x/sol-compiler": "^4.7.3", | ||||
|         "@0x/tslint-config": "^4.1.4", | ||||
|         "@0x/types": "^3.3.3", | ||||
|         "@0x/web3-wrapper": "^7.5.2", | ||||
|         "@0x/web3-wrapper": "^7.5.3", | ||||
|         "@types/bn.js": "^4.11.0", | ||||
|         "@types/lodash": "4.14.104", | ||||
|         "@types/mocha": "^5.2.7", | ||||
| @@ -79,9 +79,9 @@ | ||||
|         "typescript": "4.2.2" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.3.2", | ||||
|         "@0x/base-contract": "^6.4.0", | ||||
|         "@0x/typescript-typings": "^5.2.0", | ||||
|         "@0x/utils": "^6.4.2", | ||||
|         "@0x/utils": "^6.4.3", | ||||
|         "bn.js": "^4.11.8", | ||||
|         "ethereum-types": "^3.5.0" | ||||
|     }, | ||||
|   | ||||
| @@ -1,4 +1,36 @@ | ||||
| [ | ||||
|     { | ||||
|         "version": "0.23.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Added ETH support to `MixinCurve`", | ||||
|                 "pr": 220 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add Balancer V2 integration", | ||||
|                 "pr": 206 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1620214333 | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1619830995, | ||||
|         "version": "0.22.3", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "timestamp": 1619825976, | ||||
|         "version": "0.22.2", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|     { | ||||
|         "version": "0.22.1", | ||||
|         "changes": [ | ||||
| @@ -25,6 +57,10 @@ | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Dependencies updated" | ||||
|             }, | ||||
|             { | ||||
|                 "note": "BSC Uniswap clones (ApeSwap, CafeSwap, CheeseSwap, JulSwap)", | ||||
|                 "pr": 208 | ||||
|             } | ||||
|         ] | ||||
|     }, | ||||
|   | ||||
| @@ -5,6 +5,19 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v0.23.0 - _May 5, 2021_ | ||||
|  | ||||
|     * Added ETH support to `MixinCurve` (#220) | ||||
|     * Add Balancer V2 integration (#206) | ||||
|  | ||||
| ## v0.22.3 - _May 1, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v0.22.2 - _April 30, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|  | ||||
| ## v0.22.1 - _April 28, 2021_ | ||||
|  | ||||
|     * bump feature version to 1.2 (#213) | ||||
| @@ -16,6 +29,7 @@ CHANGELOG | ||||
| ## v0.21.1 - _April 12, 2021_ | ||||
|  | ||||
|     * Dependencies updated | ||||
|     * BSC Uniswap clones (ApeSwap, CafeSwap, CheeseSwap, JulSwap) (#208) | ||||
|  | ||||
| ## v0.21.0 - _April 1, 2021_ | ||||
|  | ||||
|   | ||||
| @@ -37,22 +37,44 @@ contract PancakeSwapFeature is | ||||
|     /// @dev Name of this feature. | ||||
|     string public constant override FEATURE_NAME = "PancakeSwapFeature"; | ||||
|     /// @dev Version of this feature. | ||||
|     uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 1); | ||||
|     uint256 public immutable override FEATURE_VERSION = _encodeVersion(1, 0, 2); | ||||
|     /// @dev WBNB contract. | ||||
|     IEtherTokenV06 private immutable WBNB; | ||||
|  | ||||
|     // 0xFF + address of the PancakeSwap factory contract. | ||||
|     uint256 constant private FF_PANCAKESWAP_FACTORY = 0xffbcfccbde45ce874adcb698cc183debcf179528120000000000000000000000; | ||||
|     // 0xFF + address of the PancakeSwapV2 factory contract. | ||||
|     uint256 constant private FF_PANCAKESWAPV2_FACTORY = 0xffca143ce32fe78f1f7019d7d551a6402fc5350c730000000000000000000000; | ||||
|     // 0xFF + address of the BakerySwap factory contract. | ||||
|     uint256 constant private FF_BAKERYSWAP_FACTORY = 0xff01bf7c66c6bd861915cdaae475042d3c4bae16a70000000000000000000000; | ||||
|     // 0xFF + address of the SushiSwap factory contract. | ||||
|     uint256 constant private FF_SUSHISWAP_FACTORY = 0xffc35DADB65012eC5796536bD9864eD8773aBc74C40000000000000000000000; | ||||
|     // 0xFF + address of the ApeSwap factory contract. | ||||
|     uint256 constant private FF_APESWAP_FACTORY = 0xff0841bd0b734e4f5853f0dd8d7ea041c241fb0da60000000000000000000000; | ||||
|     // 0xFF + address of the CafeSwap factory contract. | ||||
|     uint256 constant private FF_CAFESWAP_FACTORY = 0xff3e708fdbe3ada63fc94f8f61811196f1302137ad0000000000000000000000; | ||||
|     // 0xFF + address of the CheeseSwap factory contract. | ||||
|     uint256 constant private FF_CHEESESWAP_FACTORY = 0xffdd538e4fd1b69b7863e1f741213276a6cf1efb3b0000000000000000000000; | ||||
|     // 0xFF + address of the JulSwap factory contract. | ||||
|     uint256 constant private FF_JULSWAP_FACTORY = 0xff553990f2cba90272390f62c5bdb1681ffc8996750000000000000000000000; | ||||
|  | ||||
|     // Init code hash of the PancakeSwap pair contract. | ||||
|     uint256 constant private PANCAKESWAP_PAIR_INIT_CODE_HASH = 0xd0d4c4cd0848c93cb4fd1f498d7013ee6bfb25783ea21593d5834f5d250ece66; | ||||
|     // Init code hash of the PancakeSwapV2 pair contract. | ||||
|     uint256 constant private PANCAKESWAPV2_PAIR_INIT_CODE_HASH = 0x00fb7f630766e6a796048ea87d01acd3068e8ff67d078148a3fa3f4a84f69bd5; | ||||
|     // Init code hash of the BakerySwap pair contract. | ||||
|     uint256 constant private BAKERYSWAP_PAIR_INIT_CODE_HASH = 0xe2e87433120e32c4738a7d8f3271f3d872cbe16241d67537139158d90bac61d3; | ||||
|     // Init code hash of the SushiSwap pair contract. | ||||
|     uint256 constant private SUSHISWAP_PAIR_INIT_CODE_HASH = 0xe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303; | ||||
|     // Init code hash of the ApeSwap pair contract. | ||||
|     uint256 constant private APESWAP_PAIR_INIT_CODE_HASH = 0xf4ccce374816856d11f00e4069e7cada164065686fbef53c6167a63ec2fd8c5b; | ||||
|     // Init code hash of the CafeSwap pair contract. | ||||
|     uint256 constant private CAFESWAP_PAIR_INIT_CODE_HASH = 0x90bcdb5d0bf0e8db3852b0b7d7e05cc8f7c6eb6d511213c5ba02d1d1dbeda8d3; | ||||
|     // Init code hash of the CheeseSwap pair contract. | ||||
|     uint256 constant private CHEESESWAP_PAIR_INIT_CODE_HASH = 0xf52c5189a89e7ca2ef4f19f2798e3900fba7a316de7cef6c5a9446621ba86286; | ||||
|     // Init code hash of the JulSwap pair contract. | ||||
|     uint256 constant private JULSWAP_PAIR_INIT_CODE_HASH = 0xb1e98e21a5335633815a8cfb3b580071c2e4561c50afd57a8746def9ed890b18; | ||||
|  | ||||
|     // Mask of the lower 20 bytes of a bytes32. | ||||
|     uint256 constant private ADDRESS_MASK = 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff; | ||||
|     // BNB pseudo-token address. | ||||
| @@ -258,7 +280,7 @@ contract PancakeSwapFeature is | ||||
|  | ||||
|                 // Call pair.swap() | ||||
|                 switch mload(0xA20) // fork | ||||
|                     case 1 { | ||||
|                     case 2 { | ||||
|                         mstore(0xB00, BAKERYSWAP_PAIR_SWAP_CALL_SELECTOR_32) | ||||
|                     } | ||||
|                     default { | ||||
| @@ -352,15 +374,40 @@ contract PancakeSwapFeature is | ||||
|                         mstore(0xB35, PANCAKESWAP_PAIR_INIT_CODE_HASH) | ||||
|                     } | ||||
|                     case 1 { | ||||
|                         mstore(0xB00, FF_PANCAKESWAPV2_FACTORY) | ||||
|                         mstore(0xB15, salt) | ||||
|                         mstore(0xB35, PANCAKESWAPV2_PAIR_INIT_CODE_HASH) | ||||
|                     } | ||||
|                     case 2 { | ||||
|                         mstore(0xB00, FF_BAKERYSWAP_FACTORY) | ||||
|                         mstore(0xB15, salt) | ||||
|                         mstore(0xB35, BAKERYSWAP_PAIR_INIT_CODE_HASH) | ||||
|                     } | ||||
|                     default { | ||||
|                     case 3 { | ||||
|                         mstore(0xB00, FF_SUSHISWAP_FACTORY) | ||||
|                         mstore(0xB15, salt) | ||||
|                         mstore(0xB35, SUSHISWAP_PAIR_INIT_CODE_HASH) | ||||
|                     } | ||||
|                     case 4 { | ||||
|                         mstore(0xB00, FF_APESWAP_FACTORY) | ||||
|                         mstore(0xB15, salt) | ||||
|                         mstore(0xB35, APESWAP_PAIR_INIT_CODE_HASH) | ||||
|                     } | ||||
|                     case 5 { | ||||
|                         mstore(0xB00, FF_CAFESWAP_FACTORY) | ||||
|                         mstore(0xB15, salt) | ||||
|                         mstore(0xB35, CAFESWAP_PAIR_INIT_CODE_HASH) | ||||
|                     } | ||||
|                     case 6 { | ||||
|                         mstore(0xB00, FF_CHEESESWAP_FACTORY) | ||||
|                         mstore(0xB15, salt) | ||||
|                         mstore(0xB35, CHEESESWAP_PAIR_INIT_CODE_HASH) | ||||
|                     } | ||||
|                     default { | ||||
|                         mstore(0xB00, FF_JULSWAP_FACTORY) | ||||
|                         mstore(0xB15, salt) | ||||
|                         mstore(0xB35, JULSWAP_PAIR_INIT_CODE_HASH) | ||||
|                     } | ||||
|                 pair := and(ADDRESS_MASK, keccak256(0xB00, 0x55)) | ||||
|             } | ||||
|  | ||||
|   | ||||
| @@ -23,16 +23,21 @@ pragma experimental ABIEncoderV2; | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; | ||||
|  | ||||
|  | ||||
| /// @dev VIP PancakeSwap/BakerySwap/SushiSwap fill functions. | ||||
| /// @dev VIP PancakeSwap (and forks) fill functions. | ||||
| interface IPancakeSwapFeature { | ||||
|  | ||||
|     enum ProtocolFork { | ||||
|         PancakeSwap, | ||||
|         PancakeSwapV2, | ||||
|         BakerySwap, | ||||
|         SushiSwap | ||||
|         SushiSwap, | ||||
|         ApeSwap, | ||||
|         CafeSwap, | ||||
|         CheeseSwap, | ||||
|         JulSwap | ||||
|     } | ||||
|  | ||||
|     /// @dev Efficiently sell directly to PancakeSwap/BakerySwap/Sushiswap. | ||||
|     /// @dev Efficiently sell directly to PancakeSwap (and forks). | ||||
|     /// @param tokens Sell path. | ||||
|     /// @param sellAmount of `tokens[0]` Amount to sell. | ||||
|     /// @param minBuyAmount Minimum amount of `tokens[-1]` to buy. | ||||
|   | ||||
| @@ -23,6 +23,7 @@ pragma experimental ABIEncoderV2; | ||||
| import "./IBridgeAdapter.sol"; | ||||
| import "./BridgeProtocols.sol"; | ||||
| import "./mixins/MixinBalancer.sol"; | ||||
| import "./mixins/MixinBalancerV2.sol"; | ||||
| import "./mixins/MixinBancor.sol"; | ||||
| import "./mixins/MixinCoFiX.sol"; | ||||
| import "./mixins/MixinCurve.sol"; | ||||
| @@ -38,11 +39,13 @@ import "./mixins/MixinOasis.sol"; | ||||
| import "./mixins/MixinShell.sol"; | ||||
| import "./mixins/MixinUniswap.sol"; | ||||
| import "./mixins/MixinUniswapV2.sol"; | ||||
| import "./mixins/MixinUniswapV3.sol"; | ||||
| import "./mixins/MixinZeroExBridge.sol"; | ||||
|  | ||||
| contract BridgeAdapter is | ||||
|     IBridgeAdapter, | ||||
|     MixinBalancer, | ||||
|     MixinBalancerV2, | ||||
|     MixinBancor, | ||||
|     MixinCoFiX, | ||||
|     MixinCurve, | ||||
| @@ -58,14 +61,16 @@ contract BridgeAdapter is | ||||
|     MixinShell, | ||||
|     MixinUniswap, | ||||
|     MixinUniswapV2, | ||||
|     MixinUniswapV3, | ||||
|     MixinZeroExBridge | ||||
| { | ||||
|     constructor(IEtherTokenV06 weth) | ||||
|         public | ||||
|         MixinBalancer() | ||||
|         MixinBalancerV2() | ||||
|         MixinBancor(weth) | ||||
|         MixinCoFiX() | ||||
|         MixinCurve() | ||||
|         MixinCurve(weth) | ||||
|         MixinCryptoCom() | ||||
|         MixinDodo() | ||||
|         MixinDodoV2() | ||||
| @@ -78,6 +83,7 @@ contract BridgeAdapter is | ||||
|         MixinShell() | ||||
|         MixinUniswap(weth) | ||||
|         MixinUniswapV2() | ||||
|         MixinUniswapV3() | ||||
|         MixinZeroExBridge() | ||||
|     {} | ||||
|  | ||||
| @@ -99,6 +105,12 @@ contract BridgeAdapter is | ||||
|                 sellAmount, | ||||
|                 order.bridgeData | ||||
|             ); | ||||
|         } else if (protocolId == BridgeProtocols.UNISWAPV3) { | ||||
|             boughtAmount = _tradeUniswapV3( | ||||
|                 sellToken, | ||||
|                 sellAmount, | ||||
|                 order.bridgeData | ||||
|             ); | ||||
|         } else if (protocolId == BridgeProtocols.UNISWAPV2) { | ||||
|             boughtAmount = _tradeUniswapV2( | ||||
|                 buyToken, | ||||
| @@ -119,6 +131,13 @@ contract BridgeAdapter is | ||||
|                 sellAmount, | ||||
|                 order.bridgeData | ||||
|             ); | ||||
|         } else if (protocolId == BridgeProtocols.BALANCERV2) { | ||||
|             boughtAmount = _tradeBalancerV2( | ||||
|                 sellToken, | ||||
|                 buyToken, | ||||
|                 sellAmount, | ||||
|                 order.bridgeData | ||||
|             ); | ||||
|         } else if (protocolId == BridgeProtocols.KYBER) { | ||||
|             boughtAmount = _tradeKyber( | ||||
|                 sellToken, | ||||
|   | ||||
| @@ -44,4 +44,6 @@ library BridgeProtocols { | ||||
|     uint128 internal constant COFIX       = 14; | ||||
|     uint128 internal constant NERVE       = 15; | ||||
|     uint128 internal constant MAKERPSM    = 16; | ||||
|     uint128 internal constant BALANCERV2  = 17; | ||||
|     uint128 internal constant UNISWAPV3   = 18; | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,117 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2020 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; | ||||
|  | ||||
|  | ||||
| interface IBalancerV2Vault { | ||||
|  | ||||
|     enum SwapKind { GIVEN_IN, GIVEN_OUT } | ||||
|     /** | ||||
|      * @dev Performs a swap with a single Pool. | ||||
|      * | ||||
|      * If the swap is given in (the number of tokens to send to the Pool is known), returns the amount of tokens | ||||
|      * taken from the Pool, which must be greater than or equal to `limit`. | ||||
|      * | ||||
|      * If the swap is given out (the number of tokens to take from the Pool is known), returns the amount of | ||||
|      * tokens sent to the Pool, which must be less than or equal to `limit`. | ||||
|      * | ||||
|      * Internal Balance usage and the recipient are determined by the `funds` struct. | ||||
|      * | ||||
|      * Emits a `Swap` event. | ||||
|      * For full documentation see https://github.com/balancer-labs/balancer-core-v2/blob/master/contracts/vault/interfaces/IVault.sol | ||||
|      */ | ||||
|     function swap( | ||||
|         SingleSwap calldata request, | ||||
|         FundManagement calldata funds, | ||||
|         uint256 limit, | ||||
|         uint256 deadline | ||||
|     ) external payable returns (uint256); | ||||
|  | ||||
|     struct SingleSwap { | ||||
|         bytes32 poolId; | ||||
|         SwapKind kind; | ||||
|         IERC20TokenV06 assetIn; | ||||
|         IERC20TokenV06 assetOut; | ||||
|         uint256 amount; | ||||
|         bytes userData; | ||||
|     } | ||||
|  | ||||
|     struct FundManagement { | ||||
|         address sender; | ||||
|         bool fromInternalBalance; | ||||
|         address payable recipient; | ||||
|         bool toInternalBalance; | ||||
|     } | ||||
| } | ||||
|  | ||||
| contract MixinBalancerV2 { | ||||
|  | ||||
|     using LibERC20TokenV06 for IERC20TokenV06; | ||||
|  | ||||
|     struct BalancerV2BridgeData { | ||||
|         IBalancerV2Vault vault; | ||||
|         bytes32 poolId; | ||||
|     } | ||||
|  | ||||
|     function _tradeBalancerV2( | ||||
|         IERC20TokenV06 sellToken, | ||||
|         IERC20TokenV06 buyToken, | ||||
|         uint256 sellAmount, | ||||
|         bytes memory bridgeData | ||||
|     ) | ||||
|         internal | ||||
|         returns (uint256 boughtAmount) | ||||
|     { | ||||
|         // Decode the bridge data. | ||||
|         BalancerV2BridgeData memory data = abi.decode(bridgeData, (BalancerV2BridgeData)); | ||||
|  | ||||
|         // Grant an allowance to the exchange to spend `fromTokenAddress` token. | ||||
|         sellToken.approveIfBelow(address(data.vault), sellAmount); | ||||
|  | ||||
|         // Sell the entire sellAmount | ||||
|         IBalancerV2Vault.SingleSwap memory request = IBalancerV2Vault.SingleSwap({ | ||||
|             poolId: data.poolId, | ||||
|             kind: IBalancerV2Vault.SwapKind.GIVEN_IN, | ||||
|             assetIn: sellToken, | ||||
|             assetOut: buyToken, | ||||
|             amount: sellAmount, // amount in | ||||
|             userData: "" | ||||
|         }); | ||||
|  | ||||
|         IBalancerV2Vault.FundManagement memory funds = IBalancerV2Vault.FundManagement({ | ||||
|             sender: address(this), | ||||
|             fromInternalBalance: false, | ||||
|             recipient: payable(address(this)), | ||||
|             toInternalBalance: false | ||||
|         }); | ||||
|  | ||||
|         boughtAmount = data.vault.swap( | ||||
|             request, | ||||
|             funds, | ||||
|             1, // min amount out | ||||
|             block.timestamp // expires after this block | ||||
|         ); | ||||
|         return boughtAmount; | ||||
|     } | ||||
| } | ||||
| @@ -21,6 +21,7 @@ pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-utils/contracts/src/v06/errors/LibRichErrorsV06.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IEtherTokenV06.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; | ||||
| import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol"; | ||||
| @@ -31,6 +32,15 @@ contract MixinCurve { | ||||
|     using LibSafeMathV06 for uint256; | ||||
|     using LibRichErrorsV06 for bytes; | ||||
|  | ||||
|     /// @dev Mainnet address of the WETH contract. | ||||
|     IEtherTokenV06 private immutable WETH; | ||||
|  | ||||
|     constructor(IEtherTokenV06 weth) | ||||
|         public | ||||
|     { | ||||
|         WETH = weth; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     struct CurveBridgeData { | ||||
|         address curveAddress; | ||||
| @@ -50,10 +60,17 @@ contract MixinCurve { | ||||
|     { | ||||
|         // Decode the bridge data to get the Curve metadata. | ||||
|         CurveBridgeData memory data = abi.decode(bridgeData, (CurveBridgeData)); | ||||
|         sellToken.approveIfBelow(data.curveAddress, sellAmount); | ||||
|         uint256 payableAmount; | ||||
|         if (sellToken == WETH) { | ||||
|             payableAmount = sellAmount; | ||||
|             WETH.withdraw(sellAmount); | ||||
|         } else { | ||||
|             sellToken.approveIfBelow(data.curveAddress, sellAmount); | ||||
|         } | ||||
|  | ||||
|         uint256 beforeBalance = buyToken.balanceOf(address(this)); | ||||
|         (bool success, bytes memory resultData) = | ||||
|             data.curveAddress.call(abi.encodeWithSelector( | ||||
|             data.curveAddress.call{value: payableAmount}(abi.encodeWithSelector( | ||||
|                 data.exchangeFunctionSelector, | ||||
|                 data.fromCoinIdx, | ||||
|                 data.toCoinIdx, | ||||
| @@ -65,6 +82,12 @@ contract MixinCurve { | ||||
|         if (!success) { | ||||
|             resultData.rrevert(); | ||||
|         } | ||||
|  | ||||
|         if (buyToken == WETH) { | ||||
|             boughtAmount = address(this).balance; | ||||
|             WETH.deposit{ value: boughtAmount }(); | ||||
|         } | ||||
|  | ||||
|         return buyToken.balanceOf(address(this)).safeSub(beforeBalance); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,70 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
|  | ||||
| /* | ||||
|  | ||||
|   Copyright 2021 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6.5; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol"; | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; | ||||
| import "../IBridgeAdapter.sol"; | ||||
|  | ||||
| interface IUniswapV3Router { | ||||
|  | ||||
|     struct ExactInputParams { | ||||
|         bytes path; | ||||
|         address recipient; | ||||
|         uint256 deadline; | ||||
|         uint256 amountIn; | ||||
|         uint256 amountOutMinimum; | ||||
|     } | ||||
|  | ||||
|     function exactInput(ExactInputParams memory params) | ||||
|         external | ||||
|         payable | ||||
|         returns (uint256 amountOut); | ||||
| } | ||||
|  | ||||
| contract MixinUniswapV3 { | ||||
|  | ||||
|     using LibERC20TokenV06 for IERC20TokenV06; | ||||
|  | ||||
|     function _tradeUniswapV3( | ||||
|         IERC20TokenV06 sellToken, | ||||
|         uint256 sellAmount, | ||||
|         bytes memory bridgeData | ||||
|     ) | ||||
|         internal | ||||
|         returns (uint256 boughtAmount) | ||||
|     { | ||||
|         (IUniswapV3Router router, bytes memory path) = | ||||
|             abi.decode(bridgeData, (IUniswapV3Router, bytes)); | ||||
|  | ||||
|         // Grant the Uniswap router an allowance to sell the sell token. | ||||
|         sellToken.approveIfBelow(address(router), sellAmount); | ||||
|  | ||||
|         boughtAmount = router.exactInput(IUniswapV3Router.ExactInputParams({ | ||||
|             path: path, | ||||
|             recipient: address(this), | ||||
|             deadline: block.timestamp, | ||||
|             amountIn: sellAmount, | ||||
|             amountOutMinimum: 1 | ||||
|         })); | ||||
|     } | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/contracts-zero-ex", | ||||
|     "version": "0.22.1", | ||||
|     "version": "0.23.0", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -43,7 +43,7 @@ | ||||
|     "config": { | ||||
|         "publicInterfaceContracts": "IZeroEx,ZeroEx,FullMigration,InitialMigration,IFlashWallet,IERC20Transformer,IOwnableFeature,ISimpleFunctionRegistryFeature,ITransformERC20Feature,FillQuoteTransformer,PayTakerTransformer,PositiveSlippageFeeTransformer,WethTransformer,OwnableFeature,SimpleFunctionRegistryFeature,TransformERC20Feature,AffiliateFeeTransformer,MetaTransactionsFeature,LogMetadataTransformer,BridgeAdapter,LiquidityProviderFeature,ILiquidityProviderFeature,NativeOrdersFeature,INativeOrdersFeature,FeeCollectorController,FeeCollector,CurveLiquidityProvider,BatchFillNativeOrdersFeature,IBatchFillNativeOrdersFeature,MultiplexFeature,IMultiplexFeature", | ||||
|         "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", | ||||
|         "abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeAdapter|BridgeProtocols|CurveLiquidityProvider|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IFeature|IFlashWallet|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOwnableFeature|IPancakeSwapFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinBalancer|MixinBancor|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinDodo|MixinDodoV2|MixinKyber|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinOasis|MixinShell|MixinUniswap|MixinUniswapV2|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestMooniswap|TestNativeOrdersFeature|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx|ZeroExOptimized).json" | ||||
|         "abis": "./test/generated-artifacts/@(AffiliateFeeTransformer|BatchFillNativeOrdersFeature|BootstrapFeature|BridgeAdapter|BridgeProtocols|CurveLiquidityProvider|FeeCollector|FeeCollectorController|FillQuoteTransformer|FixinCommon|FixinEIP712|FixinProtocolFees|FixinReentrancyGuard|FixinTokenSpender|FlashWallet|FullMigration|IBatchFillNativeOrdersFeature|IBootstrapFeature|IBridgeAdapter|IERC20Bridge|IERC20Transformer|IFeature|IFlashWallet|ILiquidityProvider|ILiquidityProviderFeature|ILiquidityProviderSandbox|IMetaTransactionsFeature|IMooniswapPool|IMultiplexFeature|INativeOrdersEvents|INativeOrdersFeature|IOwnableFeature|IPancakeSwapFeature|ISimpleFunctionRegistryFeature|IStaking|ITestSimpleFunctionRegistryFeature|ITokenSpenderFeature|ITransformERC20Feature|IUniswapFeature|IUniswapV2Pair|IZeroEx|InitialMigration|LibBootstrap|LibCommonRichErrors|LibERC20Transformer|LibFeeCollector|LibLiquidityProviderRichErrors|LibMetaTransactionsRichErrors|LibMetaTransactionsStorage|LibMigrate|LibNativeOrder|LibNativeOrdersRichErrors|LibNativeOrdersStorage|LibOwnableRichErrors|LibOwnableStorage|LibProxyRichErrors|LibProxyStorage|LibReentrancyGuardStorage|LibSignature|LibSignatureRichErrors|LibSimpleFunctionRegistryRichErrors|LibSimpleFunctionRegistryStorage|LibStorage|LibTransformERC20RichErrors|LibTransformERC20Storage|LibWalletRichErrors|LiquidityProviderFeature|LiquidityProviderSandbox|LogMetadataTransformer|MetaTransactionsFeature|MixinBalancer|MixinBalancerV2|MixinBancor|MixinCoFiX|MixinCryptoCom|MixinCurve|MixinDodo|MixinDodoV2|MixinKyber|MixinMStable|MixinMakerPSM|MixinMooniswap|MixinNerve|MixinOasis|MixinShell|MixinUniswap|MixinUniswapV2|MixinUniswapV3|MixinZeroExBridge|MooniswapLiquidityProvider|MultiplexFeature|NativeOrdersCancellation|NativeOrdersFeature|NativeOrdersInfo|NativeOrdersProtocolFees|NativeOrdersSettlement|OwnableFeature|PancakeSwapFeature|PayTakerTransformer|PermissionlessTransformerDeployer|PositiveSlippageFeeTransformer|SimpleFunctionRegistryFeature|TestBridge|TestCallTarget|TestCurve|TestDelegateCaller|TestFeeCollectorController|TestFillQuoteTransformerBridge|TestFillQuoteTransformerExchange|TestFillQuoteTransformerHost|TestFixinProtocolFees|TestFixinTokenSpender|TestFullMigration|TestInitialMigration|TestLibNativeOrder|TestLibSignature|TestLiquidityProvider|TestMetaTransactionsNativeOrdersFeature|TestMetaTransactionsTransformERC20Feature|TestMigrator|TestMintTokenERC20Transformer|TestMintableERC20Token|TestMooniswap|TestNativeOrdersFeature|TestOrderSignerRegistryWithContractWallet|TestPermissionlessTransformerDeployerSuicidal|TestPermissionlessTransformerDeployerTransformer|TestRfqOriginRegistration|TestSimpleFunctionRegistryFeatureImpl1|TestSimpleFunctionRegistryFeatureImpl2|TestStaking|TestTokenSpenderERC20Token|TestTransformERC20|TestTransformerBase|TestTransformerDeployerTransformer|TestTransformerHost|TestWeth|TestWethTransformerHost|TestZeroExFeature|TransformERC20Feature|Transformer|TransformerDeployer|UniswapFeature|WethTransformer|ZeroEx|ZeroExOptimized).json" | ||||
|     }, | ||||
|     "repository": { | ||||
|         "type": "git", | ||||
| @@ -55,14 +55,14 @@ | ||||
|     }, | ||||
|     "homepage": "https://github.com/0xProject/protocol/tree/main/contracts/zero-ex", | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.5.2", | ||||
|         "@0x/contract-addresses": "^6.0.0", | ||||
|         "@0x/contracts-erc20": "^3.3.7", | ||||
|         "@0x/contracts-gen": "^2.0.37", | ||||
|         "@0x/contracts-test-utils": "^5.3.25", | ||||
|         "@0x/dev-utils": "^4.2.6", | ||||
|         "@0x/order-utils": "^10.4.20", | ||||
|         "@0x/sol-compiler": "^4.7.2", | ||||
|         "@0x/abi-gen": "^5.6.0", | ||||
|         "@0x/contract-addresses": "^6.1.0", | ||||
|         "@0x/contracts-erc20": "^3.3.8", | ||||
|         "@0x/contracts-gen": "^2.0.38", | ||||
|         "@0x/contracts-test-utils": "^5.4.0", | ||||
|         "@0x/dev-utils": "^4.2.7", | ||||
|         "@0x/order-utils": "^10.4.21", | ||||
|         "@0x/sol-compiler": "^4.7.3", | ||||
|         "@0x/ts-doc-gen": "^0.0.28", | ||||
|         "@0x/tslint-config": "^4.1.4", | ||||
|         "@types/isomorphic-fetch": "^0.0.35", | ||||
| @@ -82,13 +82,13 @@ | ||||
|         "typescript": "4.2.2" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/base-contract": "^6.3.2", | ||||
|         "@0x/protocol-utils": "^1.5.1", | ||||
|         "@0x/subproviders": "^6.5.2", | ||||
|         "@0x/base-contract": "^6.4.0", | ||||
|         "@0x/protocol-utils": "^1.6.0", | ||||
|         "@0x/subproviders": "^6.5.3", | ||||
|         "@0x/types": "^3.3.3", | ||||
|         "@0x/typescript-typings": "^5.2.0", | ||||
|         "@0x/utils": "^6.4.2", | ||||
|         "@0x/web3-wrapper": "^7.5.2", | ||||
|         "@0x/utils": "^6.4.3", | ||||
|         "@0x/web3-wrapper": "^7.5.3", | ||||
|         "ethereum-types": "^3.5.0", | ||||
|         "ethereumjs-util": "^7.0.10" | ||||
|     }, | ||||
|   | ||||
| @@ -76,6 +76,7 @@ import * as LiquidityProviderSandbox from '../test/generated-artifacts/Liquidity | ||||
| import * as LogMetadataTransformer from '../test/generated-artifacts/LogMetadataTransformer.json'; | ||||
| import * as MetaTransactionsFeature from '../test/generated-artifacts/MetaTransactionsFeature.json'; | ||||
| import * as MixinBalancer from '../test/generated-artifacts/MixinBalancer.json'; | ||||
| import * as MixinBalancerV2 from '../test/generated-artifacts/MixinBalancerV2.json'; | ||||
| import * as MixinBancor from '../test/generated-artifacts/MixinBancor.json'; | ||||
| import * as MixinCoFiX from '../test/generated-artifacts/MixinCoFiX.json'; | ||||
| import * as MixinCryptoCom from '../test/generated-artifacts/MixinCryptoCom.json'; | ||||
| @@ -91,6 +92,7 @@ import * as MixinOasis from '../test/generated-artifacts/MixinOasis.json'; | ||||
| import * as MixinShell from '../test/generated-artifacts/MixinShell.json'; | ||||
| import * as MixinUniswap from '../test/generated-artifacts/MixinUniswap.json'; | ||||
| import * as MixinUniswapV2 from '../test/generated-artifacts/MixinUniswapV2.json'; | ||||
| import * as MixinUniswapV3 from '../test/generated-artifacts/MixinUniswapV3.json'; | ||||
| import * as MixinZeroExBridge from '../test/generated-artifacts/MixinZeroExBridge.json'; | ||||
| import * as MooniswapLiquidityProvider from '../test/generated-artifacts/MooniswapLiquidityProvider.json'; | ||||
| import * as MultiplexFeature from '../test/generated-artifacts/MultiplexFeature.json'; | ||||
| @@ -235,6 +237,7 @@ export const artifacts = { | ||||
|     BridgeProtocols: BridgeProtocols as ContractArtifact, | ||||
|     IBridgeAdapter: IBridgeAdapter as ContractArtifact, | ||||
|     MixinBalancer: MixinBalancer as ContractArtifact, | ||||
|     MixinBalancerV2: MixinBalancerV2 as ContractArtifact, | ||||
|     MixinBancor: MixinBancor as ContractArtifact, | ||||
|     MixinCoFiX: MixinCoFiX as ContractArtifact, | ||||
|     MixinCryptoCom: MixinCryptoCom as ContractArtifact, | ||||
| @@ -250,6 +253,7 @@ export const artifacts = { | ||||
|     MixinShell: MixinShell as ContractArtifact, | ||||
|     MixinUniswap: MixinUniswap as ContractArtifact, | ||||
|     MixinUniswapV2: MixinUniswapV2 as ContractArtifact, | ||||
|     MixinUniswapV3: MixinUniswapV3 as ContractArtifact, | ||||
|     MixinZeroExBridge: MixinZeroExBridge as ContractArtifact, | ||||
|     ILiquidityProvider: ILiquidityProvider as ContractArtifact, | ||||
|     IMooniswapPool: IMooniswapPool as ContractArtifact, | ||||
|   | ||||
| @@ -74,6 +74,7 @@ export * from '../test/generated-wrappers/liquidity_provider_sandbox'; | ||||
| export * from '../test/generated-wrappers/log_metadata_transformer'; | ||||
| export * from '../test/generated-wrappers/meta_transactions_feature'; | ||||
| export * from '../test/generated-wrappers/mixin_balancer'; | ||||
| export * from '../test/generated-wrappers/mixin_balancer_v2'; | ||||
| export * from '../test/generated-wrappers/mixin_bancor'; | ||||
| export * from '../test/generated-wrappers/mixin_co_fi_x'; | ||||
| export * from '../test/generated-wrappers/mixin_crypto_com'; | ||||
| @@ -89,6 +90,7 @@ export * from '../test/generated-wrappers/mixin_oasis'; | ||||
| export * from '../test/generated-wrappers/mixin_shell'; | ||||
| export * from '../test/generated-wrappers/mixin_uniswap'; | ||||
| export * from '../test/generated-wrappers/mixin_uniswap_v2'; | ||||
| export * from '../test/generated-wrappers/mixin_uniswap_v3'; | ||||
| export * from '../test/generated-wrappers/mixin_zero_ex_bridge'; | ||||
| export * from '../test/generated-wrappers/mooniswap_liquidity_provider'; | ||||
| export * from '../test/generated-wrappers/multiplex_feature'; | ||||
|   | ||||
| @@ -105,6 +105,7 @@ | ||||
|         "test/generated-artifacts/LogMetadataTransformer.json", | ||||
|         "test/generated-artifacts/MetaTransactionsFeature.json", | ||||
|         "test/generated-artifacts/MixinBalancer.json", | ||||
|         "test/generated-artifacts/MixinBalancerV2.json", | ||||
|         "test/generated-artifacts/MixinBancor.json", | ||||
|         "test/generated-artifacts/MixinCoFiX.json", | ||||
|         "test/generated-artifacts/MixinCryptoCom.json", | ||||
| @@ -120,6 +121,7 @@ | ||||
|         "test/generated-artifacts/MixinShell.json", | ||||
|         "test/generated-artifacts/MixinUniswap.json", | ||||
|         "test/generated-artifacts/MixinUniswapV2.json", | ||||
|         "test/generated-artifacts/MixinUniswapV3.json", | ||||
|         "test/generated-artifacts/MixinZeroExBridge.json", | ||||
|         "test/generated-artifacts/MooniswapLiquidityProvider.json", | ||||
|         "test/generated-artifacts/MultiplexFeature.json", | ||||
|   | ||||
							
								
								
									
										36
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								package.json
									
									
									
									
									
								
							| @@ -10,7 +10,7 @@ | ||||
|     ], | ||||
|     "scripts": { | ||||
|         "deps_versions:ci": "node ./node_modules/@0x/monorepo-scripts/lib/deps_versions.js", | ||||
|         "fix": "wsrun fix $PKG --fast-exit --parallel --exclude-missing", | ||||
|         "fix": "wsrun --fast-exit --parallel --exclude-missing -c fix $PKG", | ||||
|         "ganache": "ganache-cli -p 8545 --gasLimit 10000000 --networkId 50 -m \"${npm_package_config_mnemonic}\"", | ||||
|         "prettier": "prettier --write '**/*.{ts,tsx,json,md}' --config .prettierrc", | ||||
|         "prettier:ci": "prettier --list-different '**/*.{ts,tsx,json,md}' --config .prettierrc", | ||||
| @@ -27,31 +27,25 @@ | ||||
|         "install:all": "yarn install", | ||||
|         "wsrun": "wsrun", | ||||
|         "lerna": "lerna", | ||||
|         "build": "lerna link && wsrun build $PKG -r --stages --fast-exit --exclude-missing", | ||||
|         "build:ci": "lerna link && wsrun build:ci $PKG --fast-exit -r --stages --exclude-missing", | ||||
|         "build:contracts": "lerna link && wsrun build -p ${npm_package_config_contractsPackages} -c --fast-exit -r --stages --exclude-missing", | ||||
|         "build": "lerna link && wsrun -r --stages --fast-exit --exclude-missing -c build $PKG", | ||||
|         "build:ci": "lerna link && wsrun --fast-exit -r --stages --exclude-missing -c build:ci $PKG", | ||||
|         "build:contracts": "lerna link && wsrun -p ${npm_package_config_contractsPackages} --fast-exit -r --stages --exclude-missing -c build", | ||||
|         "build:ts": "tsc -b", | ||||
|         "watch:ts": "tsc -b -w", | ||||
|         "clean": "wsrun clean $PKG --fast-exit -r --parallel --exclude-missing", | ||||
|         "clean:contracts": "wsrun clean -p ${npm_package_config_contractsPackages} -c --fast-exit -r --parallel --exclude-missing", | ||||
|         "contracts:gen": "wsrun contracts:gen $PKG --fast-exit -r --parallel --exclude-missing", | ||||
|         "contracts:compile": "wsrun compile -p ${npm_package_config_contractsPackages} --fast-exit -r --stages --exclude-missing", | ||||
|         "contracts:compile:truffle": "wsrun compile:truffle -p ${npm_package_config_contractsPackages} --fast-exit -r --stages --exclude-missing", | ||||
|         "contracts:watch": "wsrun watch $PKG --parallel --exclude-missing", | ||||
|         "clean": "wsrun --fast-exit -r --parallel --exclude-missing clean -c $PKG", | ||||
|         "contracts:watch": "wsrun --parallel --exclude-missing watch -c $PKG", | ||||
|         "remove_node_modules": "lerna clean --yes; rm -rf node_modules", | ||||
|         "rebuild": "run-s clean build", | ||||
|         "test": "wsrun test $(echo $(echo ${npm_package_config_contractsPackages} ${npm_package_config_nonContractPackages} | tr ' ' '\n' | sort | uniq) ${npm_package_config_ignoreTestsForPackages} | tr ' ' '\n' | sort | uniq -u | tr '\n' ' ') --fast-exit --serial --exclude-missing", | ||||
|         "test:all": "wsrun test $PKG --fast-exit --serial --exclude-missing", | ||||
|         "test:contracts": "wsrun test --serial -p $(echo ${npm_package_config_contractsPackages} ${npm_package_config_ignoreTestsForPackages} | tr ' ' '\n' | sort | uniq -u | tr '\n' ' ') -c --fast-exit --exclude-missing", | ||||
|         "test:contracts:all": "wsrun test --serial -p ${npm_package_config_contractsPackages} -c --fast-exit --exclude-missing", | ||||
|         "test": "wsrun --fast-exit --serial --exclude-missing -p $(echo $(echo ${npm_package_config_contractsPackages} ${npm_package_config_nonContractPackages} | tr ' ' '\n' | sort | uniq) ${npm_package_config_ignoreTestsForPackages} | tr ' ' '\n' | sort | uniq -u | tr '\n' ' ') -c test", | ||||
|         "test:all": "wsrun --fast-exit --serial --exclude-missing -c test $PKG", | ||||
|         "test:contracts": "wsrun --serial -p $(echo ${npm_package_config_contractsPackages} ${npm_package_config_ignoreTestsForPackages} | tr ' ' '\n' | sort | uniq -u | tr '\n' ' ') --fast-exit --exclude-missing -c test", | ||||
|         "test:contracts:all": "wsrun --serial -p ${npm_package_config_contractsPackages} --fast-exit --exclude-missing -c test", | ||||
|         "generate_doc": "node ./node_modules/@0x/monorepo-scripts/lib/doc_generate.js --config ./doc-gen-config.json", | ||||
|         "upload_md_docs": "aws s3 rm --recursive s3://docs-markdown; wsrun s3:sync_md_docs --exclude-missing", | ||||
|         "diff_md_docs:ci": "wsrun diff_docs --exclude-missing", | ||||
|         "upload_md_docs": "aws s3 rm --recursive s3://docs-markdown; wsrun --exclude-missing -c s3:sync_md_docs", | ||||
|         "diff_md_docs:ci": "wsrun --exclude-missing -c diff_docs", | ||||
|         "test:generate_docs:circleci": "for i in ${npm_package_config_packagesWithDocPages}; do yarn generate_doc --package $i || break -1; done;", | ||||
|         "bundlewatch": "bundlewatch", | ||||
|         "lint": "wsrun lint $PKG --fast-exit --parallel --exclude-missing", | ||||
|         "lint:stages": "wsrun lint $PKG --fast-exit --stages --exclude-missing", | ||||
|         "lint:contracts": "wsrun lint -p ${npm_package_config_contractsPackages} -c --fast-exit --stages --exclude-missing", | ||||
|         "lint": "wsrun --fast-exit --parallel --exclude-missing -c lint $PKG", | ||||
|         "upgrade_org_deps": "node node_modules/@0x/monorepo-scripts/lib/upgrade_deps.js -p '@0x|ethereum-types'", | ||||
|         "upgrade_deps": "node node_modules/@0x/monorepo-scripts/lib/upgrade_deps.js", | ||||
|         "verdaccio": "docker run --rm -i -p 4873:4873 0xorg/verdaccio" | ||||
| @@ -66,7 +60,7 @@ | ||||
|         "ignoreDependencyVersionsForPackage": "contract-wrappers" | ||||
|     }, | ||||
|     "devDependencies": { | ||||
|         "@0x/monorepo-scripts": "^3.1.6", | ||||
|         "@0x/monorepo-scripts": "^3.1.7", | ||||
|         "@0x-lerna-fork/lerna": "3.16.10", | ||||
|         "@0xproject/npm-cli-login": "^0.0.11", | ||||
|         "async-child-process": "^1.1.1", | ||||
| @@ -78,7 +72,7 @@ | ||||
|         "prettier": "~1.16.3", | ||||
|         "source-map-support": "^0.5.6", | ||||
|         "typescript": "4.2.2", | ||||
|         "wsrun": "^2.2.0" | ||||
|         "wsrun": "^5.2.4" | ||||
|     }, | ||||
|     "resolutions": { | ||||
|         "merkle-patricia-tree": "^2.3.2" | ||||
|   | ||||
| @@ -1,4 +1,101 @@ | ||||
| [ | ||||
|     { | ||||
|         "version": "6.12.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "`TwoHopSampler` to use `call` over `staticcall` in order to support sources like `Uniswap_V3` and `Balancer_V2`", | ||||
|                 "pr": 233 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1620610602 | ||||
|     }, | ||||
|     { | ||||
|         "version": "6.11.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Add price comparisons data separate from the quote report", | ||||
|                 "pr": 219 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add caching for top Balancer V2 pools on startup and during regular intervals", | ||||
|                 "pr": 228 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Tweak compiler settings for smaller sampler bytecode", | ||||
|                 "pr": 229 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Fix Multiplex multihop encoding for ETH buys/sells", | ||||
|                 "pr": 230 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Fix Sampler address override for Ganache", | ||||
|                 "pr": 232 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1620362129 | ||||
|     }, | ||||
|     { | ||||
|         "version": "6.10.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Reactivate PancakeSwapV2 and BakerySwap VIP on BSC", | ||||
|                 "pr": 222 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add LUSD Curve pool", | ||||
|                 "pr": 218 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Fix exchangeProxyGasOverhead for fallback path", | ||||
|                 "pr": 215 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Enable ETH based Curve pools", | ||||
|                 "pr": 220 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Reactivate PancakeSwapV2 and BakerySwap VIP on BSC", | ||||
|                 "pr": 222 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Disable WETH based SnowSwap pools", | ||||
|                 "pr": 220 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "PLP now includes a fallback due to observed collisions", | ||||
|                 "pr": 223 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Add Balancer V2 integration", | ||||
|                 "pr": 206 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "Re-work the PoolCache for Balancer et al", | ||||
|                 "pr": 226 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1620214333 | ||||
|     }, | ||||
|     { | ||||
|         "version": "6.9.1", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Temporarily remove PancakeV2 and BakerySwap from VIP" | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1619830995 | ||||
|     }, | ||||
|     { | ||||
|         "version": "6.9.0", | ||||
|         "changes": [ | ||||
|             { | ||||
|                 "note": "Remove conflicting Kyber reserve", | ||||
|                 "pr": 216 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1619825976 | ||||
|     }, | ||||
|     { | ||||
|         "version": "6.8.0", | ||||
|         "changes": [ | ||||
| @@ -38,6 +135,10 @@ | ||||
|             { | ||||
|                 "note": "Support `Ropsten` network", | ||||
|                 "pr": 203 | ||||
|             }, | ||||
|             { | ||||
|                 "note": "BSC Uniswap clones (ApeSwap, CafeSwap, CheeseSwap, JulSwap), Saddle BTC pool, Curve gas schedule", | ||||
|                 "pr": 208 | ||||
|             } | ||||
|         ], | ||||
|         "timestamp": 1618592834 | ||||
|   | ||||
| @@ -5,6 +5,38 @@ Edit the package's CHANGELOG.json file only. | ||||
|  | ||||
| CHANGELOG | ||||
|  | ||||
| ## v6.12.0 - _May 10, 2021_ | ||||
|  | ||||
|     * `TwoHopSampler` to use `call` over `staticcall` in order to support sources like `Uniswap_V3` and `Balancer_V2` (#233) | ||||
|  | ||||
| ## v6.11.0 - _May 7, 2021_ | ||||
|  | ||||
|     * Add price comparisons data separate from the quote report (#219) | ||||
|     * Add caching for top Balancer V2 pools on startup and during regular intervals (#228) | ||||
|     * Tweak compiler settings for smaller sampler bytecode (#229) | ||||
|     * Fix Multiplex multihop encoding for ETH buys/sells (#230) | ||||
|     * Fix Sampler address override for Ganache (#232) | ||||
|  | ||||
| ## v6.10.0 - _May 5, 2021_ | ||||
|  | ||||
|     * Reactivate PancakeSwapV2 and BakerySwap VIP on BSC (#222) | ||||
|     * Add LUSD Curve pool (#218) | ||||
|     * Fix exchangeProxyGasOverhead for fallback path (#215) | ||||
|     * Enable ETH based Curve pools (#220) | ||||
|     * Reactivate PancakeSwapV2 and BakerySwap VIP on BSC (#222) | ||||
|     * Disable WETH based SnowSwap pools (#220) | ||||
|     * PLP now includes a fallback due to observed collisions (#223) | ||||
|     * Add Balancer V2 integration (#206) | ||||
|     * Re-work the PoolCache for Balancer et al (#226) | ||||
|  | ||||
| ## v6.9.1 - _May 1, 2021_ | ||||
|  | ||||
|     * Temporarily remove PancakeV2 and BakerySwap from VIP | ||||
|  | ||||
| ## v6.9.0 - _April 30, 2021_ | ||||
|  | ||||
|     * Remove conflicting Kyber reserve (#216) | ||||
|  | ||||
| ## v6.8.0 - _April 28, 2021_ | ||||
|  | ||||
|     * Prune paths which cannot improve the best path (#183) | ||||
| @@ -21,6 +53,7 @@ CHANGELOG | ||||
| ## v6.6.0 - _April 16, 2021_ | ||||
|  | ||||
|     * Support `Ropsten` network (#203) | ||||
|     * BSC Uniswap clones (ApeSwap, CafeSwap, CheeseSwap, JulSwap), Saddle BTC pool, Curve gas schedule (#208) | ||||
|  | ||||
| ## v6.5.3 - _April 14, 2021_ | ||||
|  | ||||
|   | ||||
| @@ -6,11 +6,7 @@ | ||||
|     "shouldSaveStandardInput": true, | ||||
|     "compilerSettings": { | ||||
|         "evmVersion": "istanbul", | ||||
|         "optimizer": { | ||||
|             "enabled": true, | ||||
|             "runs": 62500, | ||||
|             "details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true } | ||||
|         }, | ||||
|         "optimizer": { "enabled": true, "runs": 200, "details": { "yul": true, "deduplicate": true } }, | ||||
|         "outputSelection": { | ||||
|             "*": { | ||||
|                 "*": [ | ||||
|   | ||||
							
								
								
									
										189
									
								
								packages/asset-swapper/contracts/src/BalancerV2Sampler.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								packages/asset-swapper/contracts/src/BalancerV2Sampler.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,189 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2021 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "./SamplerUtils.sol"; | ||||
|  | ||||
| /// @dev Minimal Balancer V2 Vault interface | ||||
| ///      for documentation refer to https://github.com/balancer-labs/balancer-core-v2/blob/master/contracts/vault/interfaces/IVault.sol | ||||
| interface IBalancerV2Vault { | ||||
|     enum SwapKind { GIVEN_IN, GIVEN_OUT } | ||||
|  | ||||
|     struct BatchSwapStep { | ||||
|         bytes32 poolId; | ||||
|         uint256 assetInIndex; | ||||
|         uint256 assetOutIndex; | ||||
|         uint256 amount; | ||||
|         bytes userData; | ||||
|     } | ||||
|  | ||||
|     struct FundManagement { | ||||
|         address sender; | ||||
|         bool fromInternalBalance; | ||||
|         address payable recipient; | ||||
|         bool toInternalBalance; | ||||
|     } | ||||
|  | ||||
|     function queryBatchSwap( | ||||
|         SwapKind kind, | ||||
|         BatchSwapStep[] calldata swaps, | ||||
|         IAsset[] calldata assets, | ||||
|         FundManagement calldata funds | ||||
|     ) external returns (int256[] memory assetDeltas); | ||||
| } | ||||
| interface IAsset { | ||||
|     // solhint-disable-previous-line no-empty-blocks | ||||
| } | ||||
|  | ||||
| contract BalancerV2Sampler is SamplerUtils { | ||||
|  | ||||
|     struct BalancerV2PoolInfo { | ||||
|         bytes32 poolId; | ||||
|         address vault; | ||||
|     } | ||||
|  | ||||
|     /// @dev Sample sell quotes from Balancer V2. | ||||
|     /// @param poolInfo Struct with pool related data | ||||
|     /// @param takerToken Address of the taker token (what to sell). | ||||
|     /// @param makerToken Address of the maker token (what to buy). | ||||
|     /// @param takerTokenAmounts Taker token sell amount for each sample. | ||||
|     /// @return makerTokenAmounts Maker amounts bought at each taker token | ||||
|     ///         amount. | ||||
|     function sampleSellsFromBalancerV2( | ||||
|         BalancerV2PoolInfo memory poolInfo, | ||||
|         address takerToken, | ||||
|         address makerToken, | ||||
|         uint256[] memory takerTokenAmounts | ||||
|     ) | ||||
|         public | ||||
|         returns (uint256[] memory makerTokenAmounts) | ||||
|     { | ||||
|         _assertValidPair(makerToken, takerToken); | ||||
|         IBalancerV2Vault vault = IBalancerV2Vault(poolInfo.vault); | ||||
|         IAsset[] memory swapAssets = new IAsset[](2); | ||||
|         swapAssets[0] = IAsset(takerToken); | ||||
|         swapAssets[1] = IAsset(makerToken); | ||||
|  | ||||
|         uint256 numSamples = takerTokenAmounts.length; | ||||
|         makerTokenAmounts = new uint256[](numSamples); | ||||
|         IBalancerV2Vault.FundManagement memory swapFunds = | ||||
|             _createSwapFunds(); | ||||
|  | ||||
|         for (uint256 i = 0; i < numSamples; i++) { | ||||
|             IBalancerV2Vault.BatchSwapStep[] memory swapSteps = | ||||
|                 _createSwapSteps(poolInfo, takerTokenAmounts[i]); | ||||
|  | ||||
|             try | ||||
|                 // For sells we specify the takerToken which is what the vault will receive from the trade | ||||
|                 vault.queryBatchSwap(IBalancerV2Vault.SwapKind.GIVEN_IN, swapSteps, swapAssets, swapFunds) | ||||
|             // amounts represent pool balance deltas from the swap (incoming balance, outgoing balance) | ||||
|             returns (int256[] memory amounts) { | ||||
|                 // Outgoing balance is negative so we need to flip the sign | ||||
|                 int256 amountOutFromPool = amounts[1] * -1; | ||||
|                 if (amountOutFromPool <= 0) { | ||||
|                     break; | ||||
|                 } | ||||
|                 makerTokenAmounts[i] = uint256(amountOutFromPool); | ||||
|             } catch (bytes memory) { | ||||
|                 // Swallow failures, leaving all results as zero. | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// @dev Sample buy quotes from Balancer V2. | ||||
|     /// @param poolInfo Struct with pool related data | ||||
|     /// @param takerToken Address of the taker token (what to sell). | ||||
|     /// @param makerToken Address of the maker token (what to buy). | ||||
|     /// @param makerTokenAmounts Maker token buy amount for each sample. | ||||
|     /// @return takerTokenAmounts Taker amounts sold at each maker token | ||||
|     ///         amount. | ||||
|     function sampleBuysFromBalancerV2( | ||||
|         BalancerV2PoolInfo memory poolInfo, | ||||
|         address takerToken, | ||||
|         address makerToken, | ||||
|         uint256[] memory makerTokenAmounts | ||||
|     ) | ||||
|         public | ||||
|         returns (uint256[] memory takerTokenAmounts) | ||||
|     { | ||||
|         _assertValidPair(makerToken, takerToken); | ||||
|         IBalancerV2Vault vault = IBalancerV2Vault(poolInfo.vault); | ||||
|         IAsset[] memory swapAssets = new IAsset[](2); | ||||
|         swapAssets[0] = IAsset(takerToken); | ||||
|         swapAssets[1] = IAsset(makerToken); | ||||
|  | ||||
|         uint256 numSamples = makerTokenAmounts.length; | ||||
|         takerTokenAmounts = new uint256[](numSamples); | ||||
|         IBalancerV2Vault.FundManagement memory swapFunds = | ||||
|             _createSwapFunds(); | ||||
|  | ||||
|         for (uint256 i = 0; i < numSamples; i++) { | ||||
|             IBalancerV2Vault.BatchSwapStep[] memory swapSteps = | ||||
|                 _createSwapSteps(poolInfo, makerTokenAmounts[i]); | ||||
|  | ||||
|             try | ||||
|                 // For buys we specify the makerToken which is what taker will receive from the trade | ||||
|                 vault.queryBatchSwap(IBalancerV2Vault.SwapKind.GIVEN_OUT, swapSteps, swapAssets, swapFunds) | ||||
|             returns (int256[] memory amounts) { | ||||
|                 int256 amountIntoPool = amounts[0]; | ||||
|                 if (amountIntoPool <= 0) { | ||||
|                     break; | ||||
|                 } | ||||
|                 takerTokenAmounts[i] = uint256(amountIntoPool); | ||||
|             } catch (bytes memory) { | ||||
|                 // Swallow failures, leaving all results as zero. | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function _createSwapSteps( | ||||
|         BalancerV2PoolInfo memory poolInfo, | ||||
|         uint256 amount | ||||
|     ) private pure returns (IBalancerV2Vault.BatchSwapStep[] memory) { | ||||
|         IBalancerV2Vault.BatchSwapStep[] memory swapSteps = | ||||
|             new IBalancerV2Vault.BatchSwapStep[](1); | ||||
|         swapSteps[0] = IBalancerV2Vault.BatchSwapStep({ | ||||
|             poolId: poolInfo.poolId, | ||||
|             assetInIndex: 0, | ||||
|             assetOutIndex: 1, | ||||
|             amount: amount, | ||||
|             userData: "" | ||||
|         }); | ||||
|  | ||||
|         return swapSteps; | ||||
|     } | ||||
|  | ||||
|     function _createSwapFunds() | ||||
|         private | ||||
|         view | ||||
|         returns (IBalancerV2Vault.FundManagement memory) | ||||
|     { | ||||
|         return | ||||
|             IBalancerV2Vault.FundManagement({ | ||||
|                 sender: address(this), | ||||
|                 fromInternalBalance: false, | ||||
|                 recipient: payable(address(this)), | ||||
|                 toInternalBalance: false | ||||
|             }); | ||||
|     } | ||||
| } | ||||
| @@ -22,16 +22,15 @@ pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "./interfaces/IBancor.sol"; | ||||
|  | ||||
| contract DeploymentConstants {} | ||||
| contract CompilerHack {} | ||||
|  | ||||
| contract BancorSampler is DeploymentConstants | ||||
| { | ||||
| contract BancorSampler is CompilerHack { | ||||
|  | ||||
|     /// @dev Base gas limit for Bancor calls. | ||||
|     uint256 constant private BANCOR_CALL_GAS = 300e3; // 300k | ||||
|  | ||||
|     struct BancorSamplerOpts { | ||||
|         address registry; | ||||
|         IBancorRegistry registry; | ||||
|         address[][] paths; | ||||
|     } | ||||
|  | ||||
| @@ -112,7 +111,7 @@ contract BancorSampler is DeploymentConstants | ||||
|         view | ||||
|         returns (address bancorNetwork, address[] memory path) | ||||
|     { | ||||
|         bancorNetwork = _getBancorNetwork(opts.registry); | ||||
|         bancorNetwork = opts.registry.getAddress(opts.registry.BANCOR_NETWORK()); | ||||
|         if (opts.paths.length == 0) { | ||||
|             return (bancorNetwork, path); | ||||
|         } | ||||
| @@ -140,13 +139,4 @@ contract BancorSampler is DeploymentConstants | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function _getBancorNetwork(address registry) | ||||
|         private | ||||
|         view | ||||
|         returns (address) | ||||
|     { | ||||
|         IBancorRegistry registry = IBancorRegistry(registry); | ||||
|         return registry.getAddress(registry.BANCOR_NETWORK()); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -21,6 +21,7 @@ pragma solidity ^0.6; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "./BalancerSampler.sol"; | ||||
| import "./BalancerV2Sampler.sol"; | ||||
| import "./BancorSampler.sol"; | ||||
| import "./CurveSampler.sol"; | ||||
| import "./DODOSampler.sol"; | ||||
| @@ -38,11 +39,13 @@ import "./SmoothySampler.sol"; | ||||
| import "./TwoHopSampler.sol"; | ||||
| import "./UniswapSampler.sol"; | ||||
| import "./UniswapV2Sampler.sol"; | ||||
| import "./UniswapV3Sampler.sol"; | ||||
| import "./UtilitySampler.sol"; | ||||
|  | ||||
|  | ||||
| contract ERC20BridgeSampler is | ||||
|     BalancerSampler, | ||||
|     BalancerV2Sampler, | ||||
|     BancorSampler, | ||||
|     CurveSampler, | ||||
|     DODOSampler, | ||||
| @@ -60,6 +63,7 @@ contract ERC20BridgeSampler is | ||||
|     TwoHopSampler, | ||||
|     UniswapSampler, | ||||
|     UniswapV2Sampler, | ||||
|     UniswapV3Sampler, | ||||
|     UtilitySampler | ||||
| { | ||||
|  | ||||
| @@ -73,7 +77,6 @@ contract ERC20BridgeSampler is | ||||
|     /// @return callResults ABI-encoded results data for each call. | ||||
|     function batchCall(bytes[] calldata callDatas) | ||||
|         external | ||||
|         view | ||||
|         returns (CallResults[] memory callResults) | ||||
|     { | ||||
|         callResults = new CallResults[](callDatas.length); | ||||
| @@ -82,7 +85,7 @@ contract ERC20BridgeSampler is | ||||
|             if (callDatas[i].length == 0) { | ||||
|                 continue; | ||||
|             } | ||||
|             (callResults[i].success, callResults[i].data) = address(this).staticcall(callDatas[i]); | ||||
|             (callResults[i].success, callResults[i].data) = address(this).call(callDatas[i]); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -37,7 +37,6 @@ contract TwoHopSampler { | ||||
|         uint256 sellAmount | ||||
|     ) | ||||
|         public | ||||
|         view | ||||
|         returns ( | ||||
|             HopInfo memory firstHop, | ||||
|             HopInfo memory secondHop, | ||||
| @@ -47,7 +46,7 @@ contract TwoHopSampler { | ||||
|         uint256 intermediateAssetAmount = 0; | ||||
|         for (uint256 i = 0; i != firstHopCalls.length; ++i) { | ||||
|             firstHopCalls[i].writeUint256(firstHopCalls[i].length - 32, sellAmount); | ||||
|             (bool didSucceed, bytes memory returnData) = address(this).staticcall(firstHopCalls[i]); | ||||
|             (bool didSucceed, bytes memory returnData) = address(this).call(firstHopCalls[i]); | ||||
|             if (didSucceed) { | ||||
|                 uint256 amount = returnData.readUint256(returnData.length - 32); | ||||
|                 if (amount > intermediateAssetAmount) { | ||||
| @@ -62,7 +61,7 @@ contract TwoHopSampler { | ||||
|         } | ||||
|         for (uint256 j = 0; j != secondHopCalls.length; ++j) { | ||||
|             secondHopCalls[j].writeUint256(secondHopCalls[j].length - 32, intermediateAssetAmount); | ||||
|             (bool didSucceed, bytes memory returnData) = address(this).staticcall(secondHopCalls[j]); | ||||
|             (bool didSucceed, bytes memory returnData) = address(this).call(secondHopCalls[j]); | ||||
|             if (didSucceed) { | ||||
|                 uint256 amount = returnData.readUint256(returnData.length - 32); | ||||
|                 if (amount > buyAmount) { | ||||
| @@ -80,7 +79,6 @@ contract TwoHopSampler { | ||||
|         uint256 buyAmount | ||||
|     ) | ||||
|         public | ||||
|         view | ||||
|         returns ( | ||||
|             HopInfo memory firstHop, | ||||
|             HopInfo memory secondHop, | ||||
| @@ -91,7 +89,7 @@ contract TwoHopSampler { | ||||
|         uint256 intermediateAssetAmount = uint256(-1); | ||||
|         for (uint256 j = 0; j != secondHopCalls.length; ++j) { | ||||
|             secondHopCalls[j].writeUint256(secondHopCalls[j].length - 32, buyAmount); | ||||
|             (bool didSucceed, bytes memory returnData) = address(this).staticcall(secondHopCalls[j]); | ||||
|             (bool didSucceed, bytes memory returnData) = address(this).call(secondHopCalls[j]); | ||||
|             if (didSucceed) { | ||||
|                 uint256 amount = returnData.readUint256(returnData.length - 32); | ||||
|                 if ( | ||||
| @@ -109,7 +107,7 @@ contract TwoHopSampler { | ||||
|         } | ||||
|         for (uint256 i = 0; i != firstHopCalls.length; ++i) { | ||||
|             firstHopCalls[i].writeUint256(firstHopCalls[i].length - 32, intermediateAssetAmount); | ||||
|             (bool didSucceed, bytes memory returnData) = address(this).staticcall(firstHopCalls[i]); | ||||
|             (bool didSucceed, bytes memory returnData) = address(this).call(firstHopCalls[i]); | ||||
|             if (didSucceed) { | ||||
|                 uint256 amount = returnData.readUint256(returnData.length - 32); | ||||
|                 if ( | ||||
|   | ||||
							
								
								
									
										313
									
								
								packages/asset-swapper/contracts/src/UniswapV3Sampler.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										313
									
								
								packages/asset-swapper/contracts/src/UniswapV3Sampler.sol
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,313 @@ | ||||
| // SPDX-License-Identifier: Apache-2.0 | ||||
| /* | ||||
|  | ||||
|   Copyright 2021 ZeroEx Intl. | ||||
|  | ||||
|   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|   you may not use this file except in compliance with the License. | ||||
|   You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
|  | ||||
| */ | ||||
|  | ||||
| pragma solidity ^0.6; | ||||
| pragma experimental ABIEncoderV2; | ||||
|  | ||||
| import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol"; | ||||
|  | ||||
| interface IUniswapV3Quoter { | ||||
|     function factory() | ||||
|         external | ||||
|         view | ||||
|         returns (IUniswapV3Factory factory); | ||||
|     function quoteExactInput(bytes memory path, uint256 amountIn) | ||||
|         external | ||||
|         returns (uint256 amountOut); | ||||
|     function quoteExactOutput(bytes memory path, uint256 amountOut) | ||||
|         external | ||||
|         returns (uint256 amountIn); | ||||
| } | ||||
|  | ||||
| interface IUniswapV3Factory { | ||||
|     function getPool(IERC20TokenV06 a, IERC20TokenV06 b, uint24 fee) | ||||
|         external | ||||
|         view | ||||
|         returns (IUniswapV3Pool pool); | ||||
| } | ||||
|  | ||||
| interface IUniswapV3Pool { | ||||
|     function token0() external view returns (IERC20TokenV06); | ||||
|     function token1() external view returns (IERC20TokenV06); | ||||
|     function fee() external view returns (uint24); | ||||
| } | ||||
|  | ||||
| contract UniswapV3Sampler | ||||
| { | ||||
|     /// @dev Gas limit for UniswapV3 calls. This is 100% a guess. | ||||
|     uint256 constant private QUOTE_GAS = 300e3; | ||||
|  | ||||
|     /// @dev Sample sell quotes from UniswapV3. | ||||
|     /// @param quoter UniswapV3 Quoter contract. | ||||
|     /// @param path Token route. Should be takerToken -> makerToken | ||||
|     /// @param takerTokenAmounts Taker token sell amount for each sample. | ||||
|     /// @return uniswapPaths The encoded uniswap path for each sample. | ||||
|     /// @return makerTokenAmounts Maker amounts bought at each taker token | ||||
|     ///         amount. | ||||
|     function sampleSellsFromUniswapV3( | ||||
|         IUniswapV3Quoter quoter, | ||||
|         IERC20TokenV06[] memory path, | ||||
|         uint256[] memory takerTokenAmounts | ||||
|     ) | ||||
|         public | ||||
|         returns ( | ||||
|             bytes[] memory uniswapPaths, | ||||
|             uint256[] memory makerTokenAmounts | ||||
|         ) | ||||
|     { | ||||
|         IUniswapV3Pool[][] memory poolPaths = | ||||
|             _getValidPoolPaths(quoter.factory(), path, 0); | ||||
|  | ||||
|         makerTokenAmounts = new uint256[](takerTokenAmounts.length); | ||||
|         uniswapPaths = new bytes[](takerTokenAmounts.length); | ||||
|  | ||||
|         for (uint256 i = 0; i < takerTokenAmounts.length; ++i) { | ||||
|             // Pick the best result from all the paths. | ||||
|             bytes memory topUniswapPath; | ||||
|             uint256 topBuyAmount = 0; | ||||
|             for (uint256 j = 0; j < poolPaths.length; ++j) { | ||||
|                 bytes memory uniswapPath = _toUniswapPath(path, poolPaths[j]); | ||||
|                 try | ||||
|                     quoter.quoteExactInput | ||||
|                         { gas: QUOTE_GAS } | ||||
|                         (uniswapPath, takerTokenAmounts[i]) | ||||
|                         returns (uint256 buyAmount) | ||||
|                 { | ||||
|                     if (topBuyAmount <= buyAmount) { | ||||
|                         topBuyAmount = buyAmount; | ||||
|                         topUniswapPath = uniswapPath; | ||||
|                     } | ||||
|                 } catch { } | ||||
|             } | ||||
|             // Break early if we can't complete the buys. | ||||
|             if (topBuyAmount == 0) { | ||||
|                 break; | ||||
|             } | ||||
|             makerTokenAmounts[i] = topBuyAmount; | ||||
|             uniswapPaths[i] = topUniswapPath; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// @dev Sample buy quotes from UniswapV3. | ||||
|     /// @param quoter UniswapV3 Quoter contract. | ||||
|     /// @param path Token route. Should be takerToken -> makerToken. | ||||
|     /// @param makerTokenAmounts Maker token buy amount for each sample. | ||||
|     /// @return uniswapPaths The encoded uniswap path for each sample. | ||||
|     /// @return takerTokenAmounts Taker amounts sold at each maker token | ||||
|     ///         amount. | ||||
|     function sampleBuysFromUniswapV3( | ||||
|         IUniswapV3Quoter quoter, | ||||
|         IERC20TokenV06[] memory path, | ||||
|         uint256[] memory makerTokenAmounts | ||||
|     ) | ||||
|         public | ||||
|         returns ( | ||||
|             bytes[] memory uniswapPaths, | ||||
|             uint256[] memory takerTokenAmounts | ||||
|         ) | ||||
|     { | ||||
|         IUniswapV3Pool[][] memory poolPaths = | ||||
|             _getValidPoolPaths(quoter.factory(), path, 0); | ||||
|         IERC20TokenV06[] memory reversedPath = _reverseTokenPath(path); | ||||
|  | ||||
|         takerTokenAmounts = new uint256[](makerTokenAmounts.length); | ||||
|         uniswapPaths = new bytes[](makerTokenAmounts.length); | ||||
|  | ||||
|         for (uint256 i = 0; i < makerTokenAmounts.length; ++i) { | ||||
|             // Pick the best result from all the paths. | ||||
|             bytes memory topUniswapPath; | ||||
|             uint256 topSellAmount = 0; | ||||
|             for (uint256 j = 0; j < poolPaths.length; ++j) { | ||||
|                 // quoter requires path to be reversed for buys. | ||||
|                 bytes memory uniswapPath = _toUniswapPath( | ||||
|                     reversedPath, | ||||
|                     _reversePoolPath(poolPaths[j]) | ||||
|                 ); | ||||
|                 try | ||||
|                     quoter.quoteExactOutput | ||||
|                         { gas: QUOTE_GAS } | ||||
|                         (uniswapPath, makerTokenAmounts[i]) | ||||
|                         returns (uint256 sellAmount) | ||||
|                 { | ||||
|                     if (topSellAmount == 0 || topSellAmount >= sellAmount) { | ||||
|                         topSellAmount = sellAmount; | ||||
|                         // But the output path should still be encoded for sells. | ||||
|                         topUniswapPath = _toUniswapPath(path, poolPaths[j]); | ||||
|                     } | ||||
|                 } catch {} | ||||
|             } | ||||
|             // Break early if we can't complete the buys. | ||||
|             if (topSellAmount == 0) { | ||||
|                 break; | ||||
|             } | ||||
|             takerTokenAmounts[i] = topSellAmount; | ||||
|             uniswapPaths[i] = topUniswapPath; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function _getValidPoolPaths( | ||||
|         IUniswapV3Factory factory, | ||||
|         IERC20TokenV06[] memory tokenPath, | ||||
|         uint256 startIndex | ||||
|     ) | ||||
|         private | ||||
|         view | ||||
|         returns (IUniswapV3Pool[][] memory poolPaths) | ||||
|     { | ||||
|         require( | ||||
|             tokenPath.length - startIndex >= 2, | ||||
|             "UniswapV3Sampler/tokenPath too short" | ||||
|         ); | ||||
|         uint24[3] memory validPoolFees = [ | ||||
|             // The launch pool fees. Could get hairier if they add more. | ||||
|             uint24(0.0005e6), | ||||
|             uint24(0.003e6), | ||||
|             uint24(0.01e6) | ||||
|         ]; | ||||
|         IUniswapV3Pool[] memory validPools = | ||||
|             new IUniswapV3Pool[](validPoolFees.length); | ||||
|         uint256 numValidPools = 0; | ||||
|         { | ||||
|             IERC20TokenV06 inputToken = tokenPath[startIndex]; | ||||
|             IERC20TokenV06 outputToken = tokenPath[startIndex + 1]; | ||||
|             for (uint256 i = 0; i < validPoolFees.length; ++i) { | ||||
|                 IUniswapV3Pool pool = | ||||
|                 factory.getPool(inputToken, outputToken, validPoolFees[i]); | ||||
|                 if (_isValidPool(pool)) { | ||||
|                     validPools[numValidPools++] = pool; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         if (numValidPools == 0) { | ||||
|             // No valid pools for this hop. | ||||
|             return poolPaths; | ||||
|         } | ||||
|         if (startIndex + 2 == tokenPath.length) { | ||||
|             // End of path. | ||||
|             poolPaths = new IUniswapV3Pool[][](numValidPools); | ||||
|             for (uint256 i = 0; i < numValidPools; ++i) { | ||||
|                 poolPaths[i] = new IUniswapV3Pool[](1); | ||||
|                 poolPaths[i][0] = validPools[i]; | ||||
|             } | ||||
|             return poolPaths; | ||||
|         } | ||||
|         // Get paths for subsequent hops. | ||||
|         IUniswapV3Pool[][] memory subsequentPoolPaths = | ||||
|             _getValidPoolPaths(factory, tokenPath, startIndex + 1); | ||||
|         if (subsequentPoolPaths.length == 0) { | ||||
|             // Could not complete the path. | ||||
|             return poolPaths; | ||||
|         } | ||||
|         // Combine our pools with the next hop paths. | ||||
|         poolPaths = new IUniswapV3Pool[][]( | ||||
|             numValidPools * subsequentPoolPaths.length | ||||
|         ); | ||||
|         for (uint256 i = 0; i < numValidPools; ++i) { | ||||
|             for (uint256 j = 0; j < subsequentPoolPaths.length; ++j) { | ||||
|                 uint256 o = i * subsequentPoolPaths.length + j; | ||||
|                 // Prepend pool to the subsequent path. | ||||
|                 poolPaths[o] = | ||||
|                     new IUniswapV3Pool[](1 + subsequentPoolPaths[j].length); | ||||
|                 poolPaths[o][0] = validPools[i]; | ||||
|                 for (uint256 k = 0; k < subsequentPoolPaths[j].length; ++k) { | ||||
|                     poolPaths[o][1 + k] = subsequentPoolPaths[j][k]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return poolPaths; | ||||
|     } | ||||
|  | ||||
|     function _reverseTokenPath(IERC20TokenV06[] memory tokenPath) | ||||
|         private | ||||
|         returns (IERC20TokenV06[] memory reversed) | ||||
|     { | ||||
|         reversed = new IERC20TokenV06[](tokenPath.length); | ||||
|         for (uint256 i = 0; i < tokenPath.length; ++i) { | ||||
|             reversed[i] = tokenPath[tokenPath.length - i - 1]; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function _reversePoolPath(IUniswapV3Pool[] memory poolPath) | ||||
|         private | ||||
|         returns (IUniswapV3Pool[] memory reversed) | ||||
|     { | ||||
|         reversed = new IUniswapV3Pool[](poolPath.length); | ||||
|         for (uint256 i = 0; i < poolPath.length; ++i) { | ||||
|             reversed[i] = poolPath[poolPath.length - i - 1]; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function _isValidPool(IUniswapV3Pool pool) | ||||
|         private | ||||
|         view | ||||
|         returns (bool isValid) | ||||
|     { | ||||
|         // Check if it has been deployed. | ||||
|         { | ||||
|             uint256 codeSize; | ||||
|             assembly { | ||||
|                 codeSize := extcodesize(pool) | ||||
|             } | ||||
|             if (codeSize == 0) { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         // Must have a balance of both tokens. | ||||
|         if (pool.token0().balanceOf(address(pool)) == 0) { | ||||
|             return false; | ||||
|         } | ||||
|         if (pool.token1().balanceOf(address(pool)) == 0) { | ||||
|             return false; | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     function _toUniswapPath( | ||||
|         IERC20TokenV06[] memory tokenPath, | ||||
|         IUniswapV3Pool[] memory poolPath | ||||
|     ) | ||||
|         private | ||||
|         view | ||||
|         returns (bytes memory uniswapPath) | ||||
|     { | ||||
|         require( | ||||
|             tokenPath.length >= 2 && tokenPath.length == poolPath.length + 1, | ||||
|             "UniswapV3Sampler/invalid path lengths" | ||||
|         ); | ||||
|         // Uniswap paths are tightly packed as: | ||||
|         // [token0, token0token1PairFee, token1, token1Token2PairFee, token2, ...] | ||||
|         uniswapPath = new bytes(tokenPath.length * 20 + poolPath.length * 3); | ||||
|         uint256 o; | ||||
|         assembly { o := add(uniswapPath, 32) } | ||||
|         for (uint256 i = 0; i < tokenPath.length; ++i) { | ||||
|             if (i > 0) { | ||||
|                 uint24 poolFee = poolPath[i - 1].fee(); | ||||
|                 assembly { | ||||
|                     mstore(o, shl(232, poolFee)) | ||||
|                     o := add(o, 3) | ||||
|                 } | ||||
|             } | ||||
|             IERC20TokenV06 token = tokenPath[i]; | ||||
|             assembly { | ||||
|                 mstore(o, shl(96, token)) | ||||
|                 o := add(o, 20) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|     "name": "@0x/asset-swapper", | ||||
|     "version": "6.8.0", | ||||
|     "version": "6.12.0", | ||||
|     "engines": { | ||||
|         "node": ">=6.12" | ||||
|     }, | ||||
| @@ -33,12 +33,13 @@ | ||||
|         "generate_contract_wrappers": "abi-gen --debug --abis  ${npm_package_config_abis} --output test/generated-wrappers --backend ethers", | ||||
|         "contracts:gen": "contracts-gen generate", | ||||
|         "contracts:copy": "contracts-gen copy", | ||||
|         "publish:private": "yarn build && gitpkg publish" | ||||
|         "publish:private": "yarn build && gitpkg publish", | ||||
|         "sampler-size": "jq .compilerOutput.evm.deployedBytecode.object  -- test/generated-artifacts/ERC20BridgeSampler.json | echo $(( $(wc -c) / 2 - 1 ))" | ||||
|     }, | ||||
|     "config": { | ||||
|         "publicInterfaceContracts": "ERC20BridgeSampler,BalanceChecker,FakeTaker", | ||||
|         "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", | ||||
|         "abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BancorSampler|CurveSampler|DODOSampler|DODOV2Sampler|DummyLiquidityProvider|ERC20BridgeSampler|Eth2DaiSampler|FakeTaker|IBalancer|IBancor|ICurve|IEth2Dai|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|ISmoothy|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MakerPSMSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SmoothySampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UtilitySampler).json", | ||||
|         "abis": "./test/generated-artifacts/@(ApproximateBuys|BalanceChecker|BalancerSampler|BalancerV2Sampler|BancorSampler|CurveSampler|DODOSampler|DODOV2Sampler|DummyLiquidityProvider|ERC20BridgeSampler|Eth2DaiSampler|FakeTaker|IBalancer|IBancor|ICurve|IEth2Dai|IKyberNetwork|IMStable|IMooniswap|IMultiBridge|IShell|ISmoothy|IUniswapExchangeQuotes|IUniswapV2Router01|KyberSampler|LiquidityProviderSampler|MStableSampler|MakerPSMSampler|MooniswapSampler|MultiBridgeSampler|NativeOrderSampler|SamplerUtils|ShellSampler|SmoothySampler|TestERC20BridgeSampler|TestNativeOrderSampler|TwoHopSampler|UniswapSampler|UniswapV2Sampler|UniswapV3Sampler|UtilitySampler).json", | ||||
|         "postpublish": { | ||||
|             "assets": [] | ||||
|         } | ||||
| @@ -57,20 +58,20 @@ | ||||
|         "registry": "git@github.com:0xProject/gitpkg-registry.git" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|         "@0x/assert": "^3.0.26", | ||||
|         "@0x/assert": "^3.0.27", | ||||
|         "@0x/base-contract": "^6.4.0", | ||||
|         "@0x/contract-addresses": "^6.0.0", | ||||
|         "@0x/contract-wrappers": "^13.16.0", | ||||
|         "@0x/contracts-erc20": "^3.3.7", | ||||
|         "@0x/contracts-zero-ex": "^0.22.1", | ||||
|         "@0x/dev-utils": "^4.2.6", | ||||
|         "@0x/json-schemas": "^6.1.2", | ||||
|         "@0x/protocol-utils": "^1.5.1", | ||||
|         "@0x/contract-addresses": "^6.1.0", | ||||
|         "@0x/contract-wrappers": "^13.16.1", | ||||
|         "@0x/contracts-erc20": "^3.3.8", | ||||
|         "@0x/contracts-zero-ex": "^0.23.0", | ||||
|         "@0x/dev-utils": "^4.2.7", | ||||
|         "@0x/json-schemas": "^6.1.3", | ||||
|         "@0x/protocol-utils": "^1.6.0", | ||||
|         "@0x/quote-server": "^5.0.0", | ||||
|         "@0x/types": "^3.3.3", | ||||
|         "@0x/typescript-typings": "^5.2.0", | ||||
|         "@0x/utils": "^6.4.2", | ||||
|         "@0x/web3-wrapper": "^7.5.2", | ||||
|         "@0x/utils": "^6.4.3", | ||||
|         "@0x/web3-wrapper": "^7.5.3", | ||||
|         "@balancer-labs/sor": "0.3.2", | ||||
|         "@bancor/sdk": "0.2.9", | ||||
|         "@ethersproject/abi": "^5.0.1", | ||||
| @@ -85,21 +86,23 @@ | ||||
|         "ethereum-types": "^3.5.0", | ||||
|         "ethereumjs-util": "^7.0.10", | ||||
|         "fast-abi": "^0.0.2", | ||||
|         "graphql": "^15.4.0", | ||||
|         "graphql-request": "^3.4.0", | ||||
|         "heartbeats": "^5.0.1", | ||||
|         "lodash": "^4.17.11" | ||||
|     }, | ||||
|     "devDependencies": { | ||||
|         "@0x/abi-gen": "^5.6.0", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.10", | ||||
|         "@0x/contracts-exchange": "^3.2.29", | ||||
|         "@0x/contracts-exchange-libs": "^4.3.28", | ||||
|         "@0x/contracts-gen": "^2.0.37", | ||||
|         "@0x/contracts-test-utils": "^5.3.25", | ||||
|         "@0x/contracts-utils": "^4.7.7", | ||||
|         "@0x/contracts-asset-proxy": "^3.7.11", | ||||
|         "@0x/contracts-exchange": "^3.2.30", | ||||
|         "@0x/contracts-exchange-libs": "^4.3.29", | ||||
|         "@0x/contracts-gen": "^2.0.38", | ||||
|         "@0x/contracts-test-utils": "^5.4.0", | ||||
|         "@0x/contracts-utils": "^4.7.8", | ||||
|         "@0x/mesh-rpc-client": "^9.4.2", | ||||
|         "@0x/migrations": "^8.0.3", | ||||
|         "@0x/sol-compiler": "^4.7.2", | ||||
|         "@0x/subproviders": "^6.5.2", | ||||
|         "@0x/migrations": "^8.0.6", | ||||
|         "@0x/sol-compiler": "^4.7.3", | ||||
|         "@0x/subproviders": "^6.5.3", | ||||
|         "@0x/ts-doc-gen": "^0.0.28", | ||||
|         "@0x/tslint-config": "^4.1.4", | ||||
|         "@0x/types": "^3.3.3", | ||||
|   | ||||
| @@ -115,6 +115,7 @@ export { | ||||
|     SOURCE_FLAGS, | ||||
|     BUY_SOURCE_FILTER_BY_CHAIN_ID, | ||||
|     SELL_SOURCE_FILTER_BY_CHAIN_ID, | ||||
|     NATIVE_FEE_TOKEN_BY_CHAIN_ID, | ||||
| } from './utils/market_operation_utils/constants'; | ||||
| export { | ||||
|     Parameters, | ||||
| @@ -160,6 +161,7 @@ export { | ||||
|     NativeRfqOrderQuoteReportEntry, | ||||
|     QuoteReport, | ||||
|     QuoteReportEntry, | ||||
|     PriceComparisonsReport, | ||||
| } from './utils/quote_report_generator'; | ||||
| export { QuoteRequestor } from './utils/quote_requestor'; | ||||
| export { ERC20BridgeSamplerContract, BalanceCheckerContract, FakeTakerContract } from './wrappers'; | ||||
|   | ||||
| @@ -13,8 +13,7 @@ import { | ||||
|     FillQuoteTransformerSide, | ||||
|     findTransformerNonce, | ||||
| } from '@0x/protocol-utils'; | ||||
| import { BigNumber, providerUtils } from '@0x/utils'; | ||||
| import { SupportedProvider, ZeroExProvider } from '@0x/web3-wrapper'; | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { constants, POSITIVE_SLIPPAGE_FEE_TRANSFORMER_GAS } from '../constants'; | ||||
| @@ -65,15 +64,26 @@ import { | ||||
| // tslint:disable-next-line:custom-no-magic-numbers | ||||
| const MAX_UINT256 = new BigNumber(2).pow(256).minus(1); | ||||
| const { NULL_ADDRESS, NULL_BYTES, ZERO_AMOUNT } = constants; | ||||
| const PANCAKE_SWAP_FORKS = [ERC20BridgeSource.PancakeSwap, ERC20BridgeSource.BakerySwap, ERC20BridgeSource.SushiSwap]; | ||||
| const DUMMY_WETH_CONTRACT = new WETH9Contract(NULL_ADDRESS, { | ||||
|  | ||||
| // use the same order in IPancakeSwapFeature.sol | ||||
| const PANCAKE_SWAP_FORKS = [ | ||||
|     ERC20BridgeSource.PancakeSwap, | ||||
|     ERC20BridgeSource.PancakeSwapV2, | ||||
|     ERC20BridgeSource.BakerySwap, | ||||
|     ERC20BridgeSource.SushiSwap, | ||||
|     ERC20BridgeSource.ApeSwap, | ||||
|     ERC20BridgeSource.CafeSwap, | ||||
|     ERC20BridgeSource.CheeseSwap, | ||||
|     ERC20BridgeSource.JulSwap, | ||||
| ]; | ||||
| const FAKE_PROVIDER: any = { | ||||
|     sendAsync(): void { | ||||
|         return; | ||||
|     }, | ||||
| } as any); | ||||
| }; | ||||
| const DUMMY_WETH_CONTRACT = new WETH9Contract(NULL_ADDRESS, FAKE_PROVIDER); | ||||
|  | ||||
| export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { | ||||
|     public readonly provider: ZeroExProvider; | ||||
|     public readonly chainId: ChainId; | ||||
|     public readonly transformerNonces: { | ||||
|         wethTransformer: number; | ||||
| @@ -86,19 +96,13 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { | ||||
|     private readonly _exchangeProxy: IZeroExContract; | ||||
|     private readonly _multiplex: MultiplexFeatureContract; | ||||
|  | ||||
|     constructor( | ||||
|         supportedProvider: SupportedProvider, | ||||
|         public readonly contractAddresses: ContractAddresses, | ||||
|         options: Partial<SwapQuoteConsumerOpts> = {}, | ||||
|     ) { | ||||
|     constructor(public readonly contractAddresses: ContractAddresses, options: Partial<SwapQuoteConsumerOpts> = {}) { | ||||
|         const { chainId } = _.merge({}, constants.DEFAULT_SWAP_QUOTER_OPTS, options); | ||||
|         assert.isNumber('chainId', chainId); | ||||
|         const provider = providerUtils.standardizeOrThrow(supportedProvider); | ||||
|         this.provider = provider; | ||||
|         this.chainId = chainId; | ||||
|         this.contractAddresses = contractAddresses; | ||||
|         this._exchangeProxy = new IZeroExContract(contractAddresses.exchangeProxy, supportedProvider); | ||||
|         this._multiplex = new MultiplexFeatureContract(contractAddresses.exchangeProxy, supportedProvider); | ||||
|         this._exchangeProxy = new IZeroExContract(contractAddresses.exchangeProxy, FAKE_PROVIDER); | ||||
|         this._multiplex = new MultiplexFeatureContract(contractAddresses.exchangeProxy, FAKE_PROVIDER); | ||||
|         this.transformerNonces = { | ||||
|             wethTransformer: findTransformerNonce( | ||||
|                 contractAddresses.transformers.wethTransformer, | ||||
| @@ -186,8 +190,13 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { | ||||
|             this.chainId === ChainId.BSC && | ||||
|             isDirectSwapCompatible(quote, optsWithDefaults, [ | ||||
|                 ERC20BridgeSource.PancakeSwap, | ||||
|                 ERC20BridgeSource.PancakeSwapV2, | ||||
|                 ERC20BridgeSource.BakerySwap, | ||||
|                 ERC20BridgeSource.SushiSwap, | ||||
|                 ERC20BridgeSource.ApeSwap, | ||||
|                 ERC20BridgeSource.CafeSwap, | ||||
|                 ERC20BridgeSource.CheeseSwap, | ||||
|                 ERC20BridgeSource.JulSwap, | ||||
|             ]) | ||||
|         ) { | ||||
|             const source = slippedOrders[0].source; | ||||
| @@ -243,7 +252,11 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { | ||||
|  | ||||
|         if ( | ||||
|             this.chainId === ChainId.Mainnet && | ||||
|             isDirectSwapCompatible(quote, optsWithDefaults, [ERC20BridgeSource.Curve, ERC20BridgeSource.Swerve]) | ||||
|             isDirectSwapCompatible(quote, optsWithDefaults, [ERC20BridgeSource.Curve, ERC20BridgeSource.Swerve]) && | ||||
|             // Curve VIP cannot currently support WETH buy/sell as the functionality needs to WITHDRAW or DEPOSIT | ||||
|             // into WETH prior/post the trade. | ||||
|             // ETH buy/sell is supported | ||||
|             ![sellToken, buyToken].includes(NATIVE_FEE_TOKEN_BY_CHAIN_ID[ChainId.Mainnet]) | ||||
|         ) { | ||||
|             const fillData = slippedOrders[0].fills[0].fillData as CurveFillData; | ||||
|             return { | ||||
| @@ -552,14 +565,17 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { | ||||
|  | ||||
|     private _encodeMultiplexMultiHopFillCalldata(quote: SwapQuote, opts: ExchangeProxyContractOpts): string { | ||||
|         const wrappedMultiHopCalls = []; | ||||
|         const tokens: string[] = []; | ||||
|         if (opts.isFromETH) { | ||||
|             wrappedMultiHopCalls.push({ | ||||
|                 selector: DUMMY_WETH_CONTRACT.getSelector('deposit'), | ||||
|                 data: NULL_BYTES, | ||||
|             }); | ||||
|             tokens.push(ETH_TOKEN_ADDRESS); | ||||
|         } | ||||
|         const [firstHopOrder, secondHopOrder] = quote.orders; | ||||
|         const intermediateToken = firstHopOrder.makerToken; | ||||
|         tokens.push(quote.takerToken, intermediateToken, quote.makerToken); | ||||
|         for (const order of [firstHopOrder, secondHopOrder]) { | ||||
|             switch (order.source) { | ||||
|                 case ERC20BridgeSource.UniswapV2: | ||||
| @@ -594,11 +610,12 @@ export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase { | ||||
|                 selector: DUMMY_WETH_CONTRACT.getSelector('withdraw'), | ||||
|                 data: NULL_BYTES, | ||||
|             }); | ||||
|             tokens.push(ETH_TOKEN_ADDRESS); | ||||
|         } | ||||
|         return this._exchangeProxy | ||||
|             .multiHopFill( | ||||
|                 { | ||||
|                     tokens: [quote.takerToken, intermediateToken, quote.makerToken], | ||||
|                     tokens, | ||||
|                     sellAmount: quote.worstCaseQuoteInfo.totalTakerAmount, | ||||
|                     calls: wrappedMultiHopCalls, | ||||
|                 }, | ||||
|   | ||||
| @@ -1,6 +1,4 @@ | ||||
| import { ContractAddresses, getContractAddressesForChainOrThrow } from '@0x/contract-addresses'; | ||||
| import { providerUtils } from '@0x/utils'; | ||||
| import { SupportedProvider, ZeroExProvider } from '@0x/web3-wrapper'; | ||||
| import * as _ from 'lodash'; | ||||
|  | ||||
| import { constants } from '../constants'; | ||||
| @@ -17,32 +15,22 @@ import { assert } from '../utils/assert'; | ||||
| import { ExchangeProxySwapQuoteConsumer } from './exchange_proxy_swap_quote_consumer'; | ||||
|  | ||||
| export class SwapQuoteConsumer implements SwapQuoteConsumerBase { | ||||
|     public readonly provider: ZeroExProvider; | ||||
|     public readonly chainId: number; | ||||
|  | ||||
|     private readonly _contractAddresses: ContractAddresses; | ||||
|     private readonly _exchangeProxyConsumer: ExchangeProxySwapQuoteConsumer; | ||||
|  | ||||
|     public static getSwapQuoteConsumer( | ||||
|         supportedProvider: SupportedProvider, | ||||
|         options: Partial<SwapQuoteConsumerOpts> = {}, | ||||
|     ): SwapQuoteConsumer { | ||||
|         return new SwapQuoteConsumer(supportedProvider, options); | ||||
|     public static getSwapQuoteConsumer(options: Partial<SwapQuoteConsumerOpts> = {}): SwapQuoteConsumer { | ||||
|         return new SwapQuoteConsumer(options); | ||||
|     } | ||||
|  | ||||
|     constructor(supportedProvider: SupportedProvider, options: Partial<SwapQuoteConsumerOpts> = {}) { | ||||
|     constructor(options: Partial<SwapQuoteConsumerOpts> = {}) { | ||||
|         const { chainId } = _.merge({}, constants.DEFAULT_SWAP_QUOTER_OPTS, options); | ||||
|         assert.isNumber('chainId', chainId); | ||||
|  | ||||
|         const provider = providerUtils.standardizeOrThrow(supportedProvider); | ||||
|         this.provider = provider; | ||||
|         this.chainId = chainId; | ||||
|         this._contractAddresses = options.contractAddresses || getContractAddressesForChainOrThrow(chainId); | ||||
|         this._exchangeProxyConsumer = new ExchangeProxySwapQuoteConsumer( | ||||
|             supportedProvider, | ||||
|             this._contractAddresses, | ||||
|             options, | ||||
|         ); | ||||
|         this._exchangeProxyConsumer = new ExchangeProxySwapQuoteConsumer(this._contractAddresses, options); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -27,7 +27,7 @@ import { | ||||
| import { assert } from './utils/assert'; | ||||
| import { MarketOperationUtils } from './utils/market_operation_utils'; | ||||
| import { BancorService } from './utils/market_operation_utils/bancor_service'; | ||||
| import { SOURCE_FLAGS, ZERO_AMOUNT } from './utils/market_operation_utils/constants'; | ||||
| import { SAMPLER_ADDRESS, SOURCE_FLAGS, ZERO_AMOUNT } from './utils/market_operation_utils/constants'; | ||||
| import { DexOrderSampler } from './utils/market_operation_utils/sampler'; | ||||
| import { SourceFilters } from './utils/market_operation_utils/source_filters'; | ||||
| import { | ||||
| @@ -93,7 +93,7 @@ export class SwapQuoter { | ||||
|             rfqt, | ||||
|             tokenAdjacencyGraph, | ||||
|             liquidityProviderRegistry, | ||||
|         } = _.merge({}, constants.DEFAULT_SWAP_QUOTER_OPTS, options); | ||||
|         } = { ...constants.DEFAULT_SWAP_QUOTER_OPTS, ...options }; | ||||
|         const provider = providerUtils.standardizeOrThrow(supportedProvider); | ||||
|         assert.isValidOrderbook('orderbook', orderbook); | ||||
|         assert.isNumber('chainId', chainId); | ||||
| @@ -114,9 +114,11 @@ export class SwapQuoter { | ||||
|         ); | ||||
|         // Allow the sampler bytecode to be overwritten using geths override functionality | ||||
|         const samplerBytecode = _.get(artifacts.ERC20BridgeSampler, 'compilerOutput.evm.deployedBytecode.object'); | ||||
|         // Allow address of the Sampler to be overridden, i.e in Ganache where overrides do not work | ||||
|         const samplerAddress = (options.samplerOverrides && options.samplerOverrides.to) || SAMPLER_ADDRESS; | ||||
|         const defaultCodeOverrides = samplerBytecode | ||||
|             ? { | ||||
|                   [this._contractAddresses.erc20BridgeSampler]: { code: samplerBytecode }, | ||||
|                   [samplerAddress]: { code: samplerBytecode }, | ||||
|               } | ||||
|             : {}; | ||||
|         const samplerOverrides = _.assign( | ||||
| @@ -125,7 +127,7 @@ export class SwapQuoter { | ||||
|         ); | ||||
|         const fastAbi = new FastABI(ERC20BridgeSamplerContract.ABI() as MethodAbi[]); | ||||
|         const samplerContract = new ERC20BridgeSamplerContract( | ||||
|             this._contractAddresses.erc20BridgeSampler, | ||||
|             samplerAddress, | ||||
|             this.provider, | ||||
|             { | ||||
|                 gas: samplerGasLimit, | ||||
| @@ -143,8 +145,7 @@ export class SwapQuoter { | ||||
|                 this.chainId, | ||||
|                 samplerContract, | ||||
|                 samplerOverrides, | ||||
|                 undefined, // balancer pool cache | ||||
|                 undefined, // cream pool cache | ||||
|                 undefined, // pools caches for balancer and cream | ||||
|                 tokenAdjacencyGraph, | ||||
|                 liquidityProviderRegistry, | ||||
|                 this.chainId === ChainId.Mainnet // Enable Bancor only on Mainnet | ||||
| @@ -496,7 +497,14 @@ function createSwapQuote( | ||||
|     gasSchedule: FeeSchedule, | ||||
|     slippage: number, | ||||
| ): SwapQuote { | ||||
|     const { optimizedOrders, quoteReport, sourceFlags, takerAmountPerEth, makerAmountPerEth } = optimizerResult; | ||||
|     const { | ||||
|         optimizedOrders, | ||||
|         quoteReport, | ||||
|         sourceFlags, | ||||
|         takerAmountPerEth, | ||||
|         makerAmountPerEth, | ||||
|         priceComparisonsReport, | ||||
|     } = optimizerResult; | ||||
|     const isTwoHop = sourceFlags === SOURCE_FLAGS[ERC20BridgeSource.MultiHop]; | ||||
|  | ||||
|     // Calculate quote info | ||||
| @@ -520,6 +528,7 @@ function createSwapQuote( | ||||
|         makerAmountPerEth, | ||||
|         quoteReport, | ||||
|         isTwoHop, | ||||
|         priceComparisonsReport, | ||||
|     }; | ||||
|  | ||||
|     if (operation === MarketOperation.Buy) { | ||||
|   | ||||
| @@ -18,7 +18,7 @@ import { | ||||
|     OptimizedMarketOrder, | ||||
|     TokenAdjacencyGraph, | ||||
| } from './utils/market_operation_utils/types'; | ||||
| import { QuoteReport } from './utils/quote_report_generator'; | ||||
| import { PriceComparisonsReport, QuoteReport } from './utils/quote_report_generator'; | ||||
|  | ||||
| /** | ||||
|  * expiryBufferMs: The number of seconds to add when calculating whether an order is expired or not. Defaults to 300s (5m). | ||||
| @@ -169,6 +169,7 @@ export interface SwapQuoteBase { | ||||
|     worstCaseQuoteInfo: SwapQuoteInfo; | ||||
|     sourceBreakdown: SwapQuoteOrdersBreakdown; | ||||
|     quoteReport?: QuoteReport; | ||||
|     priceComparisonsReport?: PriceComparisonsReport; | ||||
|     isTwoHop: boolean; | ||||
|     makerTokenDecimals: number; | ||||
|     takerTokenDecimals: number; | ||||
| @@ -385,6 +386,7 @@ export interface AltMockedRfqQuoteResponse { | ||||
| export interface SamplerOverrides { | ||||
|     overrides: GethCallOverrides; | ||||
|     block: BlockParam; | ||||
|     to?: string; | ||||
| } | ||||
|  | ||||
| export interface SamplerCallResult { | ||||
|   | ||||
| @@ -1,192 +0,0 @@ | ||||
| import { getPoolsWithTokens, parsePoolData } from '@balancer-labs/sor'; | ||||
| import { Pool } from '@balancer-labs/sor/dist/types'; | ||||
|  | ||||
| import { BALANCER_MAX_POOLS_FETCHED, BALANCER_SUBGRAPH_URL, BALANCER_TOP_POOLS_FETCHED } from './constants'; | ||||
|  | ||||
| // tslint:disable:boolean-naming | ||||
|  | ||||
| interface CacheValue { | ||||
|     timestamp: number; | ||||
|     pools: Pool[]; | ||||
| } | ||||
|  | ||||
| // tslint:disable:custom-no-magic-numbers | ||||
| const FIVE_SECONDS_MS = 5 * 1000; | ||||
| const ONE_DAY_MS = 24 * 60 * 60 * 1000; | ||||
| const DEFAULT_TIMEOUT_MS = 1000; | ||||
| // tslint:enable:custom-no-magic-numbers | ||||
|  | ||||
| interface BalancerPoolResponse { | ||||
|     id: string; | ||||
|     swapFee: string; | ||||
|     tokens: Array<{ address: string; decimals: number; balance: string }>; | ||||
|     tokensList: string[]; | ||||
|     totalWeight: string; | ||||
| } | ||||
|  | ||||
| export class BalancerPoolsCache { | ||||
|     constructor( | ||||
|         private readonly _cache: { [key: string]: CacheValue } = {}, | ||||
|         private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED, | ||||
|         private readonly subgraphUrl: string = BALANCER_SUBGRAPH_URL, | ||||
|         private readonly topPoolsFetched: number = BALANCER_TOP_POOLS_FETCHED, | ||||
|     ) { | ||||
|         void this._loadTopPoolsAsync(); | ||||
|         // Reload the top pools every 12 hours | ||||
|         setInterval(async () => void this._loadTopPoolsAsync(), ONE_DAY_MS / 2); | ||||
|     } | ||||
|  | ||||
|     public async getPoolsForPairAsync( | ||||
|         takerToken: string, | ||||
|         makerToken: string, | ||||
|         timeoutMs: number = DEFAULT_TIMEOUT_MS, | ||||
|     ): Promise<Pool[]> { | ||||
|         const timeout = new Promise<Pool[]>(resolve => setTimeout(resolve, timeoutMs, [])); | ||||
|         return Promise.race([this._getPoolsForPairAsync(takerToken, makerToken), timeout]); | ||||
|     } | ||||
|  | ||||
|     public getCachedPoolAddressesForPair( | ||||
|         takerToken: string, | ||||
|         makerToken: string, | ||||
|         cacheExpiryMs?: number, | ||||
|     ): string[] | undefined { | ||||
|         const key = JSON.stringify([takerToken, makerToken]); | ||||
|         const value = this._cache[key]; | ||||
|         if (cacheExpiryMs === undefined) { | ||||
|             return value === undefined ? [] : value.pools.map(pool => pool.id); | ||||
|         } | ||||
|         const minTimestamp = Date.now() - cacheExpiryMs; | ||||
|         if (value === undefined || value.timestamp < minTimestamp) { | ||||
|             return undefined; | ||||
|         } else { | ||||
|             return value.pools.map(pool => pool.id); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public howToSampleBalancer( | ||||
|         takerToken: string, | ||||
|         makerToken: string, | ||||
|         isAllowedSource: boolean, | ||||
|     ): { onChain: boolean; offChain: boolean } { | ||||
|         // If Balancer is excluded as a source, do not sample. | ||||
|         if (!isAllowedSource) { | ||||
|             return { onChain: false, offChain: false }; | ||||
|         } | ||||
|         const cachedBalancerPools = this.getCachedPoolAddressesForPair(takerToken, makerToken, ONE_DAY_MS); | ||||
|         // Sample Balancer on-chain (i.e. via the ERC20BridgeSampler contract) if: | ||||
|         // - Cached values are not stale | ||||
|         // - There is at least one Balancer pool for this pair | ||||
|         const onChain = cachedBalancerPools !== undefined && cachedBalancerPools.length > 0; | ||||
|         // Sample Balancer off-chain (i.e. via GraphQL query + `computeBalancerBuy/SellQuote`) | ||||
|         // if cached values are stale | ||||
|         const offChain = cachedBalancerPools === undefined; | ||||
|         return { onChain, offChain }; | ||||
|     } | ||||
|  | ||||
|     protected async _getPoolsForPairAsync( | ||||
|         takerToken: string, | ||||
|         makerToken: string, | ||||
|         cacheExpiryMs: number = FIVE_SECONDS_MS, | ||||
|     ): Promise<Pool[]> { | ||||
|         const key = JSON.stringify([takerToken, makerToken]); | ||||
|         const value = this._cache[key]; | ||||
|         const minTimestamp = Date.now() - cacheExpiryMs; | ||||
|         if (value === undefined || value.timestamp < minTimestamp) { | ||||
|             const pools = await this._fetchPoolsForPairAsync(takerToken, makerToken); | ||||
|             this._cachePoolsForPair(takerToken, makerToken, pools); | ||||
|         } | ||||
|         return this._cache[key].pools; | ||||
|     } | ||||
|  | ||||
|     protected _cachePoolsForPair(takerToken: string, makerToken: string, pools: Pool[]): void { | ||||
|         const key = JSON.stringify([takerToken, makerToken]); | ||||
|         this._cache[key] = { | ||||
|             pools, | ||||
|             timestamp: Date.now(), | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     protected async _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> { | ||||
|         try { | ||||
|             const poolData = (await getPoolsWithTokens(takerToken, makerToken)).pools; | ||||
|             // Sort by maker token balance (descending) | ||||
|             const pools = parsePoolData(poolData, takerToken, makerToken).sort((a, b) => | ||||
|                 b.balanceOut.minus(a.balanceOut).toNumber(), | ||||
|             ); | ||||
|             return pools.length > this.maxPoolsFetched ? pools.slice(0, this.maxPoolsFetched) : pools; | ||||
|         } catch (err) { | ||||
|             return []; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     protected async _loadTopPoolsAsync(): Promise<void> { | ||||
|         const fromToPools: { | ||||
|             [from: string]: { [to: string]: Pool[] }; | ||||
|         } = {}; | ||||
|  | ||||
|         const pools = await this._fetchTopPoolsAsync(); | ||||
|         pools.forEach(pool => { | ||||
|             const { tokensList } = pool; | ||||
|             for (const from of tokensList) { | ||||
|                 for (const to of tokensList.filter(t => t.toLowerCase() !== from.toLowerCase())) { | ||||
|                     if (!fromToPools[from]) { | ||||
|                         fromToPools[from] = {}; | ||||
|                     } | ||||
|                     if (!fromToPools[from][to]) { | ||||
|                         fromToPools[from][to] = []; | ||||
|                     } | ||||
|                     try { | ||||
|                         // The list of pools must be relevant to `from` and `to`  for `parsePoolData` | ||||
|                         const poolData = parsePoolData([pool], from, to); | ||||
|                         fromToPools[from][to].push(poolData[0]); | ||||
|                         // Cache this as we progress through | ||||
|                         this._cachePoolsForPair(from, to, fromToPools[from][to]); | ||||
|                     } catch { | ||||
|                         // soldier on | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     protected async _fetchTopPoolsAsync(): Promise<BalancerPoolResponse[]> { | ||||
|         const query = ` | ||||
|       query { | ||||
|           pools (first: ${ | ||||
|               this.topPoolsFetched | ||||
|           }, where: {publicSwap: true, liquidity_gt: 0}, orderBy: swapsCount, orderDirection: desc) { | ||||
|             id | ||||
|             publicSwap | ||||
|             swapFee | ||||
|             totalWeight | ||||
|             tokensList | ||||
|             tokens { | ||||
|               id | ||||
|               address | ||||
|               balance | ||||
|               decimals | ||||
|               symbol | ||||
|               denormWeight | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|     `; | ||||
|         try { | ||||
|             const response = await fetch(this.subgraphUrl, { | ||||
|                 method: 'POST', | ||||
|                 headers: { | ||||
|                     Accept: 'application/json', | ||||
|                     'Content-Type': 'application/json', | ||||
|                 }, | ||||
|                 body: JSON.stringify({ | ||||
|                     query, | ||||
|                 }), | ||||
|             }); | ||||
|  | ||||
|             const { data } = await response.json(); | ||||
|             return data.pools; | ||||
|         } catch (err) { | ||||
|             return []; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -2,12 +2,17 @@ import { ChainId } from '@0x/contract-addresses'; | ||||
| import { BigNumber, NULL_BYTES } from '@0x/utils'; | ||||
|  | ||||
| import { | ||||
|     APESWAP_ROUTER_BY_CHAIN_ID, | ||||
|     BAKERYSWAP_ROUTER_BY_CHAIN_ID, | ||||
|     BELT_BSC_INFOS, | ||||
|     CAFESWAP_ROUTER_BY_CHAIN_ID, | ||||
|     CHEESESWAP_ROUTER_BY_CHAIN_ID, | ||||
|     COMPONENT_POOLS_BY_CHAIN_ID, | ||||
|     CRYPTO_COM_ROUTER_BY_CHAIN_ID, | ||||
|     CURVE_MAINNET_INFOS, | ||||
|     ELLIPSIS_BSC_INFOS, | ||||
|     JULSWAP_ROUTER_BY_CHAIN_ID, | ||||
|     KYBER_BANNED_RESERVES, | ||||
|     KYBER_BRIDGED_LIQUIDITY_PREFIX, | ||||
|     KYBER_DMM_ROUTER_BY_CHAIN_ID, | ||||
|     MAX_DODOV2_POOLS_QUERIED, | ||||
| @@ -15,7 +20,7 @@ import { | ||||
|     NERVE_BSC_INFOS, | ||||
|     NULL_ADDRESS, | ||||
|     PANCAKESWAP_ROUTER_BY_CHAIN_ID, | ||||
|     PANCAKESWAP_V2_ROUTER_BY_CHAIN_ID, | ||||
|     PANCAKESWAPV2_ROUTER_BY_CHAIN_ID, | ||||
|     SADDLE_MAINNET_INFOS, | ||||
|     SHELL_POOLS_BY_CHAIN_ID, | ||||
|     SMOOTHY_BSC_INFOS, | ||||
| @@ -24,6 +29,7 @@ import { | ||||
|     SUSHISWAP_ROUTER_BY_CHAIN_ID, | ||||
|     SWERVE_MAINNET_INFOS, | ||||
|     UNISWAPV2_ROUTER_BY_CHAIN_ID, | ||||
|     XSIGMA_MAINNET_INFOS, | ||||
| } from './constants'; | ||||
| import { CurveInfo, ERC20BridgeSource } from './types'; | ||||
|  | ||||
| @@ -32,7 +38,11 @@ import { CurveInfo, ERC20BridgeSource } from './types'; | ||||
|  * @param reserveId Kyber reserveId | ||||
|  */ | ||||
| export function isAllowedKyberReserveId(reserveId: string): boolean { | ||||
|     return reserveId !== NULL_BYTES && !reserveId.startsWith(KYBER_BRIDGED_LIQUIDITY_PREFIX); | ||||
|     return ( | ||||
|         reserveId !== NULL_BYTES && | ||||
|         !reserveId.startsWith(KYBER_BRIDGED_LIQUIDITY_PREFIX) && | ||||
|         !KYBER_BANNED_RESERVES.includes(reserveId) | ||||
|     ); | ||||
| } | ||||
|  | ||||
| // tslint:disable-next-line: completed-docs ban-types | ||||
| @@ -194,6 +204,19 @@ export function getSaddleInfosForPair(chainId: ChainId, takerToken: string, make | ||||
|     ); | ||||
| } | ||||
|  | ||||
| export function getXSigmaInfosForPair(chainId: ChainId, takerToken: string, makerToken: string): CurveInfo[] { | ||||
|     if (chainId !== ChainId.Mainnet) { | ||||
|         return []; | ||||
|     } | ||||
|     return Object.values(XSIGMA_MAINNET_INFOS).filter(c => | ||||
|         [makerToken, takerToken].every( | ||||
|             t => | ||||
|                 (c.tokens.includes(t) && c.metaToken === undefined) || | ||||
|                 (c.tokens.includes(t) && c.metaToken !== undefined && [makerToken, takerToken].includes(c.metaToken)), | ||||
|         ), | ||||
|     ); | ||||
| } | ||||
|  | ||||
| export function getShellLikeInfosForPair( | ||||
|     chainId: ChainId, | ||||
|     takerToken: string, | ||||
| @@ -210,6 +233,11 @@ export function getShellLikeInfosForPair( | ||||
|     } | ||||
| } | ||||
|  | ||||
| export interface CurveDetailedInfo extends CurveInfo { | ||||
|     makerTokenIdx: number; | ||||
|     takerTokenIdx: number; | ||||
| } | ||||
|  | ||||
| export function getCurveLikeInfosForPair( | ||||
|     chainId: ChainId, | ||||
|     takerToken: string, | ||||
| @@ -222,28 +250,46 @@ export function getCurveLikeInfosForPair( | ||||
|         | ERC20BridgeSource.Belt | ||||
|         | ERC20BridgeSource.Ellipsis | ||||
|         | ERC20BridgeSource.Smoothy | ||||
|         | ERC20BridgeSource.Saddle, | ||||
| ): CurveInfo[] { | ||||
|         | ERC20BridgeSource.Saddle | ||||
|         | ERC20BridgeSource.XSigma, | ||||
| ): CurveDetailedInfo[] { | ||||
|     let pools: CurveInfo[] = []; | ||||
|     switch (source) { | ||||
|         case ERC20BridgeSource.Curve: | ||||
|             return getCurveInfosForPair(chainId, takerToken, makerToken); | ||||
|             pools = getCurveInfosForPair(chainId, takerToken, makerToken); | ||||
|             break; | ||||
|         case ERC20BridgeSource.Swerve: | ||||
|             return getSwerveInfosForPair(chainId, takerToken, makerToken); | ||||
|             pools = getSwerveInfosForPair(chainId, takerToken, makerToken); | ||||
|             break; | ||||
|         case ERC20BridgeSource.SnowSwap: | ||||
|             return getSnowSwapInfosForPair(chainId, takerToken, makerToken); | ||||
|             pools = getSnowSwapInfosForPair(chainId, takerToken, makerToken); | ||||
|             break; | ||||
|         case ERC20BridgeSource.Nerve: | ||||
|             return getNerveInfosForPair(chainId, takerToken, makerToken); | ||||
|             pools = getNerveInfosForPair(chainId, takerToken, makerToken); | ||||
|             break; | ||||
|         case ERC20BridgeSource.Belt: | ||||
|             return getBeltInfosForPair(chainId, takerToken, makerToken); | ||||
|             pools = getBeltInfosForPair(chainId, takerToken, makerToken); | ||||
|             break; | ||||
|         case ERC20BridgeSource.Ellipsis: | ||||
|             return getEllipsisInfosForPair(chainId, takerToken, makerToken); | ||||
|             pools = getEllipsisInfosForPair(chainId, takerToken, makerToken); | ||||
|             break; | ||||
|         case ERC20BridgeSource.Smoothy: | ||||
|             return getSmoothyInfosForPair(chainId, takerToken, makerToken); | ||||
|             pools = getSmoothyInfosForPair(chainId, takerToken, makerToken); | ||||
|             break; | ||||
|         case ERC20BridgeSource.Saddle: | ||||
|             return getSaddleInfosForPair(chainId, takerToken, makerToken); | ||||
|             pools = getSaddleInfosForPair(chainId, takerToken, makerToken); | ||||
|             break; | ||||
|         case ERC20BridgeSource.XSigma: | ||||
|             pools = getXSigmaInfosForPair(chainId, takerToken, makerToken); | ||||
|             break; | ||||
|         default: | ||||
|             throw new Error(`Unknown Curve like source ${source}`); | ||||
|     } | ||||
|     return pools.map(pool => ({ | ||||
|         ...pool, | ||||
|         makerTokenIdx: pool.tokens.indexOf(makerToken), | ||||
|         takerTokenIdx: pool.tokens.indexOf(takerToken), | ||||
|     })); | ||||
| } | ||||
|  | ||||
| export function uniswapV2LikeRouterAddress( | ||||
| @@ -253,9 +299,13 @@ export function uniswapV2LikeRouterAddress( | ||||
|         | ERC20BridgeSource.SushiSwap | ||||
|         | ERC20BridgeSource.CryptoCom | ||||
|         | ERC20BridgeSource.PancakeSwap | ||||
|         | ERC20BridgeSource.PancakeSwapV2 | ||||
|         | ERC20BridgeSource.BakerySwap | ||||
|         | ERC20BridgeSource.KyberDmm | ||||
|         | ERC20BridgeSource.PancakeSwapV2, | ||||
|         | ERC20BridgeSource.ApeSwap | ||||
|         | ERC20BridgeSource.CafeSwap | ||||
|         | ERC20BridgeSource.CheeseSwap | ||||
|         | ERC20BridgeSource.JulSwap, | ||||
| ): string { | ||||
|     switch (source) { | ||||
|         case ERC20BridgeSource.UniswapV2: | ||||
| @@ -266,12 +316,20 @@ export function uniswapV2LikeRouterAddress( | ||||
|             return CRYPTO_COM_ROUTER_BY_CHAIN_ID[chainId]; | ||||
|         case ERC20BridgeSource.PancakeSwap: | ||||
|             return PANCAKESWAP_ROUTER_BY_CHAIN_ID[chainId]; | ||||
|         case ERC20BridgeSource.PancakeSwapV2: | ||||
|             return PANCAKESWAPV2_ROUTER_BY_CHAIN_ID[chainId]; | ||||
|         case ERC20BridgeSource.BakerySwap: | ||||
|             return BAKERYSWAP_ROUTER_BY_CHAIN_ID[chainId]; | ||||
|         case ERC20BridgeSource.KyberDmm: | ||||
|             return KYBER_DMM_ROUTER_BY_CHAIN_ID[chainId]; | ||||
|         case ERC20BridgeSource.PancakeSwapV2: | ||||
|             return PANCAKESWAP_V2_ROUTER_BY_CHAIN_ID[chainId]; | ||||
|         case ERC20BridgeSource.ApeSwap: | ||||
|             return APESWAP_ROUTER_BY_CHAIN_ID[chainId]; | ||||
|         case ERC20BridgeSource.CafeSwap: | ||||
|             return CAFESWAP_ROUTER_BY_CHAIN_ID[chainId]; | ||||
|         case ERC20BridgeSource.CheeseSwap: | ||||
|             return CHEESESWAP_ROUTER_BY_CHAIN_ID[chainId]; | ||||
|         case ERC20BridgeSource.JulSwap: | ||||
|             return JULSWAP_ROUTER_BY_CHAIN_ID[chainId]; | ||||
|         default: | ||||
|             throw new Error(`Unknown UniswapV2 like source ${source}`); | ||||
|     } | ||||
|   | ||||
| @@ -24,6 +24,7 @@ import { | ||||
|     PsmInfo, | ||||
|     TokenAdjacencyGraph, | ||||
|     UniswapV2FillData, | ||||
|     UniswapV3FillData, | ||||
| } from './types'; | ||||
|  | ||||
| // tslint:disable: custom-no-magic-numbers no-bitwise | ||||
| @@ -39,6 +40,7 @@ export const ONE_HOUR_IN_SECONDS = 60 * 60; | ||||
| export const ONE_SECOND_MS = 1000; | ||||
| export const NULL_BYTES = '0x'; | ||||
| export const NULL_ADDRESS = '0x0000000000000000000000000000000000000000'; | ||||
| export const SAMPLER_ADDRESS = '0x5555555555555555555555555555555555555555'; | ||||
| export const COMPARISON_PRICE_DECIMALS = 10; | ||||
|  | ||||
| function valueByChainId<T>(rest: Partial<{ [key in ChainId]: T }>, defaultValue: T): { [key in ChainId]: T } { | ||||
| @@ -67,6 +69,7 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>( | ||||
|             ERC20BridgeSource.Kyber, | ||||
|             ERC20BridgeSource.Curve, | ||||
|             ERC20BridgeSource.Balancer, | ||||
|             ERC20BridgeSource.BalancerV2, | ||||
|             ERC20BridgeSource.Bancor, | ||||
|             ERC20BridgeSource.MStable, | ||||
|             ERC20BridgeSource.Mooniswap, | ||||
| @@ -86,6 +89,8 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>( | ||||
|             ERC20BridgeSource.Smoothy, | ||||
|             ERC20BridgeSource.Component, | ||||
|             ERC20BridgeSource.Saddle, | ||||
|             ERC20BridgeSource.XSigma, | ||||
|             ERC20BridgeSource.UniswapV3, | ||||
|         ]), | ||||
|         [ChainId.Ropsten]: new SourceFilters([ | ||||
|             ERC20BridgeSource.Kyber, | ||||
| @@ -93,6 +98,7 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>( | ||||
|             ERC20BridgeSource.SushiSwap, | ||||
|             ERC20BridgeSource.Uniswap, | ||||
|             ERC20BridgeSource.UniswapV2, | ||||
|             ERC20BridgeSource.UniswapV3, | ||||
|         ]), | ||||
|         [ChainId.Rinkeby]: new SourceFilters([ERC20BridgeSource.Native]), | ||||
|         [ChainId.Kovan]: new SourceFilters([ERC20BridgeSource.Native]), | ||||
| @@ -107,9 +113,13 @@ export const SELL_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>( | ||||
|             ERC20BridgeSource.MultiHop, | ||||
|             ERC20BridgeSource.Nerve, | ||||
|             ERC20BridgeSource.PancakeSwap, | ||||
|             ERC20BridgeSource.PancakeSwapV2, | ||||
|             ERC20BridgeSource.SushiSwap, | ||||
|             ERC20BridgeSource.Smoothy, | ||||
|             ERC20BridgeSource.PancakeSwapV2, | ||||
|             ERC20BridgeSource.ApeSwap, | ||||
|             ERC20BridgeSource.CafeSwap, | ||||
|             ERC20BridgeSource.CheeseSwap, | ||||
|             ERC20BridgeSource.JulSwap, | ||||
|         ]), | ||||
|     }, | ||||
|  | ||||
| @@ -129,6 +139,7 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>( | ||||
|             ERC20BridgeSource.Kyber, | ||||
|             ERC20BridgeSource.Curve, | ||||
|             ERC20BridgeSource.Balancer, | ||||
|             ERC20BridgeSource.BalancerV2, | ||||
|             // ERC20BridgeSource.Bancor, // FIXME: Bancor Buys not implemented in Sampler | ||||
|             ERC20BridgeSource.MStable, | ||||
|             ERC20BridgeSource.Mooniswap, | ||||
| @@ -148,6 +159,8 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>( | ||||
|             ERC20BridgeSource.Smoothy, | ||||
|             ERC20BridgeSource.Component, | ||||
|             ERC20BridgeSource.Saddle, | ||||
|             ERC20BridgeSource.XSigma, | ||||
|             ERC20BridgeSource.UniswapV3, | ||||
|         ]), | ||||
|         [ChainId.Ropsten]: new SourceFilters([ | ||||
|             ERC20BridgeSource.Kyber, | ||||
| @@ -155,6 +168,7 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>( | ||||
|             ERC20BridgeSource.SushiSwap, | ||||
|             ERC20BridgeSource.Uniswap, | ||||
|             ERC20BridgeSource.UniswapV2, | ||||
|             ERC20BridgeSource.UniswapV3, | ||||
|         ]), | ||||
|         [ChainId.Rinkeby]: new SourceFilters([ERC20BridgeSource.Native]), | ||||
|         [ChainId.Kovan]: new SourceFilters([ERC20BridgeSource.Native]), | ||||
| @@ -169,9 +183,13 @@ export const BUY_SOURCE_FILTER_BY_CHAIN_ID = valueByChainId<SourceFilters>( | ||||
|             ERC20BridgeSource.MultiHop, | ||||
|             ERC20BridgeSource.Nerve, | ||||
|             ERC20BridgeSource.PancakeSwap, | ||||
|             ERC20BridgeSource.PancakeSwapV2, | ||||
|             ERC20BridgeSource.SushiSwap, | ||||
|             ERC20BridgeSource.Smoothy, | ||||
|             ERC20BridgeSource.PancakeSwapV2, | ||||
|             ERC20BridgeSource.ApeSwap, | ||||
|             ERC20BridgeSource.CafeSwap, | ||||
|             ERC20BridgeSource.CheeseSwap, | ||||
|             ERC20BridgeSource.JulSwap, | ||||
|         ]), | ||||
|     }, | ||||
|     new SourceFilters([]), | ||||
| @@ -285,6 +303,7 @@ export const MAINNET_TOKENS = { | ||||
|     STABLEx: '0xcd91538b91b4ba7797d39a2f66e63810b50a33d0', | ||||
|     alUSD: '0xbc6da0fe9ad5f3b0d58160288917aa56653660e9', | ||||
|     FRAX: '0x853d955acef822db058eb8505911ed77f175b99e', | ||||
|     LUSD: '0x5f98805a4e8be255a32880fdec7f6728c6568ba0', | ||||
| }; | ||||
|  | ||||
| export const BSC_TOKENS = { | ||||
| @@ -321,11 +340,11 @@ export const CURVE_POOLS = { | ||||
|     oBTC: '0xd81da8d904b52208541bade1bd6595d8a251f8dd', // 21.obtc | ||||
|     UST: '0x890f4e345b1daed0367a877a1612f86a1f86985f', // 22.ust | ||||
|     eurs: '0x0ce6a5ff5217e38315f87032cf90686c96627caa', // 23.eurs | ||||
|     // seth: '0xc5424b857f758e906013f3555dad202e4bdb4567', // 24.seth | ||||
|     seth: '0xc5424b857f758e906013f3555dad202e4bdb4567', // 24.seth | ||||
|     aave: '0xdebf20617708857ebe4f679508e7b7863a8a8eee', // 25.aave | ||||
|     // curve steth: '0xdc24316b9ae028f1497c275eb9192a3ea0f67022' // 26.stETH | ||||
|     steth: '0xdc24316b9ae028f1497c275eb9192a3ea0f67022', // 26.stETH | ||||
|     saave: '0xeb16ae0052ed37f479f7fe63849198df1765a733', // saave | ||||
|     // ankreth: '0xa96a65c051bf88b4095ee1f2451c2a9d43f53ae2', // ankreth | ||||
|     ankreth: '0xa96a65c051bf88b4095ee1f2451c2a9d43f53ae2', // ankreth | ||||
|     USDP: '0x42d7025938bec20b69cbae5a77421082407f053a', // usdp | ||||
|     ib: '0x2dded6da1bf5dbdf597c45fcfaa3194e53ecfeaf', // iron bank | ||||
|     link: '0xf178c0b5bb7e7abf4e12a4838c7b7c5ba2c623c0', // link | ||||
| @@ -334,6 +353,8 @@ export const CURVE_POOLS = { | ||||
|     STABLEx: '0x3252efd4ea2d6c78091a1f43982ee2c3659cc3d1', | ||||
|     alUSD: '0x43b4fdfd4ff969587185cdb6f0bd875c5fc83f8c', | ||||
|     FRAX: '0xd632f22692fac7611d2aa1c0d552930d43caed3b', | ||||
|     LUSD: '0xed279fdd11ca84beef15af5d39bb4d4bee23f0ca', | ||||
|     BUSD: '0x4807862aa8b2bf68830e4c8dc86d0e9a998e085a', | ||||
| }; | ||||
|  | ||||
| export const SWERVE_POOLS = { | ||||
| @@ -343,7 +364,12 @@ export const SWERVE_POOLS = { | ||||
| export const SNOWSWAP_POOLS = { | ||||
|     yUSD: '0xbf7ccd6c446acfcc5df023043f2167b62e81899b', | ||||
|     yVault: '0x4571753311e37ddb44faa8fb78a6df9a6e3c6c0b', | ||||
|     eth: '0x16bea2e63adade5984298d53a4d4d9c09e278192', | ||||
|     // POOL Disabled as it uses WETH over ETH | ||||
|     // There is a conflict with Curve and SnowSwap | ||||
|     // where Curve uses ETH and SnowSwap uses WETH | ||||
|     // To re-enable this we need to flag an WETH | ||||
|     // unwrap or not | ||||
|     // eth: '0x16bea2e63adade5984298d53a4d4d9c09e278192', | ||||
| }; | ||||
|  | ||||
| export const SMOOTHY_POOLS = { | ||||
| @@ -367,6 +393,10 @@ export const ELLIPSIS_POOLS = { | ||||
|     threePool: '0x160caed03795365f3a589f10c379ffa7d75d4e76', | ||||
| }; | ||||
|  | ||||
| export const XSIGMA_POOLS = { | ||||
|     stable: '0x3333333ACdEdBbC9Ad7bda0876e60714195681c5', | ||||
| }; | ||||
|  | ||||
| export const DEFAULT_INTERMEDIATE_TOKENS_BY_CHAIN_ID = valueByChainId<string[]>( | ||||
|     { | ||||
|         [ChainId.Mainnet]: [ | ||||
| @@ -423,7 +453,10 @@ export const NATIVE_FEE_TOKEN_BY_CHAIN_ID = valueByChainId<string>( | ||||
|     NULL_ADDRESS, | ||||
| ); | ||||
|  | ||||
| export const NATIVE_FEE_TOKEN_AMOUNT_BY_CHAIN_ID = valueByChainId({}, ONE_ETHER); | ||||
| export const NATIVE_FEE_TOKEN_AMOUNT_BY_CHAIN_ID = valueByChainId( | ||||
|     { [ChainId.Mainnet]: ONE_ETHER.times(0.1) }, | ||||
|     ONE_ETHER, | ||||
| ); | ||||
|  | ||||
| // Order dependent | ||||
| const CURVE_TRI_POOL_MAINNET_TOKENS = [MAINNET_TOKENS.DAI, MAINNET_TOKENS.USDC, MAINNET_TOKENS.USDT]; | ||||
| @@ -478,147 +511,175 @@ export const CURVE_MAINNET_INFOS: { [name: string]: CurveInfo } = { | ||||
|     [CURVE_POOLS.compound]: createCurveExchangeUnderlyingPool({ | ||||
|         tokens: [MAINNET_TOKENS.DAI, MAINNET_TOKENS.USDC], | ||||
|         pool: CURVE_POOLS.compound, | ||||
|         gasSchedule: 597e3, | ||||
|         gasSchedule: 587e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.PAX]: createCurveExchangeUnderlyingPool({ | ||||
|         tokens: [MAINNET_TOKENS.DAI, MAINNET_TOKENS.USDC, MAINNET_TOKENS.USDT, MAINNET_TOKENS.PAX], | ||||
|         pool: CURVE_POOLS.PAX, | ||||
|         gasSchedule: 752e3, | ||||
|         gasSchedule: 742e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.sUSD]: createCurveExchangeUnderlyingPool({ | ||||
|         tokens: [MAINNET_TOKENS.DAI, MAINNET_TOKENS.USDC, MAINNET_TOKENS.USDT, MAINNET_TOKENS.sUSD], | ||||
|         pool: CURVE_POOLS.sUSD, | ||||
|         gasSchedule: 312e3, | ||||
|         gasSchedule: 302e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.renBTC]: createCurveExchangePool({ | ||||
|         tokens: [MAINNET_TOKENS.RenBTC, MAINNET_TOKENS.WBTC], | ||||
|         pool: CURVE_POOLS.renBTC, | ||||
|         gasSchedule: 181e3, | ||||
|         gasSchedule: 171e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.sBTC]: createCurveExchangePool({ | ||||
|         tokens: [MAINNET_TOKENS.RenBTC, MAINNET_TOKENS.WBTC, MAINNET_TOKENS.sBTC], | ||||
|         pool: CURVE_POOLS.sBTC, | ||||
|         gasSchedule: 337e3, | ||||
|         gasSchedule: 327e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.HBTC]: createCurveExchangePool({ | ||||
|         tokens: [MAINNET_TOKENS.hBTC, MAINNET_TOKENS.WBTC], | ||||
|         pool: CURVE_POOLS.HBTC, | ||||
|         gasSchedule: 220e3, | ||||
|         gasSchedule: 210e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.TRI]: createCurveExchangePool({ | ||||
|         tokens: [MAINNET_TOKENS.DAI, MAINNET_TOKENS.USDC, MAINNET_TOKENS.USDT], | ||||
|         pool: CURVE_POOLS.TRI, | ||||
|         gasSchedule: 186e3, | ||||
|         gasSchedule: 176e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.GUSD]: createCurveMetaTriPool({ | ||||
|         token: MAINNET_TOKENS.GUSD, | ||||
|         pool: CURVE_POOLS.GUSD, | ||||
|         gasSchedule: 421e3, | ||||
|         gasSchedule: 411e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.HUSD]: createCurveMetaTriPool({ | ||||
|         token: MAINNET_TOKENS.HUSD, | ||||
|         pool: CURVE_POOLS.HUSD, | ||||
|         gasSchedule: 406e3, | ||||
|         gasSchedule: 396e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.USDN]: createCurveMetaTriPool({ | ||||
|         token: MAINNET_TOKENS.USDN, | ||||
|         pool: CURVE_POOLS.USDN, | ||||
|         gasSchedule: 408e3, | ||||
|         gasSchedule: 398e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.mUSD]: createCurveMetaTriPool({ | ||||
|         token: MAINNET_TOKENS.mUSD, | ||||
|         pool: CURVE_POOLS.mUSD, | ||||
|         gasSchedule: 395e3, | ||||
|         gasSchedule: 385e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.dUSD]: createCurveMetaTriPool({ | ||||
|         token: MAINNET_TOKENS.dUSD, | ||||
|         pool: CURVE_POOLS.dUSD, | ||||
|         gasSchedule: 381e3, | ||||
|         gasSchedule: 371e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.tBTC]: createCurveMetaTriBtcPool({ | ||||
|         token: MAINNET_TOKENS.tBTC, | ||||
|         pool: CURVE_POOLS.tBTC, | ||||
|         gasSchedule: 492e3, | ||||
|         gasSchedule: 482e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.pBTC]: createCurveMetaTriBtcPool({ | ||||
|         token: MAINNET_TOKENS.pBTC, | ||||
|         pool: CURVE_POOLS.pBTC, | ||||
|         gasSchedule: 513e3, | ||||
|         gasSchedule: 503e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.bBTC]: createCurveMetaTriBtcPool({ | ||||
|         token: MAINNET_TOKENS.bBTC, | ||||
|         pool: CURVE_POOLS.bBTC, | ||||
|         gasSchedule: 507e3, | ||||
|         gasSchedule: 497e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.oBTC]: createCurveMetaTriBtcPool({ | ||||
|         token: MAINNET_TOKENS.oBTC, | ||||
|         pool: CURVE_POOLS.oBTC, | ||||
|         gasSchedule: 498e3, | ||||
|         gasSchedule: 488e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.UST]: createCurveMetaTriPool({ | ||||
|         token: MAINNET_TOKENS.UST, | ||||
|         pool: CURVE_POOLS.UST, | ||||
|         gasSchedule: 350e3, | ||||
|         gasSchedule: 340e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.eurs]: createCurveExchangePool({ | ||||
|         tokens: [MAINNET_TOKENS.EURS, MAINNET_TOKENS.sEUR], | ||||
|         pool: CURVE_POOLS.eurs, | ||||
|         gasSchedule: 330e3, | ||||
|         gasSchedule: 320e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.aave]: createCurveExchangeUnderlyingPool({ | ||||
|         tokens: [MAINNET_TOKENS.DAI, MAINNET_TOKENS.USDC, MAINNET_TOKENS.USDT], | ||||
|         pool: CURVE_POOLS.aave, | ||||
|         gasSchedule: 590e3, | ||||
|         gasSchedule: 580e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.aave]: createCurveExchangePool({ | ||||
|         tokens: [MAINNET_TOKENS.aDAI, MAINNET_TOKENS.aUSDC, MAINNET_TOKENS.aUSDT], | ||||
|         pool: CURVE_POOLS.aave, | ||||
|         gasSchedule: 590e3, | ||||
|         gasSchedule: 580e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.saave]: createCurveExchangeUnderlyingPool({ | ||||
|         tokens: [MAINNET_TOKENS.DAI, MAINNET_TOKENS.sUSD], | ||||
|         pool: CURVE_POOLS.saave, | ||||
|         gasSchedule: 590e3, | ||||
|         gasSchedule: 580e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.saave]: createCurveExchangePool({ | ||||
|         tokens: [MAINNET_TOKENS.aDAI, MAINNET_TOKENS.aSUSD], | ||||
|         pool: CURVE_POOLS.saave, | ||||
|         gasSchedule: 590e3, | ||||
|         gasSchedule: 580e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.USDP]: createCurveMetaTriPool({ | ||||
|         token: MAINNET_TOKENS.USDP, | ||||
|         pool: CURVE_POOLS.USDP, | ||||
|         gasSchedule: 384e3, | ||||
|         gasSchedule: 374e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.ib]: createCurveExchangeUnderlyingPool({ | ||||
|         tokens: [MAINNET_TOKENS.DAI, MAINNET_TOKENS.USDC, MAINNET_TOKENS.USDT], | ||||
|         pool: CURVE_POOLS.ib, | ||||
|         gasSchedule: 656e3, | ||||
|         gasSchedule: 646e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.link]: createCurveExchangePool({ | ||||
|         tokens: [MAINNET_TOKENS.LINK, MAINNET_TOKENS.sLINK], | ||||
|         pool: CURVE_POOLS.link, | ||||
|         gasSchedule: 329e3, | ||||
|         gasSchedule: 319e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.TUSD]: createCurveMetaTriPool({ | ||||
|         token: MAINNET_TOKENS.TUSD, | ||||
|         pool: CURVE_POOLS.TUSD, | ||||
|         gasSchedule: 414e3, | ||||
|         gasSchedule: 404e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.STABLEx]: createCurveMetaTriPool({ | ||||
|         token: MAINNET_TOKENS.STABLEx, | ||||
|         pool: CURVE_POOLS.STABLEx, | ||||
|         gasSchedule: 407e3, | ||||
|         gasSchedule: 397e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.alUSD]: createCurveMetaTriPool({ | ||||
|         token: MAINNET_TOKENS.alUSD, | ||||
|         pool: CURVE_POOLS.alUSD, | ||||
|         gasSchedule: 397e3, | ||||
|         gasSchedule: 387e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.FRAX]: createCurveMetaTriPool({ | ||||
|         token: MAINNET_TOKENS.FRAX, | ||||
|         pool: CURVE_POOLS.FRAX, | ||||
|         gasSchedule: 397e3, | ||||
|         gasSchedule: 387e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.LUSD]: createCurveMetaTriPool({ | ||||
|         token: MAINNET_TOKENS.LUSD, | ||||
|         pool: CURVE_POOLS.LUSD, | ||||
|         gasSchedule: 387e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.BUSD]: createCurveMetaTriPool({ | ||||
|         token: MAINNET_TOKENS.BUSD, | ||||
|         pool: CURVE_POOLS.BUSD, | ||||
|         gasSchedule: 387e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.steth]: createCurveExchangePool({ | ||||
|         // This pool uses ETH | ||||
|         tokens: [MAINNET_TOKENS.WETH, MAINNET_TOKENS.stETH], | ||||
|         pool: CURVE_POOLS.steth, | ||||
|         gasSchedule: 151e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.seth]: createCurveExchangePool({ | ||||
|         // This pool uses ETH | ||||
|         tokens: [MAINNET_TOKENS.WETH, MAINNET_TOKENS.sETH], | ||||
|         pool: CURVE_POOLS.seth, | ||||
|         gasSchedule: 187e3, | ||||
|     }), | ||||
|     [CURVE_POOLS.ankreth]: createCurveExchangePool({ | ||||
|         // This pool uses ETH | ||||
|         tokens: [MAINNET_TOKENS.WETH, MAINNET_TOKENS.ankrETH], | ||||
|         pool: CURVE_POOLS.ankreth, | ||||
|         gasSchedule: 125e3, | ||||
|     }), | ||||
| }; | ||||
|  | ||||
| @@ -626,7 +687,7 @@ export const SWERVE_MAINNET_INFOS: { [name: string]: CurveInfo } = { | ||||
|     [SWERVE_POOLS.y]: createCurveExchangePool({ | ||||
|         tokens: [MAINNET_TOKENS.DAI, MAINNET_TOKENS.USDC, MAINNET_TOKENS.USDT, MAINNET_TOKENS.TUSD], | ||||
|         pool: SWERVE_POOLS.y, | ||||
|         gasSchedule: 150e3, | ||||
|         gasSchedule: 140e3, | ||||
|     }), | ||||
| }; | ||||
|  | ||||
| @@ -634,30 +695,31 @@ export const SNOWSWAP_MAINNET_INFOS: { [name: string]: CurveInfo } = { | ||||
|     [SNOWSWAP_POOLS.yUSD]: createCurveExchangePool({ | ||||
|         tokens: [MAINNET_TOKENS.yUSD, MAINNET_TOKENS.ybCRV], | ||||
|         pool: SNOWSWAP_POOLS.yUSD, | ||||
|         gasSchedule: 1000e3, | ||||
|         gasSchedule: 990e3, | ||||
|     }), | ||||
|     [SNOWSWAP_POOLS.yUSD]: createCurveExchangeUnderlyingPool({ | ||||
|         tokens: [MAINNET_TOKENS.yCRV, MAINNET_TOKENS.bCRV], | ||||
|         pool: SNOWSWAP_POOLS.yUSD, | ||||
|         gasSchedule: 1000e3, | ||||
|         gasSchedule: 990e3, | ||||
|     }), | ||||
|     [SNOWSWAP_POOLS.yVault]: createCurveExchangePool({ | ||||
|         tokens: [MAINNET_TOKENS.yDAI, MAINNET_TOKENS.yUSDC, MAINNET_TOKENS.yUSDT, MAINNET_TOKENS.yTUSD], | ||||
|         pool: SNOWSWAP_POOLS.yVault, | ||||
|         gasSchedule: 1500e3, | ||||
|     }), | ||||
|     [SNOWSWAP_POOLS.eth]: createCurveExchangePool({ | ||||
|         tokens: [MAINNET_TOKENS.WETH, MAINNET_TOKENS.vETH, MAINNET_TOKENS.ankrETH, MAINNET_TOKENS.crETH], | ||||
|         pool: SNOWSWAP_POOLS.eth, | ||||
|         gasSchedule: 1000e3, | ||||
|         gasSchedule: 1490e3, | ||||
|     }), | ||||
|     // Unsupported due to collision with WETH and ETH with execution using MixinCurve | ||||
|     // [SNOWSWAP_POOLS.eth]: createCurveExchangePool({ | ||||
|     //     tokens: [MAINNET_TOKENS.WETH, MAINNET_TOKENS.vETH, MAINNET_TOKENS.ankrETH, MAINNET_TOKENS.crETH], | ||||
|     //     pool: SNOWSWAP_POOLS.eth, | ||||
|     //     gasSchedule: 990e3, | ||||
|     // }), | ||||
| }; | ||||
|  | ||||
| export const BELT_BSC_INFOS: { [name: string]: CurveInfo } = { | ||||
|     [BELT_POOLS.vPool]: createCurveExchangeUnderlyingPool({ | ||||
|         tokens: [BSC_TOKENS.DAI, BSC_TOKENS.USDC, BSC_TOKENS.USDT, BSC_TOKENS.BUSD], | ||||
|         pool: BELT_POOLS.vPool, | ||||
|         gasSchedule: 4500e3, | ||||
|         gasSchedule: 4490e3, | ||||
|     }), | ||||
| }; | ||||
|  | ||||
| @@ -665,6 +727,14 @@ export const ELLIPSIS_BSC_INFOS: { [name: string]: CurveInfo } = { | ||||
|     [ELLIPSIS_POOLS.threePool]: createCurveExchangePool({ | ||||
|         tokens: [BSC_TOKENS.BUSD, BSC_TOKENS.USDC, BSC_TOKENS.USDT], | ||||
|         pool: ELLIPSIS_POOLS.threePool, | ||||
|         gasSchedule: 140e3, | ||||
|     }), | ||||
| }; | ||||
|  | ||||
| export const XSIGMA_MAINNET_INFOS: { [name: string]: CurveInfo } = { | ||||
|     [XSIGMA_POOLS.stable]: createCurveExchangePool({ | ||||
|         tokens: [MAINNET_TOKENS.DAI, MAINNET_TOKENS.USDC, MAINNET_TOKENS.USDT], | ||||
|         pool: XSIGMA_POOLS.stable, | ||||
|         gasSchedule: 150e3, | ||||
|     }), | ||||
| }; | ||||
| @@ -678,18 +748,17 @@ export const SADDLE_MAINNET_INFOS: { [name: string]: CurveInfo } = { | ||||
|         poolAddress: SADDLE_POOLS.stables, | ||||
|         tokens: [MAINNET_TOKENS.DAI, MAINNET_TOKENS.USDC, MAINNET_TOKENS.USDT], | ||||
|         metaToken: undefined, | ||||
|         gasSchedule: 220e3, | ||||
|         gasSchedule: 150e3, | ||||
|     }, | ||||
|     [SADDLE_POOLS.bitcoins]: { | ||||
|         exchangeFunctionSelector: CurveFunctionSelectors.swap, | ||||
|         sellQuoteFunctionSelector: CurveFunctionSelectors.calculateSwap, | ||||
|         buyQuoteFunctionSelector: CurveFunctionSelectors.None, | ||||
|         poolAddress: SADDLE_POOLS.bitcoins, | ||||
|         tokens: [MAINNET_TOKENS.tBTC, MAINNET_TOKENS.WBTC, MAINNET_TOKENS.RenBTC, MAINNET_TOKENS.sBTC], | ||||
|         metaToken: undefined, | ||||
|         gasSchedule: 150e3, | ||||
|     }, | ||||
|     // TODO:Romain having "Cannot swap more than you own" error when running simbot | ||||
|     // [SADDLE_POOLS.bitcoins]: { | ||||
|     //     exchangeFunctionSelector: CurveFunctionSelectors.swap, | ||||
|     //     sellQuoteFunctionSelector: CurveFunctionSelectors.calculateSwap, | ||||
|     //     buyQuoteFunctionSelector: CurveFunctionSelectors.None, | ||||
|     //     poolAddress: SADDLE_POOLS.stables, | ||||
|     //     tokens: [MAINNET_TOKENS.tBTC, MAINNET_TOKENS.WBTC, MAINNET_TOKENS.RenBTC, MAINNET_TOKENS.sBTC], | ||||
|     //     metaToken: undefined, | ||||
|     //     gasSchedule: 220e3, | ||||
|     // }, | ||||
| }; | ||||
|  | ||||
| export const SMOOTHY_MAINNET_INFOS: { [name: string]: CurveInfo } = { | ||||
| @@ -709,7 +778,7 @@ export const SMOOTHY_MAINNET_INFOS: { [name: string]: CurveInfo } = { | ||||
|             MAINNET_TOKENS.GUSD, | ||||
|         ], | ||||
|         metaToken: undefined, | ||||
|         gasSchedule: 200e3, | ||||
|         gasSchedule: 190e3, | ||||
|     }, | ||||
| }; | ||||
|  | ||||
| @@ -721,7 +790,7 @@ export const SMOOTHY_BSC_INFOS: { [name: string]: CurveInfo } = { | ||||
|         poolAddress: SMOOTHY_POOLS.syUSD, | ||||
|         tokens: [BSC_TOKENS.BUSD, BSC_TOKENS.USDT, BSC_TOKENS.USDC, BSC_TOKENS.DAI, BSC_TOKENS.PAX, BSC_TOKENS.UST], | ||||
|         metaToken: undefined, | ||||
|         gasSchedule: 100e3, | ||||
|         gasSchedule: 90e3, | ||||
|     }, | ||||
| }; | ||||
|  | ||||
| @@ -733,7 +802,7 @@ export const NERVE_BSC_INFOS: { [name: string]: CurveInfo } = { | ||||
|         poolAddress: NERVE_POOLS.threePool, | ||||
|         tokens: [BSC_TOKENS.BUSD, BSC_TOKENS.USDT, BSC_TOKENS.USDC], | ||||
|         metaToken: undefined, | ||||
|         gasSchedule: 150e3, | ||||
|         gasSchedule: 140e3, | ||||
|     }, | ||||
| }; | ||||
|  | ||||
| @@ -744,6 +813,7 @@ export const NERVE_BSC_INFOS: { [name: string]: CurveInfo } = { | ||||
|  * 0xbb Bridged price reserve (i.e Uniswap/Curve) | ||||
|  */ | ||||
| export const KYBER_BRIDGED_LIQUIDITY_PREFIX = '0xbb'; | ||||
| export const KYBER_BANNED_RESERVES = ['0xff4f6e65426974205175616e7400000000000000000000000000000000000000']; | ||||
| export const MAX_KYBER_RESERVES_QUERIED = 5; | ||||
| export const KYBER_CONFIG_BY_CHAIN_ID = valueByChainId<KyberSamplerOpts>( | ||||
|     { | ||||
| @@ -978,9 +1048,31 @@ export const COMPONENT_POOLS_BY_CHAIN_ID = valueByChainId( | ||||
|     }, | ||||
| ); | ||||
|  | ||||
| export const BALANCER_V2_VAULT_ADDRESS_BY_CHAIN = valueByChainId<string>( | ||||
|     { | ||||
|         [ChainId.Mainnet]: '0xba12222222228d8ba445958a75a0704d566bf2c8', | ||||
|     }, | ||||
|     NULL_ADDRESS, | ||||
| ); | ||||
|  | ||||
| export const BALANCER_SUBGRAPH_URL = 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer'; | ||||
| export const BALANCER_TOP_POOLS_FETCHED = 250; | ||||
| export const BALANCER_MAX_POOLS_FETCHED = 3; | ||||
| export const BALANCER_V2_SUBGRAPH_URL = 'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-v2'; | ||||
|  | ||||
| export const UNISWAPV3_CONFIG_BY_CHAIN_ID = valueByChainId( | ||||
|     { | ||||
|         [ChainId.Mainnet]: { | ||||
|             quoter: '0xb27308f9f90d607463bb33ea1bebb41c27ce5ab6', | ||||
|             router: '0xe592427a0aece92de3edee1f18e0157c05861564', | ||||
|         }, | ||||
|         [ChainId.Ropsten]: { | ||||
|             quoter: '0x2f9e608fd881861b8916257b76613cb22ee0652c', | ||||
|             router: '0x03782388516e94fcd4c18666303601a12aa729ea', | ||||
|         }, | ||||
|     }, | ||||
|     { quoter: NULL_ADDRESS, router: NULL_ADDRESS }, | ||||
| ); | ||||
|  | ||||
| // | ||||
| // BSC | ||||
| @@ -992,7 +1084,7 @@ export const PANCAKESWAP_ROUTER_BY_CHAIN_ID = valueByChainId<string>( | ||||
|     NULL_ADDRESS, | ||||
| ); | ||||
|  | ||||
| export const PANCAKESWAP_V2_ROUTER_BY_CHAIN_ID = valueByChainId<string>( | ||||
| export const PANCAKESWAPV2_ROUTER_BY_CHAIN_ID = valueByChainId<string>( | ||||
|     { | ||||
|         [ChainId.BSC]: '0x10ed43c718714eb63d5aa57b78b54704e256024e', | ||||
|     }, | ||||
| @@ -1006,6 +1098,34 @@ export const BAKERYSWAP_ROUTER_BY_CHAIN_ID = valueByChainId<string>( | ||||
|     NULL_ADDRESS, | ||||
| ); | ||||
|  | ||||
| export const APESWAP_ROUTER_BY_CHAIN_ID = valueByChainId<string>( | ||||
|     { | ||||
|         [ChainId.BSC]: '0xc0788a3ad43d79aa53b09c2eacc313a787d1d607', | ||||
|     }, | ||||
|     NULL_ADDRESS, | ||||
| ); | ||||
|  | ||||
| export const CAFESWAP_ROUTER_BY_CHAIN_ID = valueByChainId<string>( | ||||
|     { | ||||
|         [ChainId.BSC]: '0x933daea3a5995fb94b14a7696a5f3ffd7b1e385a', | ||||
|     }, | ||||
|     NULL_ADDRESS, | ||||
| ); | ||||
|  | ||||
| export const CHEESESWAP_ROUTER_BY_CHAIN_ID = valueByChainId<string>( | ||||
|     { | ||||
|         [ChainId.BSC]: '0x3047799262d8d2ef41ed2a222205968bc9b0d895', | ||||
|     }, | ||||
|     NULL_ADDRESS, | ||||
| ); | ||||
|  | ||||
| export const JULSWAP_ROUTER_BY_CHAIN_ID = valueByChainId<string>( | ||||
|     { | ||||
|         [ChainId.BSC]: '0xbd67d157502a23309db761c41965600c2ec788b2', | ||||
|     }, | ||||
|     NULL_ADDRESS, | ||||
| ); | ||||
|  | ||||
| /** | ||||
|  * Calculated gross gas cost of the underlying exchange. | ||||
|  * The cost of switching from one source to another, assuming | ||||
| @@ -1037,6 +1157,7 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = { | ||||
|     [ERC20BridgeSource.Ellipsis]: fillData => (fillData as CurveFillData).pool.gasSchedule, | ||||
|     [ERC20BridgeSource.Smoothy]: fillData => (fillData as CurveFillData).pool.gasSchedule, | ||||
|     [ERC20BridgeSource.Saddle]: fillData => (fillData as CurveFillData).pool.gasSchedule, | ||||
|     [ERC20BridgeSource.XSigma]: fillData => (fillData as CurveFillData).pool.gasSchedule, | ||||
|     [ERC20BridgeSource.MultiBridge]: () => 350e3, | ||||
|     [ERC20BridgeSource.UniswapV2]: (fillData?: FillData) => { | ||||
|         // TODO: Different base cost if to/from ETH. | ||||
| @@ -1075,17 +1196,12 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = { | ||||
|         return gas; | ||||
|     }, | ||||
|     [ERC20BridgeSource.Balancer]: () => 120e3, | ||||
|     [ERC20BridgeSource.BalancerV2]: () => 100e3, | ||||
|     [ERC20BridgeSource.Cream]: () => 120e3, | ||||
|     [ERC20BridgeSource.MStable]: () => 700e3, | ||||
|     [ERC20BridgeSource.MakerPsm]: (fillData?: FillData) => { | ||||
|         const psmFillData = fillData as MakerPsmFillData; | ||||
|  | ||||
|         // TODO(kimpers): update with more accurate numbers after allowances have been set | ||||
|         if (psmFillData.takerToken === psmFillData.gemTokenAddress) { | ||||
|             return psmFillData.isSellOperation ? 389e3 : 423e3; | ||||
|         } else { | ||||
|             return 444e3; | ||||
|         } | ||||
|         return psmFillData.takerToken === psmFillData.gemTokenAddress ? 210e3 : 290e3; | ||||
|     }, | ||||
|     [ERC20BridgeSource.Mooniswap]: () => 130e3, | ||||
|     [ERC20BridgeSource.Shell]: () => 170e3, | ||||
| @@ -1136,6 +1252,15 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = { | ||||
|         } | ||||
|         return gas; | ||||
|     }, | ||||
|     [ERC20BridgeSource.PancakeSwapV2]: (fillData?: FillData) => { | ||||
|         // TODO: Different base cost if to/from ETH. | ||||
|         let gas = 90e3; | ||||
|         const path = (fillData as UniswapV2FillData).tokenAddressPath; | ||||
|         if (path.length > 2) { | ||||
|             gas += (path.length - 2) * 60e3; // +60k for each hop. | ||||
|         } | ||||
|         return gas; | ||||
|     }, | ||||
|     [ERC20BridgeSource.BakerySwap]: (fillData?: FillData) => { | ||||
|         // TODO: Different base cost if to/from ETH. | ||||
|         let gas = 90e3; | ||||
| @@ -1145,7 +1270,7 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = { | ||||
|         } | ||||
|         return gas; | ||||
|     }, | ||||
|     [ERC20BridgeSource.PancakeSwapV2]: (fillData?: FillData) => { | ||||
|     [ERC20BridgeSource.ApeSwap]: (fillData?: FillData) => { | ||||
|         // TODO: Different base cost if to/from ETH. | ||||
|         let gas = 90e3; | ||||
|         const path = (fillData as UniswapV2FillData).tokenAddressPath; | ||||
| @@ -1154,6 +1279,41 @@ export const DEFAULT_GAS_SCHEDULE: Required<FeeSchedule> = { | ||||
|         } | ||||
|         return gas; | ||||
|     }, | ||||
|     [ERC20BridgeSource.CafeSwap]: (fillData?: FillData) => { | ||||
|         // TODO: Different base cost if to/from ETH. | ||||
|         let gas = 90e3; | ||||
|         const path = (fillData as UniswapV2FillData).tokenAddressPath; | ||||
|         if (path.length > 2) { | ||||
|             gas += (path.length - 2) * 60e3; // +60k for each hop. | ||||
|         } | ||||
|         return gas; | ||||
|     }, | ||||
|     [ERC20BridgeSource.CheeseSwap]: (fillData?: FillData) => { | ||||
|         // TODO: Different base cost if to/from ETH. | ||||
|         let gas = 90e3; | ||||
|         const path = (fillData as UniswapV2FillData).tokenAddressPath; | ||||
|         if (path.length > 2) { | ||||
|             gas += (path.length - 2) * 60e3; // +60k for each hop. | ||||
|         } | ||||
|         return gas; | ||||
|     }, | ||||
|     [ERC20BridgeSource.JulSwap]: (fillData?: FillData) => { | ||||
|         // TODO: Different base cost if to/from ETH. | ||||
|         let gas = 90e3; | ||||
|         const path = (fillData as UniswapV2FillData).tokenAddressPath; | ||||
|         if (path.length > 2) { | ||||
|             gas += (path.length - 2) * 60e3; // +60k for each hop. | ||||
|         } | ||||
|         return gas; | ||||
|     }, | ||||
|     [ERC20BridgeSource.UniswapV3]: (fillData?: FillData) => { | ||||
|         let gas = 160e3; | ||||
|         const path = (fillData as UniswapV3FillData).tokenAddressPath; | ||||
|         if (path.length > 2) { | ||||
|             gas += (path.length - 2) * 117e3; // +117k for each hop. | ||||
|         } | ||||
|         return gas; | ||||
|     }, | ||||
| }; | ||||
|  | ||||
| export const DEFAULT_FEE_SCHEDULE: Required<FeeSchedule> = { ...DEFAULT_GAS_SCHEDULE }; | ||||
| @@ -1177,5 +1337,6 @@ export const DEFAULT_GET_MARKET_ORDERS_OPTS: GetMarketOrdersOpts = { | ||||
|     exchangeProxyOverhead: () => ZERO_AMOUNT, | ||||
|     allowFallback: true, | ||||
|     shouldGenerateQuoteReport: true, | ||||
|     shouldIncludePriceComparisonsReport: false, | ||||
|     tokenAdjacencyGraph: { default: [] }, | ||||
| }; | ||||
|   | ||||
| @@ -1,109 +0,0 @@ | ||||
| import { Pool } from '@balancer-labs/sor/dist/types'; | ||||
| import { getPoolsWithTokens, parsePoolData } from 'cream-sor'; | ||||
|  | ||||
| import { BALANCER_MAX_POOLS_FETCHED } from './constants'; | ||||
|  | ||||
| // tslint:disable:boolean-naming | ||||
|  | ||||
| interface CacheValue { | ||||
|     timestamp: number; | ||||
|     pools: Pool[]; | ||||
| } | ||||
|  | ||||
| // tslint:disable:custom-no-magic-numbers | ||||
| const FIVE_SECONDS_MS = 5 * 1000; | ||||
| const ONE_DAY_MS = 24 * 60 * 60 * 1000; | ||||
| const DEFAULT_TIMEOUT_MS = 1000; | ||||
| // tslint:enable:custom-no-magic-numbers | ||||
|  | ||||
| export class CreamPoolsCache { | ||||
|     constructor( | ||||
|         private readonly _cache: { [key: string]: CacheValue } = {}, | ||||
|         private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED, | ||||
|     ) {} | ||||
|  | ||||
|     public async getPoolsForPairAsync( | ||||
|         takerToken: string, | ||||
|         makerToken: string, | ||||
|         timeoutMs: number = DEFAULT_TIMEOUT_MS, | ||||
|     ): Promise<Pool[]> { | ||||
|         const timeout = new Promise<Pool[]>(resolve => setTimeout(resolve, timeoutMs, [])); | ||||
|         return Promise.race([this._getPoolsForPairAsync(takerToken, makerToken), timeout]); | ||||
|     } | ||||
|  | ||||
|     public getCachedPoolAddressesForPair( | ||||
|         takerToken: string, | ||||
|         makerToken: string, | ||||
|         cacheExpiryMs?: number, | ||||
|     ): string[] | undefined { | ||||
|         const key = JSON.stringify([takerToken, makerToken]); | ||||
|         const value = this._cache[key]; | ||||
|         if (cacheExpiryMs === undefined) { | ||||
|             return value === undefined ? [] : value.pools.map(pool => pool.id); | ||||
|         } | ||||
|         const minTimestamp = Date.now() - cacheExpiryMs; | ||||
|         if (value === undefined || value.timestamp < minTimestamp) { | ||||
|             return undefined; | ||||
|         } else { | ||||
|             return value.pools.map(pool => pool.id); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public howToSampleCream( | ||||
|         takerToken: string, | ||||
|         makerToken: string, | ||||
|         isAllowedSource: boolean, | ||||
|     ): { onChain: boolean; offChain: boolean } { | ||||
|         // If CREAM is excluded as a source, do not sample. | ||||
|         if (!isAllowedSource) { | ||||
|             return { onChain: false, offChain: false }; | ||||
|         } | ||||
|         const cachedCreamPools = this.getCachedPoolAddressesForPair(takerToken, makerToken, ONE_DAY_MS); | ||||
|         // Sample CREAM on-chain (i.e. via the ERC20BridgeSampler contract) if: | ||||
|         // - Cached values are not stale | ||||
|         // - There is at least one CREAM pool for this pair | ||||
|         const onChain = cachedCreamPools !== undefined && cachedCreamPools.length > 0; | ||||
|         // Sample CREAM off-chain (i.e. via GraphQL query + `computeCreamBuy/SellQuote`) | ||||
|         // if cached values are stale | ||||
|         const offChain = cachedCreamPools === undefined; | ||||
|         return { onChain, offChain }; | ||||
|     } | ||||
|  | ||||
|     protected async _getPoolsForPairAsync( | ||||
|         takerToken: string, | ||||
|         makerToken: string, | ||||
|         cacheExpiryMs: number = FIVE_SECONDS_MS, | ||||
|     ): Promise<Pool[]> { | ||||
|         const key = JSON.stringify([takerToken, makerToken]); | ||||
|         const value = this._cache[key]; | ||||
|         const minTimestamp = Date.now() - cacheExpiryMs; | ||||
|         if (value === undefined || value.timestamp < minTimestamp) { | ||||
|             const pools = await this._fetchPoolsForPairAsync(takerToken, makerToken); | ||||
|             const timestamp = Date.now(); | ||||
|             this._cache[key] = { | ||||
|                 pools, | ||||
|                 timestamp, | ||||
|             }; | ||||
|         } | ||||
|         return this._cache[key].pools; | ||||
|     } | ||||
|  | ||||
|     // tslint:disable-next-line: prefer-function-over-method | ||||
|     protected async _loadTopPoolsAsync(): Promise<void> { | ||||
|         // Do nothing | ||||
|     } | ||||
|  | ||||
|     // tslint:disable-next-line:prefer-function-over-method | ||||
|     protected async _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> { | ||||
|         try { | ||||
|             const poolData = (await getPoolsWithTokens(takerToken, makerToken)).pools; | ||||
|             // Sort by maker token balance (descending) | ||||
|             const pools = parsePoolData(poolData, takerToken, makerToken).sort((a, b) => | ||||
|                 b.balanceOut.minus(a.balanceOut).toNumber(), | ||||
|             ); | ||||
|             return pools.length > this.maxPoolsFetched ? pools.slice(0, this.maxPoolsFetched) : pools; | ||||
|         } catch (err) { | ||||
|             return []; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -16,7 +16,14 @@ import { | ||||
|     getNativeAdjustedMakerFillAmount, | ||||
| } from '../utils'; | ||||
|  | ||||
| import { generateQuoteReport, QuoteReport } from './../quote_report_generator'; | ||||
| import { | ||||
|     dexSampleToReportSource, | ||||
|     generateQuoteReport, | ||||
|     multiHopSampleToReportSource, | ||||
|     nativeOrderToReportEntry, | ||||
|     PriceComparisonsReport, | ||||
|     QuoteReport, | ||||
| } from './../quote_report_generator'; | ||||
| import { getComparisonPrices } from './comparison_price'; | ||||
| import { | ||||
|     BUY_SOURCE_FILTER_BY_CHAIN_ID, | ||||
| @@ -68,6 +75,27 @@ export class MarketOperationUtils { | ||||
|         return generateQuoteReport(side, quotes.nativeOrders, liquidityDelivered, comparisonPrice, quoteRequestor); | ||||
|     } | ||||
|  | ||||
|     private static _computePriceComparisonsReport( | ||||
|         quoteRequestor: QuoteRequestor | undefined, | ||||
|         marketSideLiquidity: MarketSideLiquidity, | ||||
|         comparisonPrice?: BigNumber | undefined, | ||||
|     ): PriceComparisonsReport { | ||||
|         const { side, quotes } = marketSideLiquidity; | ||||
|         const dexSources = _.flatten(quotes.dexQuotes).map(quote => dexSampleToReportSource(quote, side)); | ||||
|         const multiHopSources = quotes.twoHopQuotes.map(quote => multiHopSampleToReportSource(quote, side)); | ||||
|         const nativeSources = quotes.nativeOrders.map(order => | ||||
|             nativeOrderToReportEntry( | ||||
|                 order.type, | ||||
|                 order as any, | ||||
|                 order.fillableTakerAmount, | ||||
|                 comparisonPrice, | ||||
|                 quoteRequestor, | ||||
|             ), | ||||
|         ); | ||||
|  | ||||
|         return { dexSources, multiHopSources, nativeSources }; | ||||
|     } | ||||
|  | ||||
|     constructor( | ||||
|         private readonly _sampler: DexOrderSampler, | ||||
|         private readonly contractAddresses: AssetSwapperContractAddresses, | ||||
| @@ -100,29 +128,6 @@ export class MarketOperationUtils { | ||||
|         const quoteSourceFilters = this._sellSources.merge(requestFilters); | ||||
|         const feeSourceFilters = this._feeSources.exclude(_opts.excludedFeeSources); | ||||
|  | ||||
|         const { | ||||
|             onChain: sampleBalancerOnChain, | ||||
|             offChain: sampleBalancerOffChain, | ||||
|         } = this._sampler.balancerPoolsCache.howToSampleBalancer( | ||||
|             takerToken, | ||||
|             makerToken, | ||||
|             quoteSourceFilters.isAllowed(ERC20BridgeSource.Balancer), | ||||
|         ); | ||||
|  | ||||
|         const { | ||||
|             onChain: sampleCreamOnChain, | ||||
|             offChain: sampleCreamOffChain, | ||||
|         } = this._sampler.creamPoolsCache.howToSampleCream( | ||||
|             takerToken, | ||||
|             makerToken, | ||||
|             quoteSourceFilters.isAllowed(ERC20BridgeSource.Cream), | ||||
|         ); | ||||
|  | ||||
|         const offChainSources = [ | ||||
|             ...(!sampleCreamOnChain ? [ERC20BridgeSource.Cream] : []), | ||||
|             ...(!sampleBalancerOnChain ? [ERC20BridgeSource.Balancer] : []), | ||||
|         ]; | ||||
|  | ||||
|         // Used to determine whether the tx origin is an EOA or a contract | ||||
|         const txOrigin = (_opts.rfqt && _opts.rfqt.txOrigin) || NULL_ADDRESS; | ||||
|  | ||||
| @@ -146,12 +151,7 @@ export class MarketOperationUtils { | ||||
|                 this._nativeFeeTokenAmount, | ||||
|             ), | ||||
|             // Get sell quotes for taker -> maker. | ||||
|             this._sampler.getSellQuotes( | ||||
|                 quoteSourceFilters.exclude(offChainSources).sources, | ||||
|                 makerToken, | ||||
|                 takerToken, | ||||
|                 sampleAmounts, | ||||
|             ), | ||||
|             this._sampler.getSellQuotes(quoteSourceFilters.sources, makerToken, takerToken, sampleAmounts), | ||||
|             this._sampler.getTwoHopSellQuotes( | ||||
|                 quoteSourceFilters.isAllowed(ERC20BridgeSource.MultiHop) ? quoteSourceFilters.sources : [], | ||||
|                 makerToken, | ||||
| @@ -161,13 +161,8 @@ export class MarketOperationUtils { | ||||
|             this._sampler.isAddressContract(txOrigin), | ||||
|         ); | ||||
|  | ||||
|         const offChainBalancerPromise = sampleBalancerOffChain | ||||
|             ? this._sampler.getBalancerSellQuotesOffChainAsync(makerToken, takerToken, sampleAmounts) | ||||
|             : Promise.resolve([]); | ||||
|  | ||||
|         const offChainCreamPromise = sampleCreamOffChain | ||||
|             ? this._sampler.getCreamSellQuotesOffChainAsync(makerToken, takerToken, sampleAmounts) | ||||
|             : Promise.resolve([]); | ||||
|         // Refresh the cached pools asynchronously if required | ||||
|         void this._refreshPoolCacheIfRequiredAsync(takerToken, makerToken); | ||||
|  | ||||
|         const [ | ||||
|             [ | ||||
| @@ -179,9 +174,7 @@ export class MarketOperationUtils { | ||||
|                 rawTwoHopQuotes, | ||||
|                 isTxOriginContract, | ||||
|             ], | ||||
|             offChainBalancerQuotes, | ||||
|             offChainCreamQuotes, | ||||
|         ] = await Promise.all([samplerPromise, offChainBalancerPromise, offChainCreamPromise]); | ||||
|         ] = await Promise.all([samplerPromise]); | ||||
|  | ||||
|         // Filter out any invalid two hop quotes where we couldn't find a route | ||||
|         const twoHopQuotes = rawTwoHopQuotes.filter( | ||||
| @@ -210,7 +203,7 @@ export class MarketOperationUtils { | ||||
|                 nativeOrders: limitOrdersWithFillableAmounts, | ||||
|                 rfqtIndicativeQuotes: [], | ||||
|                 twoHopQuotes, | ||||
|                 dexQuotes: dexQuotes.concat([...offChainBalancerQuotes, ...offChainCreamQuotes]), | ||||
|                 dexQuotes, | ||||
|             }, | ||||
|             isRfqSupported, | ||||
|         }; | ||||
| @@ -236,29 +229,6 @@ export class MarketOperationUtils { | ||||
|         const quoteSourceFilters = this._buySources.merge(requestFilters); | ||||
|         const feeSourceFilters = this._feeSources.exclude(_opts.excludedFeeSources); | ||||
|  | ||||
|         const { | ||||
|             onChain: sampleBalancerOnChain, | ||||
|             offChain: sampleBalancerOffChain, | ||||
|         } = this._sampler.balancerPoolsCache.howToSampleBalancer( | ||||
|             takerToken, | ||||
|             makerToken, | ||||
|             quoteSourceFilters.isAllowed(ERC20BridgeSource.Balancer), | ||||
|         ); | ||||
|  | ||||
|         const { | ||||
|             onChain: sampleCreamOnChain, | ||||
|             offChain: sampleCreamOffChain, | ||||
|         } = this._sampler.creamPoolsCache.howToSampleCream( | ||||
|             takerToken, | ||||
|             makerToken, | ||||
|             quoteSourceFilters.isAllowed(ERC20BridgeSource.Cream), | ||||
|         ); | ||||
|  | ||||
|         const offChainSources = [ | ||||
|             ...(!sampleCreamOnChain ? [ERC20BridgeSource.Cream] : []), | ||||
|             ...(!sampleBalancerOnChain ? [ERC20BridgeSource.Balancer] : []), | ||||
|         ]; | ||||
|  | ||||
|         // Used to determine whether the tx origin is an EOA or a contract | ||||
|         const txOrigin = (_opts.rfqt && _opts.rfqt.txOrigin) || NULL_ADDRESS; | ||||
|  | ||||
| @@ -282,12 +252,7 @@ export class MarketOperationUtils { | ||||
|                 this._nativeFeeTokenAmount, | ||||
|             ), | ||||
|             // Get buy quotes for taker -> maker. | ||||
|             this._sampler.getBuyQuotes( | ||||
|                 quoteSourceFilters.exclude(offChainSources).sources, | ||||
|                 makerToken, | ||||
|                 takerToken, | ||||
|                 sampleAmounts, | ||||
|             ), | ||||
|             this._sampler.getBuyQuotes(quoteSourceFilters.sources, makerToken, takerToken, sampleAmounts), | ||||
|             this._sampler.getTwoHopBuyQuotes( | ||||
|                 quoteSourceFilters.isAllowed(ERC20BridgeSource.MultiHop) ? quoteSourceFilters.sources : [], | ||||
|                 makerToken, | ||||
| @@ -297,13 +262,8 @@ export class MarketOperationUtils { | ||||
|             this._sampler.isAddressContract(txOrigin), | ||||
|         ); | ||||
|  | ||||
|         const offChainBalancerPromise = sampleBalancerOffChain | ||||
|             ? this._sampler.getBalancerBuyQuotesOffChainAsync(makerToken, takerToken, sampleAmounts) | ||||
|             : Promise.resolve([]); | ||||
|  | ||||
|         const offChainCreamPromise = sampleCreamOffChain | ||||
|             ? this._sampler.getCreamBuyQuotesOffChainAsync(makerToken, takerToken, sampleAmounts) | ||||
|             : Promise.resolve([]); | ||||
|         // Refresh the cached pools asynchronously if required | ||||
|         void this._refreshPoolCacheIfRequiredAsync(takerToken, makerToken); | ||||
|  | ||||
|         const [ | ||||
|             [ | ||||
| @@ -315,9 +275,7 @@ export class MarketOperationUtils { | ||||
|                 rawTwoHopQuotes, | ||||
|                 isTxOriginContract, | ||||
|             ], | ||||
|             offChainBalancerQuotes, | ||||
|             offChainCreamQuotes, | ||||
|         ] = await Promise.all([samplerPromise, offChainBalancerPromise, offChainCreamPromise]); | ||||
|         ] = await Promise.all([samplerPromise]); | ||||
|  | ||||
|         // Filter out any invalid two hop quotes where we couldn't find a route | ||||
|         const twoHopQuotes = rawTwoHopQuotes.filter( | ||||
| @@ -346,7 +304,7 @@ export class MarketOperationUtils { | ||||
|                 nativeOrders: limitOrdersWithFillableAmounts, | ||||
|                 rfqtIndicativeQuotes: [], | ||||
|                 twoHopQuotes, | ||||
|                 dexQuotes: dexQuotes.concat(offChainBalancerQuotes, offChainCreamQuotes), | ||||
|                 dexQuotes, | ||||
|             }, | ||||
|             isRfqSupported, | ||||
|         }; | ||||
| @@ -554,20 +512,29 @@ export class MarketOperationUtils { | ||||
|             throw new Error(AggregationError.NoOptimalPath); | ||||
|         } | ||||
|  | ||||
|         // Generate a fallback path if native orders are in the optimal path. | ||||
|         const nativeFills = optimalPath.fills.filter(f => f.source === ERC20BridgeSource.Native); | ||||
|         if (opts.allowFallback && nativeFills.length !== 0) { | ||||
|         // Generate a fallback path if sources requiring a fallback (fragile) are in the optimal path. | ||||
|         // Native is relatively fragile (limit order collision, expiry, or lack of available maker balance) | ||||
|         // LiquidityProvider is relatively fragile (collision) | ||||
|         const fragileSources = [ERC20BridgeSource.Native, ERC20BridgeSource.LiquidityProvider]; | ||||
|         const fragileFills = optimalPath.fills.filter(f => fragileSources.includes(f.source)); | ||||
|         if (opts.allowFallback && fragileFills.length !== 0) { | ||||
|             // We create a fallback path that is exclusive of Native liquidity | ||||
|             // This is the optimal on-chain path for the entire input amount | ||||
|             const nonNativeFills = fills.filter(p => p.length > 0 && p[0].source !== ERC20BridgeSource.Native); | ||||
|             const nonNativeOptimalPath = await findOptimalPathAsync(side, nonNativeFills, inputAmount, opts.runLimit); | ||||
|             const sturdyFills = fills.filter(p => p.length > 0 && !fragileSources.includes(p[0].source)); | ||||
|             const sturdyOptimalPath = await findOptimalPathAsync(side, sturdyFills, inputAmount, opts.runLimit, { | ||||
|                 ...penaltyOpts, | ||||
|                 exchangeProxyOverhead: (sourceFlags: number) => | ||||
|                     // tslint:disable-next-line: no-bitwise | ||||
|                     penaltyOpts.exchangeProxyOverhead(sourceFlags | optimalPath.sourceFlags), | ||||
|             }); | ||||
|             // Calculate the slippage of on-chain sources compared to the most optimal path | ||||
|             // if within an acceptable threshold we enable a fallback to prevent reverts | ||||
|             if ( | ||||
|                 nonNativeOptimalPath !== undefined && | ||||
|                 (nativeFills.length === optimalPath.fills.length || | ||||
|                     nonNativeOptimalPath.adjustedSlippage(optimalPathRate) <= maxFallbackSlippage) | ||||
|                 sturdyOptimalPath !== undefined && | ||||
|                 (fragileFills.length === optimalPath.fills.length || | ||||
|                     sturdyOptimalPath.adjustedSlippage(optimalPathRate) <= maxFallbackSlippage) | ||||
|             ) { | ||||
|                 optimalPath.addFallback(nonNativeOptimalPath); | ||||
|                 optimalPath.addFallback(sturdyOptimalPath); | ||||
|             } | ||||
|         } | ||||
|         const collapsedPath = optimalPath.collapse(orderOpts); | ||||
| @@ -738,7 +705,27 @@ export class MarketOperationUtils { | ||||
|                 wholeOrderPrice, | ||||
|             ); | ||||
|         } | ||||
|         return { ...optimizerResult, quoteReport }; | ||||
|  | ||||
|         let priceComparisonsReport: PriceComparisonsReport | undefined; | ||||
|         if (_opts.shouldIncludePriceComparisonsReport) { | ||||
|             priceComparisonsReport = MarketOperationUtils._computePriceComparisonsReport( | ||||
|                 _opts.rfqt ? _opts.rfqt.quoteRequestor : undefined, | ||||
|                 marketSideLiquidity, | ||||
|                 wholeOrderPrice, | ||||
|             ); | ||||
|         } | ||||
|         return { ...optimizerResult, quoteReport, priceComparisonsReport }; | ||||
|     } | ||||
|  | ||||
|     private async _refreshPoolCacheIfRequiredAsync(takerToken: string, makerToken: string): Promise<void> { | ||||
|         void Promise.all( | ||||
|             Object.values(this._sampler.poolsCaches).map(async cache => { | ||||
|                 if (cache.isFresh(takerToken, makerToken)) { | ||||
|                     return Promise.resolve([]); | ||||
|                 } | ||||
|                 return cache.getFreshPoolsForPairAsync(takerToken, makerToken); | ||||
|             }), | ||||
|         ); | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -7,12 +7,14 @@ import { MAX_UINT256, ZERO_AMOUNT } from './constants'; | ||||
| import { | ||||
|     AggregationError, | ||||
|     BalancerFillData, | ||||
|     BalancerV2FillData, | ||||
|     BancorFillData, | ||||
|     CollapsedFill, | ||||
|     CurveFillData, | ||||
|     DexSample, | ||||
|     DODOFillData, | ||||
|     ERC20BridgeSource, | ||||
|     FillData, | ||||
|     GenericRouterFillData, | ||||
|     KyberFillData, | ||||
|     LiquidityProviderFillData, | ||||
| @@ -28,6 +30,7 @@ import { | ||||
|     OrderDomain, | ||||
|     ShellFillData, | ||||
|     UniswapV2FillData, | ||||
|     UniswapV3FillData, | ||||
| } from './types'; | ||||
|  | ||||
| // tslint:disable completed-docs | ||||
| @@ -41,6 +44,11 @@ export interface CreateOrderFromPathOpts { | ||||
|     bridgeSlippage: number; | ||||
| } | ||||
|  | ||||
| interface FinalUniswapV3FillData extends Omit<UniswapV3FillData, 'uniswapPaths'> { | ||||
|     // The uniswap-encoded path that can fll the maximum input amount. | ||||
|     uniswapPath: string; | ||||
| } | ||||
|  | ||||
| export function createOrdersFromTwoHopSample( | ||||
|     sample: DexSample<MultiHopFillData>, | ||||
|     opts: CreateOrderFromPathOpts, | ||||
| @@ -75,6 +83,8 @@ export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): s | ||||
|     switch (source) { | ||||
|         case ERC20BridgeSource.Balancer: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.Balancer, 'Balancer'); | ||||
|         case ERC20BridgeSource.BalancerV2: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.BalancerV2, 'BalancerV2'); | ||||
|         case ERC20BridgeSource.Bancor: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.Bancor, 'Bancor'); | ||||
|         // case ERC20BridgeSource.CoFiX: | ||||
| @@ -120,6 +130,8 @@ export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): s | ||||
|             return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'Linkswap'); | ||||
|         case ERC20BridgeSource.PancakeSwap: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'PancakeSwap'); | ||||
|         case ERC20BridgeSource.PancakeSwapV2: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'PancakeSwapV2'); | ||||
|         case ERC20BridgeSource.BakerySwap: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'BakerySwap'); | ||||
|         case ERC20BridgeSource.Nerve: | ||||
| @@ -134,8 +146,18 @@ export function getErc20BridgeSourceToBridgeSource(source: ERC20BridgeSource): s | ||||
|             return encodeBridgeSourceId(BridgeProtocol.Curve, 'Smoothy'); | ||||
|         case ERC20BridgeSource.Saddle: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.Nerve, 'Saddle'); | ||||
|         case ERC20BridgeSource.PancakeSwapV2: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'PancakeSwapV2'); | ||||
|         case ERC20BridgeSource.XSigma: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.Curve, 'xSigma'); | ||||
|         case ERC20BridgeSource.ApeSwap: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'ApeSwap'); | ||||
|         case ERC20BridgeSource.CafeSwap: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'CafeSwap'); | ||||
|         case ERC20BridgeSource.CheeseSwap: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'CheeseSwap'); | ||||
|         case ERC20BridgeSource.JulSwap: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.UniswapV2, 'JulSwap'); | ||||
|         case ERC20BridgeSource.UniswapV3: | ||||
|             return encodeBridgeSourceId(BridgeProtocol.UniswapV3, 'UniswapV3'); | ||||
|         default: | ||||
|             throw new Error(AggregationError.NoBridgeForSource); | ||||
|     } | ||||
| @@ -165,6 +187,7 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder | ||||
|         case ERC20BridgeSource.Ellipsis: | ||||
|         case ERC20BridgeSource.Smoothy: | ||||
|         case ERC20BridgeSource.Saddle: | ||||
|         case ERC20BridgeSource.XSigma: | ||||
|             const curveFillData = (order as OptimizedMarketBridgeOrder<CurveFillData>).fillData; | ||||
|             bridgeData = encoder.encode([ | ||||
|                 curveFillData.pool.poolAddress, | ||||
| @@ -178,6 +201,11 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder | ||||
|             const balancerFillData = (order as OptimizedMarketBridgeOrder<BalancerFillData>).fillData; | ||||
|             bridgeData = encoder.encode([balancerFillData.poolAddress]); | ||||
|             break; | ||||
|         case ERC20BridgeSource.BalancerV2: | ||||
|             const balancerV2FillData = (order as OptimizedMarketBridgeOrder<BalancerV2FillData>).fillData; | ||||
|             const { vault, poolId } = balancerV2FillData; | ||||
|             bridgeData = encoder.encode([vault, poolId]); | ||||
|             break; | ||||
|         case ERC20BridgeSource.Bancor: | ||||
|             const bancorFillData = (order as OptimizedMarketBridgeOrder<BancorFillData>).fillData; | ||||
|             bridgeData = encoder.encode([bancorFillData.networkAddress, bancorFillData.path]); | ||||
| @@ -187,9 +215,13 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder | ||||
|         case ERC20BridgeSource.CryptoCom: | ||||
|         case ERC20BridgeSource.Linkswap: | ||||
|         case ERC20BridgeSource.PancakeSwap: | ||||
|         case ERC20BridgeSource.PancakeSwapV2: | ||||
|         case ERC20BridgeSource.BakerySwap: | ||||
|         case ERC20BridgeSource.KyberDmm: | ||||
|         case ERC20BridgeSource.PancakeSwapV2: | ||||
|         case ERC20BridgeSource.ApeSwap: | ||||
|         case ERC20BridgeSource.CafeSwap: | ||||
|         case ERC20BridgeSource.CheeseSwap: | ||||
|         case ERC20BridgeSource.JulSwap: | ||||
|             const uniswapV2FillData = (order as OptimizedMarketBridgeOrder<UniswapV2FillData>).fillData; | ||||
|             bridgeData = encoder.encode([uniswapV2FillData.router, uniswapV2FillData.tokenAddressPath]); | ||||
|             break; | ||||
| @@ -238,6 +270,10 @@ export function createBridgeDataForBridgeOrder(order: OptimizedMarketBridgeOrder | ||||
|             const psmFillData = (order as OptimizedMarketBridgeOrder<MakerPsmFillData>).fillData; | ||||
|             bridgeData = encoder.encode([psmFillData.psmAddress, psmFillData.gemTokenAddress]); | ||||
|             break; | ||||
|         case ERC20BridgeSource.UniswapV3: | ||||
|             const uniswapV3FillData = (order as OptimizedMarketBridgeOrder<FinalUniswapV3FillData>).fillData; | ||||
|             bridgeData = encoder.encode([uniswapV3FillData.router, uniswapV3FillData.uniswapPath]); | ||||
|             break; | ||||
|         default: | ||||
|             throw new Error(AggregationError.NoBridgeForSource); | ||||
|     } | ||||
| @@ -256,7 +292,7 @@ export function createBridgeOrder( | ||||
|         takerToken, | ||||
|         makerAmount, | ||||
|         takerAmount, | ||||
|         fillData: fill.fillData, | ||||
|         fillData: createFinalBridgeOrderFillDataFromCollapsedFill(fill), | ||||
|         source: fill.source, | ||||
|         sourcePathId: fill.sourcePathId, | ||||
|         type: FillQuoteTransformerOrderType.Bridge, | ||||
| @@ -264,6 +300,36 @@ export function createBridgeOrder( | ||||
|     }; | ||||
| } | ||||
|  | ||||
| function createFinalBridgeOrderFillDataFromCollapsedFill(fill: CollapsedFill): FillData { | ||||
|     switch (fill.source) { | ||||
|         case ERC20BridgeSource.UniswapV3: { | ||||
|             const fd = fill.fillData as UniswapV3FillData; | ||||
|             return { | ||||
|                 router: fd.router, | ||||
|                 tokenAddressPath: fd.tokenAddressPath, | ||||
|                 uniswapPath: getBestUniswapV3PathForInputAmount(fd, fill.input), | ||||
|             }; | ||||
|         } | ||||
|         default: | ||||
|             break; | ||||
|     } | ||||
|     return fill.fillData; | ||||
| } | ||||
|  | ||||
| function getBestUniswapV3PathForInputAmount(fillData: UniswapV3FillData, inputAmount: BigNumber): string { | ||||
|     if (fillData.pathAmounts.length === 0) { | ||||
|         throw new Error(`No Uniswap V3 paths`); | ||||
|     } | ||||
|     // Find the best path that can satisfy `inputAmount`. | ||||
|     // Assumes `fillData.pathAmounts` is sorted ascending. | ||||
|     for (const { inputAmount: pathInputAmount, uniswapPath } of fillData.pathAmounts) { | ||||
|         if (pathInputAmount.gte(inputAmount)) { | ||||
|             return uniswapPath; | ||||
|         } | ||||
|     } | ||||
|     return fillData.pathAmounts[fillData.pathAmounts.length - 1].uniswapPath; | ||||
| } | ||||
|  | ||||
| export function getMakerTakerTokens(opts: CreateOrderFromPathOpts): [string, string] { | ||||
|     const makerToken = opts.side === MarketOperation.Sell ? opts.outputToken : opts.inputToken; | ||||
|     const takerToken = opts.side === MarketOperation.Sell ? opts.inputToken : opts.outputToken; | ||||
| @@ -281,6 +347,7 @@ const makerPsmEncoder = AbiEncoder.create([ | ||||
|     { name: 'psmAddress', type: 'address' }, | ||||
|     { name: 'gemTokenAddress', type: 'address' }, | ||||
| ]); | ||||
| const balancerV2Encoder = AbiEncoder.create([{ name: 'vault', type: 'address' }, { name: 'poolId', type: 'bytes32' }]); | ||||
| const routerAddressPathEncoder = AbiEncoder.create('(address,address[])'); | ||||
| const tokenAddressEncoder = AbiEncoder.create([{ name: 'tokenAddress', type: 'address' }]); | ||||
|  | ||||
| @@ -316,6 +383,7 @@ export const BRIDGE_ENCODERS: { | ||||
|     [ERC20BridgeSource.Ellipsis]: curveEncoder, | ||||
|     [ERC20BridgeSource.Smoothy]: curveEncoder, | ||||
|     [ERC20BridgeSource.Saddle]: curveEncoder, | ||||
|     [ERC20BridgeSource.XSigma]: curveEncoder, | ||||
|     // UniswapV2 like, (router, address[]) | ||||
|     [ERC20BridgeSource.Bancor]: routerAddressPathEncoder, | ||||
|     [ERC20BridgeSource.UniswapV2]: routerAddressPathEncoder, | ||||
| @@ -323,6 +391,14 @@ export const BRIDGE_ENCODERS: { | ||||
|     [ERC20BridgeSource.CryptoCom]: routerAddressPathEncoder, | ||||
|     [ERC20BridgeSource.Linkswap]: routerAddressPathEncoder, | ||||
|     [ERC20BridgeSource.KyberDmm]: routerAddressPathEncoder, | ||||
|     // BSC | ||||
|     [ERC20BridgeSource.PancakeSwap]: routerAddressPathEncoder, | ||||
|     [ERC20BridgeSource.PancakeSwapV2]: routerAddressPathEncoder, | ||||
|     [ERC20BridgeSource.BakerySwap]: routerAddressPathEncoder, | ||||
|     [ERC20BridgeSource.ApeSwap]: routerAddressPathEncoder, | ||||
|     [ERC20BridgeSource.CafeSwap]: routerAddressPathEncoder, | ||||
|     [ERC20BridgeSource.CheeseSwap]: routerAddressPathEncoder, | ||||
|     [ERC20BridgeSource.JulSwap]: routerAddressPathEncoder, | ||||
|     // Generic pools | ||||
|     [ERC20BridgeSource.Shell]: poolEncoder, | ||||
|     [ERC20BridgeSource.Component]: poolEncoder, | ||||
| @@ -334,10 +410,11 @@ export const BRIDGE_ENCODERS: { | ||||
|     [ERC20BridgeSource.Uniswap]: poolEncoder, | ||||
|     // Custom integrations | ||||
|     [ERC20BridgeSource.MakerPsm]: makerPsmEncoder, | ||||
|     // BSC | ||||
|     [ERC20BridgeSource.PancakeSwap]: routerAddressPathEncoder, | ||||
|     [ERC20BridgeSource.BakerySwap]: routerAddressPathEncoder, | ||||
|     [ERC20BridgeSource.PancakeSwapV2]: routerAddressPathEncoder, | ||||
|     [ERC20BridgeSource.BalancerV2]: balancerV2Encoder, | ||||
|     [ERC20BridgeSource.UniswapV3]: AbiEncoder.create([ | ||||
|         { name: 'router', type: 'address' }, | ||||
|         { name: 'path', type: 'bytes' }, | ||||
|     ]), | ||||
| }; | ||||
|  | ||||
| function getFillTokenAmounts(fill: CollapsedFill, side: MarketOperation): [BigNumber, BigNumber] { | ||||
|   | ||||
| @@ -0,0 +1,149 @@ | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| /** | ||||
|  * This has been copied from https://github.com/balancer-labs/balancer-sor/blob/john/rc2/src/helpers.ts. | ||||
|  * Still awaiting V2 support for @balancer-labs/sor, once full V2 support is shipped we can upgrade sor and delete this file | ||||
|  */ | ||||
| export const parsePoolData = ( | ||||
|     directPools: SubGraphPoolDictionary, | ||||
|     tokenIn: string, | ||||
|     tokenOut: string, | ||||
|     mostLiquidPoolsFirstHop: SubGraphPool[] = [], | ||||
|     mostLiquidPoolsSecondHop: SubGraphPool[] = [], | ||||
|     hopTokens: string[] = [], | ||||
| ): [SubGraphPoolDictionary, Path[]] => { | ||||
|     const pathDataList: Path[] = []; | ||||
|     const pools: SubGraphPoolDictionary = {}; | ||||
|  | ||||
|     // First add direct pair paths | ||||
|     // tslint:disable-next-line:forin | ||||
|     for (const idKey in directPools) { | ||||
|         const p: SubGraphPool = directPools[idKey]; | ||||
|         // Add pool to the set with all pools (only adds if it's still not present in dict) | ||||
|         pools[idKey] = p; | ||||
|  | ||||
|         const swap: Swap = { | ||||
|             pool: p.id, | ||||
|             tokenIn, | ||||
|             tokenOut, | ||||
|             tokenInDecimals: 18, // Placeholder for actual decimals | ||||
|             tokenOutDecimals: 18, | ||||
|         }; | ||||
|  | ||||
|         const path: Path = { | ||||
|             id: p.id, | ||||
|             swaps: [swap], | ||||
|         }; | ||||
|         pathDataList.push(path); | ||||
|     } | ||||
|  | ||||
|     // Now add multi-hop paths. | ||||
|     // mostLiquidPoolsFirstHop and mostLiquidPoolsSecondHop always has the same | ||||
|     // lengh of hopTokens | ||||
|     for (let i = 0; i < hopTokens.length; i++) { | ||||
|         // Add pools to the set with all pools (only adds if it's still not present in dict) | ||||
|         pools[mostLiquidPoolsFirstHop[i].id] = mostLiquidPoolsFirstHop[i]; | ||||
|         pools[mostLiquidPoolsSecondHop[i].id] = mostLiquidPoolsSecondHop[i]; | ||||
|  | ||||
|         const swap1: Swap = { | ||||
|             pool: mostLiquidPoolsFirstHop[i].id, | ||||
|             tokenIn, | ||||
|             tokenOut: hopTokens[i], | ||||
|             tokenInDecimals: 18, // Placeholder for actual decimals | ||||
|             tokenOutDecimals: 18, | ||||
|         }; | ||||
|  | ||||
|         const swap2: Swap = { | ||||
|             pool: mostLiquidPoolsSecondHop[i].id, | ||||
|             tokenIn: hopTokens[i], | ||||
|             tokenOut, | ||||
|             tokenInDecimals: 18, // Placeholder for actual decimals | ||||
|             tokenOutDecimals: 18, | ||||
|         }; | ||||
|  | ||||
|         const path: Path = { | ||||
|             id: mostLiquidPoolsFirstHop[i].id + mostLiquidPoolsSecondHop[i].id, // Path id is the concatenation of the ids of poolFirstHop and poolSecondHop | ||||
|             swaps: [swap1, swap2], | ||||
|         }; | ||||
|         pathDataList.push(path); | ||||
|     } | ||||
|     return [pools, pathDataList]; | ||||
| }; | ||||
|  | ||||
| interface SubGraphPool { | ||||
|     id: string; | ||||
|     swapFee: string; | ||||
|     totalWeight: string; | ||||
|     totalShares: string; | ||||
|     tokens: SubGraphToken[]; | ||||
|     tokensList: string[]; | ||||
|     poolType?: string; | ||||
|  | ||||
|     // Only for stable pools | ||||
|     amp: string; | ||||
|  | ||||
|     // Only for element pools | ||||
|     lpShares?: BigNumber; | ||||
|     time?: BigNumber; | ||||
|     principalToken?: string; | ||||
|     baseToken?: string; | ||||
| } | ||||
|  | ||||
| interface SubGraphPoolDictionary { | ||||
|     [poolId: string]: SubGraphPool; | ||||
| } | ||||
|  | ||||
| interface SubGraphToken { | ||||
|     address: string; | ||||
|     balance: string; | ||||
|     decimals: string | number; | ||||
|     // Stable & Element field | ||||
|     weight?: string; | ||||
| } | ||||
| interface Path { | ||||
|     id: string; // pool address if direct path, contactenation of pool addresses if multihop | ||||
|     swaps: Swap[]; | ||||
|     poolPairData?: PoolPairData[]; | ||||
|     limitAmount?: BigNumber; | ||||
|     filterEffectivePrice?: BigNumber; // TODO: This is just used for filtering, maybe there is a better way to filter? | ||||
| } | ||||
|  | ||||
| interface Swap { | ||||
|     pool: string; | ||||
|     tokenIn: string; | ||||
|     tokenOut: string; | ||||
|     swapAmount?: string; | ||||
|     limitReturnAmount?: string; | ||||
|     maxPrice?: string; | ||||
|     tokenInDecimals: number; | ||||
|     tokenOutDecimals: number; | ||||
| } | ||||
|  | ||||
| export interface PoolPairData { | ||||
|     id: string; | ||||
|     poolType?: string; // Todo: make this a mandatory field? | ||||
|     pairType?: string; // Todo: make this a mandatory field? | ||||
|     tokenIn: string; | ||||
|     tokenOut: string; | ||||
|     balanceIn?: BigNumber; | ||||
|     balanceOut?: BigNumber; | ||||
|     decimalsIn: number; | ||||
|     decimalsOut: number; | ||||
|     swapFee: BigNumber; | ||||
|  | ||||
|     // For weighted & element pools | ||||
|     weightIn?: BigNumber; | ||||
|     weightOut?: BigNumber; | ||||
|  | ||||
|     // Only for stable pools | ||||
|     allBalances: BigNumber[]; | ||||
|     invariant?: BigNumber; | ||||
|     amp?: BigNumber; | ||||
|     tokenIndexIn?: number; | ||||
|     tokenIndexOut?: number; | ||||
|  | ||||
|     // Only for element pools | ||||
|     lpShares?: BigNumber; | ||||
|     time?: BigNumber; | ||||
|     principalToken?: string; | ||||
|     baseToken?: string; | ||||
| } | ||||
| @@ -0,0 +1,107 @@ | ||||
| import { getPoolsWithTokens, parsePoolData } from '@balancer-labs/sor'; | ||||
| import { Pool } from '@balancer-labs/sor/dist/types'; | ||||
| import { gql, request } from 'graphql-request'; | ||||
|  | ||||
| import { BALANCER_MAX_POOLS_FETCHED, BALANCER_SUBGRAPH_URL, BALANCER_TOP_POOLS_FETCHED } from '../constants'; | ||||
|  | ||||
| import { CacheValue, PoolsCache } from './pools_cache'; | ||||
|  | ||||
| // tslint:disable:custom-no-magic-numbers | ||||
| const ONE_DAY_MS = 24 * 60 * 60 * 1000; | ||||
| // tslint:enable:custom-no-magic-numbers | ||||
|  | ||||
| interface BalancerPoolResponse { | ||||
|     id: string; | ||||
|     swapFee: string; | ||||
|     tokens: Array<{ address: string; decimals: number; balance: string }>; | ||||
|     tokensList: string[]; | ||||
|     totalWeight: string; | ||||
| } | ||||
|  | ||||
| export class BalancerPoolsCache extends PoolsCache { | ||||
|     constructor( | ||||
|         private readonly _subgraphUrl: string = BALANCER_SUBGRAPH_URL, | ||||
|         cache: { [key: string]: CacheValue } = {}, | ||||
|         private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED, | ||||
|         private readonly _topPoolsFetched: number = BALANCER_TOP_POOLS_FETCHED, | ||||
|     ) { | ||||
|         super(cache); | ||||
|         void this._loadTopPoolsAsync(); | ||||
|         // Reload the top pools every 12 hours | ||||
|         setInterval(async () => void this._loadTopPoolsAsync(), ONE_DAY_MS / 2); | ||||
|     } | ||||
|  | ||||
|     protected async _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> { | ||||
|         try { | ||||
|             const poolData = (await getPoolsWithTokens(takerToken, makerToken)).pools; | ||||
|             // Sort by maker token balance (descending) | ||||
|             const pools = parsePoolData(poolData, takerToken, makerToken).sort((a, b) => | ||||
|                 b.balanceOut.minus(a.balanceOut).toNumber(), | ||||
|             ); | ||||
|             return pools.length > this.maxPoolsFetched ? pools.slice(0, this.maxPoolsFetched) : pools; | ||||
|         } catch (err) { | ||||
|             return []; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     protected async _loadTopPoolsAsync(): Promise<void> { | ||||
|         const fromToPools: { | ||||
|             [from: string]: { [to: string]: Pool[] }; | ||||
|         } = {}; | ||||
|  | ||||
|         const pools = await this._fetchTopPoolsAsync(); | ||||
|         for (const pool of pools) { | ||||
|             const { tokensList } = pool; | ||||
|             for (const from of tokensList) { | ||||
|                 for (const to of tokensList.filter(t => t.toLowerCase() !== from.toLowerCase())) { | ||||
|                     fromToPools[from] = fromToPools[from] || {}; | ||||
|                     fromToPools[from][to] = fromToPools[from][to] || []; | ||||
|  | ||||
|                     try { | ||||
|                         // The list of pools must be relevant to `from` and `to`  for `parsePoolData` | ||||
|                         const poolData = parsePoolData([pool], from, to); | ||||
|                         fromToPools[from][to].push(poolData[0]); | ||||
|                         // Cache this as we progress through | ||||
|                         const expiresAt = Date.now() + this._cacheTimeMs; | ||||
|                         this._cachePoolsForPair(from, to, fromToPools[from][to], expiresAt); | ||||
|                     } catch { | ||||
|                         // soldier on | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     protected async _fetchTopPoolsAsync(): Promise<BalancerPoolResponse[]> { | ||||
|         const query = gql` | ||||
|             query fetchTopPools($topPoolsFetched: Int!) { | ||||
|                 pools( | ||||
|                     first: $topPoolsFetched | ||||
|                     where: { publicSwap: true, liquidity_gt: 0 } | ||||
|                     orderBy: swapsCount | ||||
|                     orderDirection: desc | ||||
|                 ) { | ||||
|                     id | ||||
|                     publicSwap | ||||
|                     swapFee | ||||
|                     totalWeight | ||||
|                     tokensList | ||||
|                     tokens { | ||||
|                         id | ||||
|                         address | ||||
|                         balance | ||||
|                         decimals | ||||
|                         symbol | ||||
|                         denormWeight | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         `; | ||||
|         try { | ||||
|             const { pools } = await request(this._subgraphUrl, query, { topPoolsFetched: this._topPoolsFetched }); | ||||
|             return pools; | ||||
|         } catch (err) { | ||||
|             return []; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,172 @@ | ||||
| import { BigNumber } from '@0x/utils'; | ||||
| // import { parsePoolData } from '@balancer-labs'; // TODO - upgrade to v2 | ||||
| import { Pool } from '@balancer-labs/sor/dist/types'; | ||||
| import { gql, request } from 'graphql-request'; | ||||
|  | ||||
| import { DEFAULT_WARNING_LOGGER } from '../../../constants'; | ||||
| import { LogFunction } from '../../../types'; | ||||
| import { BALANCER_MAX_POOLS_FETCHED, BALANCER_TOP_POOLS_FETCHED, BALANCER_V2_SUBGRAPH_URL } from '../constants'; | ||||
|  | ||||
| import { parsePoolData } from './balancer_sor_v2'; | ||||
| import { CacheValue, PoolsCache } from './pools_cache'; | ||||
|  | ||||
| // tslint:disable-next-line:custom-no-magic-numbers | ||||
| const ONE_DAY_MS = 24 * 60 * 60 * 1000; | ||||
|  | ||||
| interface BalancerPoolResponse { | ||||
|     id: string; | ||||
|     swapFee: string; | ||||
|     tokens: Array<{ address: string; decimals: number; balance: string; weight: string; symbol: string }>; | ||||
|     tokensList: string[]; | ||||
|     totalWeight: string; | ||||
|     totalShares: string; | ||||
|     amp: string | null; | ||||
| } | ||||
|  | ||||
| export class BalancerV2PoolsCache extends PoolsCache { | ||||
|     private static _parseSubgraphPoolData(pool: any, takerToken: string, makerToken: string): Pool { | ||||
|         const tToken = pool.tokens.find((t: any) => t.address === takerToken); | ||||
|         const mToken = pool.tokens.find((t: any) => t.address === makerToken); | ||||
|         const swap = pool.swaps && pool.swaps[0]; | ||||
|         const tokenAmountOut = swap ? swap.tokenAmountOut : undefined; | ||||
|         const tokenAmountIn = swap ? swap.tokenAmountIn : undefined; | ||||
|         const spotPrice = | ||||
|             tokenAmountOut && tokenAmountIn ? new BigNumber(tokenAmountOut).div(tokenAmountIn) : undefined; // TODO: xianny check | ||||
|  | ||||
|         return { | ||||
|             id: pool.id, | ||||
|             balanceIn: new BigNumber(tToken.balance), | ||||
|             balanceOut: new BigNumber(mToken.balance), | ||||
|             weightIn: new BigNumber(tToken.weight), | ||||
|             weightOut: new BigNumber(mToken.weight), | ||||
|             swapFee: new BigNumber(pool.swapFee), | ||||
|             spotPrice, | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     constructor( | ||||
|         private readonly subgraphUrl: string = BALANCER_V2_SUBGRAPH_URL, | ||||
|         private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED, | ||||
|         private readonly _topPoolsFetched: number = BALANCER_TOP_POOLS_FETCHED, | ||||
|         private readonly _warningLogger: LogFunction = DEFAULT_WARNING_LOGGER, | ||||
|         cache: { [key: string]: CacheValue } = {}, | ||||
|     ) { | ||||
|         super(cache); | ||||
|         void this._loadTopPoolsAsync(); | ||||
|         // Reload the top pools every 12 hours | ||||
|         setInterval(async () => void this._loadTopPoolsAsync(), ONE_DAY_MS / 2); | ||||
|     } | ||||
|  | ||||
|     // protected async _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> { | ||||
|     //     try { | ||||
|     //         const poolData = (await getPoolsWithTokens(takerToken, makerToken)).pools; | ||||
|     //         // Sort by maker token balance (descending) | ||||
|     //         const pools = parsePoolData(poolData, takerToken, makerToken).sort((a, b) => | ||||
|     //             b.balanceOut.minus(a.balanceOut).toNumber(), | ||||
|     //         ); | ||||
|     //         return pools.length > this.maxPoolsFetched ? pools.slice(0, this.maxPoolsFetched) : pools; | ||||
|     //     } catch (err) { | ||||
|     //         return []; | ||||
|     //     } | ||||
|     // } | ||||
|  | ||||
|     protected async _fetchTopPoolsAsync(): Promise<BalancerPoolResponse[]> { | ||||
|         const query = gql` | ||||
|             query fetchTopPools($topPoolsFetched: Int!) { | ||||
|                 pools( | ||||
|                     first: $topPoolsFetched | ||||
|                     where: { totalLiquidity_gt: 0 } | ||||
|                     orderBy: swapsCount | ||||
|                     orderDirection: desc | ||||
|                 ) { | ||||
|                     id | ||||
|                     swapFee | ||||
|                     totalWeight | ||||
|                     tokensList | ||||
|                     amp | ||||
|                     totalShares | ||||
|                     tokens { | ||||
|                         id | ||||
|                         address | ||||
|                         balance | ||||
|                         decimals | ||||
|                         symbol | ||||
|                         weight | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         `; | ||||
|  | ||||
|         const { pools } = await request<{ pools: BalancerPoolResponse[] }>(this.subgraphUrl, query, { | ||||
|             topPoolsFetched: this._topPoolsFetched, | ||||
|         }); | ||||
|  | ||||
|         return pools; | ||||
|     } | ||||
|     protected async _loadTopPoolsAsync(): Promise<void> { | ||||
|         const fromToPools: { | ||||
|             [from: string]: { [to: string]: Pool[] }; | ||||
|         } = {}; | ||||
|  | ||||
|         const pools = await this._fetchTopPoolsAsync(); | ||||
|         for (const pool of pools) { | ||||
|             const { tokensList } = pool; | ||||
|             for (const from of tokensList) { | ||||
|                 for (const to of tokensList.filter(t => t.toLowerCase() !== from.toLowerCase())) { | ||||
|                     fromToPools[from] = fromToPools[from] || {}; | ||||
|                     fromToPools[from][to] = fromToPools[from][to] || []; | ||||
|  | ||||
|                     try { | ||||
|                         // The list of pools must be relevant to `from` and `to`  for `parsePoolData` | ||||
|                         const [poolData] = parsePoolData({ [pool.id]: pool as any }, from, to); | ||||
|                         fromToPools[from][to].push( | ||||
|                             BalancerV2PoolsCache._parseSubgraphPoolData(poolData[pool.id], from, to), | ||||
|                         ); | ||||
|                         // Cache this as we progress through | ||||
|                         const expiresAt = Date.now() + this._cacheTimeMs; | ||||
|                         this._cachePoolsForPair(from, to, fromToPools[from][to], expiresAt); | ||||
|                     } catch (err) { | ||||
|                         this._warningLogger(err, `Failed to load Balancer V2 top pools`); | ||||
|                         // soldier on | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     protected async _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> { | ||||
|         const query = gql` | ||||
|         query getPools { | ||||
|             pools( | ||||
|               first: ${this.maxPoolsFetched}, | ||||
|               where: { | ||||
|                 tokensList_contains: ["${takerToken}", "${makerToken}"] | ||||
|               } | ||||
|             ) { | ||||
|                 id | ||||
|                 tokens { | ||||
|                     address | ||||
|                     balance | ||||
|                     weight | ||||
|                 } | ||||
|               swapFee | ||||
|               swaps( | ||||
|                 orderBy: timestamp, orderDirection: desc, first: 1, | ||||
|                   where:{ | ||||
|                   tokenIn: "${takerToken}", | ||||
|                   tokenOut: "${makerToken}" | ||||
|                 } | ||||
|               ) { | ||||
|                 tokenAmountIn | ||||
|                 tokenAmountOut | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|           `; | ||||
|         try { | ||||
|             const { pools } = await request(this.subgraphUrl, query); | ||||
|             return pools.map((pool: any) => BalancerV2PoolsCache._parseSubgraphPoolData(pool, takerToken, makerToken)); | ||||
|         } catch (e) { | ||||
|             return []; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,28 @@ | ||||
| import { Pool } from '@balancer-labs/sor/dist/types'; | ||||
| import { getPoolsWithTokens, parsePoolData } from 'cream-sor'; | ||||
|  | ||||
| import { BALANCER_MAX_POOLS_FETCHED } from '../constants'; | ||||
|  | ||||
| import { CacheValue, PoolsCache } from './pools_cache'; | ||||
|  | ||||
| export class CreamPoolsCache extends PoolsCache { | ||||
|     constructor( | ||||
|         _cache: { [key: string]: CacheValue } = {}, | ||||
|         private readonly maxPoolsFetched: number = BALANCER_MAX_POOLS_FETCHED, | ||||
|     ) { | ||||
|         super(_cache); | ||||
|     } | ||||
|  | ||||
|     protected async _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> { | ||||
|         try { | ||||
|             const poolData = (await getPoolsWithTokens(takerToken, makerToken)).pools; | ||||
|             // Sort by maker token balance (descending) | ||||
|             const pools = parsePoolData(poolData, takerToken, makerToken).sort((a, b) => | ||||
|                 b.balanceOut.minus(a.balanceOut).toNumber(), | ||||
|             ); | ||||
|             return pools.slice(0, this.maxPoolsFetched); | ||||
|         } catch (err) { | ||||
|             return []; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,4 @@ | ||||
| export { BalancerPoolsCache } from './balancer_utils'; | ||||
| export { BalancerV2PoolsCache } from './balancer_v2_utils'; | ||||
| export { CreamPoolsCache } from './cream_utils'; | ||||
| export { PoolsCache } from './pools_cache'; | ||||
| @@ -0,0 +1,78 @@ | ||||
| import { Pool } from '@balancer-labs/sor/dist/types'; | ||||
|  | ||||
| import { ONE_HOUR_IN_SECONDS, ONE_SECOND_MS } from '../constants'; | ||||
| export { Pool }; | ||||
| export interface CacheValue { | ||||
|     expiresAt: number; | ||||
|     pools: Pool[]; | ||||
| } | ||||
|  | ||||
| // tslint:disable:custom-no-magic-numbers | ||||
| // Cache results for 30mins | ||||
| const DEFAULT_CACHE_TIME_MS = (ONE_HOUR_IN_SECONDS / 2) * ONE_SECOND_MS; | ||||
| const DEFAULT_TIMEOUT_MS = 1000; | ||||
| // tslint:enable:custom-no-magic-numbers | ||||
|  | ||||
| export abstract class PoolsCache { | ||||
|     protected static _isExpired(value: CacheValue): boolean { | ||||
|         return Date.now() >= value.expiresAt; | ||||
|     } | ||||
|     constructor( | ||||
|         protected readonly _cache: { [key: string]: CacheValue }, | ||||
|         protected readonly _cacheTimeMs: number = DEFAULT_CACHE_TIME_MS, | ||||
|     ) {} | ||||
|  | ||||
|     public async getFreshPoolsForPairAsync( | ||||
|         takerToken: string, | ||||
|         makerToken: string, | ||||
|         timeoutMs: number = DEFAULT_TIMEOUT_MS, | ||||
|     ): Promise<Pool[]> { | ||||
|         const timeout = new Promise<Pool[]>(resolve => setTimeout(resolve, timeoutMs, [])); | ||||
|         return Promise.race([this._getAndSaveFreshPoolsForPairAsync(takerToken, makerToken), timeout]); | ||||
|     } | ||||
|  | ||||
|     public getCachedPoolAddressesForPair( | ||||
|         takerToken: string, | ||||
|         makerToken: string, | ||||
|         ignoreExpired: boolean = true, | ||||
|     ): string[] | undefined { | ||||
|         const key = JSON.stringify([takerToken, makerToken]); | ||||
|         const value = this._cache[key]; | ||||
|         if (ignoreExpired) { | ||||
|             return value === undefined ? [] : value.pools.map(pool => pool.id); | ||||
|         } | ||||
|         if (!value) { | ||||
|             return undefined; | ||||
|         } | ||||
|         if (PoolsCache._isExpired(value)) { | ||||
|             return undefined; | ||||
|         } | ||||
|         return (value || []).pools.map(pool => pool.id); | ||||
|     } | ||||
|  | ||||
|     public isFresh(takerToken: string, makerToken: string): boolean { | ||||
|         const cached = this.getCachedPoolAddressesForPair(takerToken, makerToken, false); | ||||
|         return cached !== undefined; | ||||
|     } | ||||
|  | ||||
|     protected async _getAndSaveFreshPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]> { | ||||
|         const key = JSON.stringify([takerToken, makerToken]); | ||||
|         const value = this._cache[key]; | ||||
|         if (value === undefined || value.expiresAt >= Date.now()) { | ||||
|             const pools = await this._fetchPoolsForPairAsync(takerToken, makerToken); | ||||
|             const expiresAt = Date.now() + this._cacheTimeMs; | ||||
|             this._cachePoolsForPair(takerToken, makerToken, pools, expiresAt); | ||||
|         } | ||||
|         return this._cache[key].pools; | ||||
|     } | ||||
|  | ||||
|     protected _cachePoolsForPair(takerToken: string, makerToken: string, pools: Pool[], expiresAt: number): void { | ||||
|         const key = JSON.stringify([takerToken, makerToken]); | ||||
|         this._cache[key] = { | ||||
|             pools, | ||||
|             expiresAt, | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     protected abstract _fetchPoolsForPairAsync(takerToken: string, makerToken: string): Promise<Pool[]>; | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user