Compare commits

...

38 Commits

Author SHA1 Message Date
Github Actions
70d2117470 Publish
- @0x/contracts-integrations@2.7.43
 - @0x/asset-swapper@6.13.0
2021-05-11 03:18:25 +00:00
Github Actions
2c173ccaf3 Updated CHANGELOGS & MD docs 2021-05-11 03:18:20 +00:00
mzhu25
d2f4a0c5f3 Updated config.yml 2021-05-10 19:51:12 -07:00
mzhu25
0d6021e5e3 Add LiquidityProvider to BSC sources (#234) 2021-05-10 18:27:52 -07:00
Github Actions
bb04726e7f Publish
- @0x/contracts-integrations@2.7.42
 - @0x/asset-swapper@6.12.0
2021-05-10 01:36:49 +00:00
Github Actions
220ca370c2 Updated CHANGELOGS & MD docs 2021-05-10 01:36:44 +00:00
Jacob Evans
63af4e3e98 fix: TwoHopSampler call (#233) 2021-05-10 11:05:30 +10:00
Github Actions
9754e12d82 Publish
- @0x/contracts-integrations@2.7.41
 - @0x/asset-swapper@6.11.0
2021-05-07 04:35:35 +00:00
Github Actions
d72ebed246 Updated CHANGELOGS & MD docs 2021-05-07 04:35:31 +00:00
Jacob Evans
587fc71058 fix: Sampler contract address overrides (#232)
* fix: Sampler contract address overrides

* Update CHANGELOG
2021-05-07 13:52:51 +10:00
Kim Persson
7d34e09a12 fix: add separate priceComparisonsReport to fix missing quoteReport data [TKR-91] (#219)
* fix: add separate priceComparisonsReport to fix missing quoteReport data

* chore: remove notice about unconfirmed Uniswap V3 addresses

* refactor: move price comparisons computation logic into separate method

* chore: add AS changelog entry
2021-05-06 14:54:54 +02:00
Kim Persson
7d15baad0f feat: Balancer V2 load and cache top pools by num swaps on startup [TKR-96] (#228)
* feat: Balancer V2 load and cache top pools by num swaps on startup

* refactor: Clean up code for Balancer V1 & V2 cache heating

* chore: add AS changelog entry
2021-05-06 14:21:30 +02:00
mzhu25
1e6476ada7 Add ETH pseudo-address when wrapping/unwrapping in Multiplex multihop (#230)
* Add ETH pseudo-address when wrapping/unwrapping in Multiplex multihop

* Update changelog
2021-05-06 15:29:24 +10:00
Lawrence Forman
1d6ca5f6b5 @0x/asset-swapper: Tweak compiler settings for smaller sampler size (#229)
Co-authored-by: Lawrence Forman <me@merklejerk.com>
2021-05-05 18:36:38 -04:00
Github Actions
fb249f02fc Publish
- @0x/contracts-asset-proxy@3.7.11
 - @0x/contracts-broker@1.1.29
 - @0x/contracts-coordinator@3.1.30
 - @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-forwarder@4.2.30
 - @0x/contracts-exchange-libs@4.3.29
 - @0x/contracts-exchange@3.2.30
 - @0x/contracts-extensions@6.2.24
 - @0x/contracts-integrations@2.7.40
 - @0x/contracts-multisig@4.1.30
 - @0x/contracts-staking@2.0.37
 - @0x/contracts-test-utils@5.4.0
 - @0x/contracts-treasury@1.1.6
 - @0x/contracts-utils@4.7.8
 - @0x/contracts-zero-ex@0.23.0
 - @0x/asset-swapper@6.10.0
 - @0x/contract-addresses@6.1.0
 - @0x/contract-artifacts@3.14.2
 - @0x/contract-wrappers-test@12.2.45
 - @0x/contract-wrappers@13.16.1
 - @0x/migrations@8.0.6
 - @0x/order-utils@10.4.21
 - @0x/protocol-utils@1.6.0
2021-05-05 11:32:51 +00:00
Github Actions
fdf04ef275 Updated CHANGELOGS & MD docs 2021-05-05 11:32:46 +00:00
Jacob Evans
b0f5f634f2 bump test-publish resource_class 2021-05-05 21:02:31 +10:00
Jacob Evans
6ee0108565 fix: async pool cache (#226) 2021-05-05 21:01:51 +10:00
Jacob Evans
c73097e688 chore: Deploy FQT with UniswapV3 support (#227) 2021-05-05 21:01:39 +10:00
Lawrence Forman
a2d42b07b5 UniswapV3 [TKR-4] (#197)
* add balancer v2

* fetch balancer v2 pools from subgraph

* feat: initial stab at a Balancer V2 Sampler WIP

* feat: add sampling for buys and fix build issues WIP [untested]

* fix: BalancerV2Sampler implementation issues, works on Kovan

* chore: BalancerV2 sampling boilerplate

* fix: update Balancer V2 mainnet address

* fix: consolidate differences between the 2 working branches

* fix: use mainnet Balancer V2 subgraph

* fix: stack too deep by minimizing and inline Balancer V2 vault interface

* fix: address review comments and clean up

* fix: sampler vault interface and pools cache assuming a pool has swaps

* address more review comments

* fix: TS type issues and add a comment about deadline argument

* fix: pools_cache_tests incorrect token addresses, prettier incompat

* fix: make ERC20BridgeSampler support BalancerV2 non view sampler fns

* fix: use a struct for passing encoded bridge data for Balancer V2

* chore: add changelog entries

* fix: improve gas accuracy of gas schedule for Balancer V2 & Maker Psm

* fix: don't exclude sources with stale caches & wait for cache refresh

* rebase

* `@0x/asset-swapper`: Fix stack too deep errors in sampler

* `@0x/asset-swapper`: Add uniswap V3 sampler.

* `@0x/contracts-zero-ex`: Add UniswapV3 support to FQT

* `@0x/protocol-utils`: Update BridgeProtocols.
`@0x/asset-swapper`: Add sell integration for UniswapV3.

* `@0x/asset-swapper`: Remove unnecessary swap quote consumer constructor arg.
`@0x/asset-swapper`: Enable UniswapV3 on ropsten.

* `@0x/asset-swapper`: UniswapV3 fixes

* `@0x/asset-swapper`: Fix stuff based on latest deployed testnet contracts

* `@0x/asset-swapper`: Remove UniV3 from mainnet sources for now

* `@0x/asset-swapper`: Tweak univ3 gas schedule

* fix CI?

* `@0x/contracts-test-utils`: Set default ganache gas limit to 100e6

Co-authored-by: xianny <xianny@gmail.com>
Co-authored-by: Kim Persson <kimpersson88@gmail.com>
Co-authored-by: Lawrence Forman <me@merklejerk.com>
Co-authored-by: Jacob Evans <jacob@dekz.net>
2021-05-05 19:44:17 +10:00
Xianny
f9a794af93 feat: Balancer V2 integration (#206)
* add balancer v2

* fetch balancer v2 pools from subgraph

* feat: initial stab at a Balancer V2 Sampler WIP

* feat: add sampling for buys and fix build issues WIP [untested]

* fix: BalancerV2Sampler implementation issues, works on Kovan

* chore: BalancerV2 sampling boilerplate

* fix: update Balancer V2 mainnet address

* fix: consolidate differences between the 2 working branches

* fix: use mainnet Balancer V2 subgraph

* fix: stack too deep by minimizing and inline Balancer V2 vault interface

* fix: address review comments and clean up

* fix: sampler vault interface and pools cache assuming a pool has swaps

* address more review comments

* fix: TS type issues and add a comment about deadline argument

* fix: pools_cache_tests incorrect token addresses, prettier incompat

* fix: make ERC20BridgeSampler support BalancerV2 non view sampler fns

* fix: use a struct for passing encoded bridge data for Balancer V2

* chore: add changelog entries

* fix: improve gas accuracy of gas schedule for Balancer V2 & Maker Psm

* fix: don't exclude sources with stale caches & wait for cache refresh

* rebase

* `@0x/asset-swapper`: Fix stack too deep errors in sampler

Co-authored-by: Kim Persson <kimpersson88@gmail.com>
Co-authored-by: Lawrence Forman <me@merklejerk.com>
2021-05-05 11:01:28 +02:00
Jacob Evans
a2643674ca Fix: PLP now generates a fallback (#223)
* fix: PLP requires a fallback

* update changelog

* Fix missed source exclusion
2021-05-05 08:22:19 +10:00
Jacob Evans
c00ce9daac feat: Support ETH based Curve pools (#220)
* feat: Support ETH based Curve pools

* Disable Curve VIP for WETH trades

* feat: Support for sETH and ankrETH (Curve)

* Disable SnowSwap ETH pools

* feat: add BUSD Curve 3pool

* fix changelog

Co-authored-by: Romain Butteaud <romain.butteaud@gmail.com>
2021-05-05 07:33:41 +10:00
mzhu25
c68b5d7844 Fix/staking epoch finalization (#221)
* Patch staking and recover state in constructor

* Add ganache mainnet fork test

* Add ganache mainnet fork test

* update changelog

* hardcode last pool ID

* Separate patch contract to unbreak tests
2021-05-04 11:29:16 -07:00
Jacob Evans
09ed106d4c feat: Deployed Balancer V2 and Curve ETH support (#225) 2021-05-04 16:52:36 +10:00
Jacob Evans
a6b92fc658 fix: Fix test forever with new sources being added 2021-05-04 16:49:16 +10:00
mzhu25
4be4a1a30b Fix exchangeProxyGasOverhead used to compute fallback orders (#215)
* Fix exchangeProxyGasOverhead used to compute fallback orders

* update changelog
2021-05-04 13:41:21 +10:00
Romain Butteaud
9bede5d331 fix: reactive PancakeSwap, BakerySwap VIP on BSC (#222) 2021-05-04 13:40:57 +10:00
Romain Butteaud
b50d4aee6d Chore: adding xSigma liquidity source [TKR-59] (#201)
* Chore: adding xSigma liquidity source

* fix: prettier
2021-05-03 19:50:26 -07:00
Jacob Evans
55bc367bd6 feat: Add LUSD Curve pool (#218) 2021-05-04 08:08:27 +10:00
Github Actions
7a59b7eafe Publish
- @0x/contracts-integrations@2.7.39
 - @0x/contracts-zero-ex@0.22.3
 - @0x/asset-swapper@6.9.1
 - @0x/contract-wrappers-test@12.2.44
 - @0x/migrations@8.0.5
2021-05-01 01:03:24 +00:00
Github Actions
9e59d41e44 Updated CHANGELOGS & MD docs 2021-05-01 01:03:19 +00:00
Jacob Evans
475e6c7bca fix: Temporarily remove PancakeV2/Bakery from VIP (#217) 2021-05-01 10:35:54 +10:00
Github Actions
dbc5a5293e Publish
- @0x/contracts-integrations@2.7.38
 - @0x/contracts-treasury@1.1.5
 - @0x/contracts-zero-ex@0.22.2
 - @0x/asset-swapper@6.9.0
 - @0x/contract-wrappers-test@12.2.43
 - @0x/migrations@8.0.4
2021-04-30 23:39:46 +00:00
Github Actions
f4bd2bd0d8 Updated CHANGELOGS & MD docs 2021-04-30 23:39:42 +00:00
Romain Butteaud
f1782a83ba chore: BSC PancakeSwap forks VIP, PancakeSwapV2, Saddle BTC pool, Curve gas schedule [TKR-41] [TKR-11] [TKR-79] [TKR-86] (#208)
* chore: popular BSC Uniswap clones, Curve gas schedule update, Saddle BTC pool

* chore: adding PancakeSwapV2 VIP

* fix: yarn prettier
2021-05-01 08:48:10 +10:00
Jacob Evans
cbade0d558 fix: Ban colliding Kyber reserve (#216) 2021-04-29 15:24:39 +10:00
mzhu25
fe0c26387c Fix treasury voting power calculation (#214)
* Fix treasury voting power calculation

* Update changelog
2021-04-28 10:22:52 -07:00
135 changed files with 3615 additions and 1556 deletions

View File

@@ -1,25 +1,25 @@
version: 2
version: 2.1
jobs:
build:
resource_class: medium+
resource_class: xlarge
docker:
- image: nikolaik/python-nodejs:python3.7-nodejs10
- image: node:12
environment:
CONTRACTS_COMMIT_HASH: '9ed05f5'
NODE_OPTIONS: '--max-old-space-size=16384'
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:

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1620214333,
"version": "3.7.11",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1619596077,
"version": "3.7.10",

View File

@@ -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

View File

@@ -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"
},

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1620214333,
"version": "1.1.29",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1619596077,
"version": "1.1.28",

View File

@@ -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

View File

@@ -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": {

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1620214333,
"version": "3.1.30",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1619596077,
"version": "3.1.29",

View File

@@ -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

View File

@@ -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"
},

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1620214333,
"version": "1.3.28",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1619596077,
"version": "1.3.27",

View File

@@ -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

View File

@@ -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": {

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1620214333,
"version": "2.1.29",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1619596077,
"version": "2.1.28",

View File

@@ -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

View File

@@ -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": {

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1620214333,
"version": "3.3.8",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1619596077,
"version": "3.3.7",

View File

@@ -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

View File

@@ -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"

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1620214333,
"version": "3.1.29",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1619596077,
"version": "3.1.28",

View File

@@ -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

View File

@@ -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"

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1620214333,
"version": "4.2.30",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1619596077,
"version": "4.2.29",

View File

@@ -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

View File

@@ -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"
},

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1620214333,
"version": "4.3.29",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1619596077,
"version": "4.3.28",

View File

@@ -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

View File

@@ -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": {

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1620214333,
"version": "3.2.30",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1619596077,
"version": "3.2.29",

View File

@@ -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

View File

@@ -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": {

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1620214333,
"version": "6.2.24",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1619596077,
"version": "6.2.23",

View File

@@ -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

View File

@@ -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"
},

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/contracts-integrations",
"version": "2.7.37",
"version": "2.7.43",
"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.13.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"

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1620214333,
"version": "4.1.30",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1619596077,
"version": "4.1.29",

View File

@@ -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

View File

@@ -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"
},

View File

@@ -1,4 +1,14 @@
[
{
"version": "2.0.37",
"changes": [
{
"note": "Patch epoch finalization issue",
"pr": 221
}
],
"timestamp": 1620214333
},
{
"timestamp": 1619596077,
"version": "2.0.36",

View File

@@ -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

View 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;
}
}

View File

@@ -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) {

View File

@@ -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"
},

View File

@@ -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,

View 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

View File

@@ -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';

View File

@@ -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",

View File

@@ -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",

View File

@@ -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

View File

@@ -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",

View File

@@ -20,6 +20,7 @@ export let providerConfigs: Web3Config = {
shouldUseInProcessGanache: true,
shouldAllowUnlimitedContractSize: true,
hardfork: 'istanbul',
gasLimit: 100e6,
unlocked_accounts: [
'0x6cc5f688a315f3dc28a7781717a9a798a59fda7b',
'0x55dc8f21d20d4c6ed3c82916a438a413ca68e335',

View File

@@ -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",

View File

@@ -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

View File

@@ -30,6 +30,7 @@ interface IZrxTreasury {
uint256 votingPeriod;
uint256 proposalThreshold;
uint256 quorumThreshold;
bytes32 defaultPoolId;
}
struct ProposedAction {

View File

@@ -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,

View File

@@ -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"
},

View File

@@ -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))

View File

@@ -1,4 +1,13 @@
[
{
"timestamp": 1620214333,
"version": "4.7.8",
"changes": [
{
"note": "Dependencies updated"
}
]
},
{
"timestamp": 1619596077,
"version": "4.7.7",

View File

@@ -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

View File

@@ -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"
},

View File

@@ -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
}
]
},

View File

@@ -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_

View File

@@ -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))
}

View File

@@ -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.

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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
}));
}
}

View File

@@ -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"
},

View File

@@ -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,

View File

@@ -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';

View File

@@ -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",

View File

@@ -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"

View File

@@ -1,4 +1,111 @@
[
{
"version": "6.13.0",
"changes": [
{
"note": "Add LiquidityProvider to BSC sources",
"pr": 234
}
],
"timestamp": 1620703098
},
{
"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 +145,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

View File

@@ -5,6 +5,42 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
## v6.13.0 - _May 11, 2021_
* Add LiquidityProvider to BSC sources (#234)
## 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 +57,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_

View File

@@ -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": {
"*": {
"*": [

View 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
});
}
}

View File

@@ -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());
}
}

View File

@@ -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]);
}
}
}

View File

@@ -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 (

View 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)
}
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@0x/asset-swapper",
"version": "6.8.0",
"version": "6.13.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",

View File

@@ -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';

View File

@@ -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,
},

View File

@@ -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);
}
/**

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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 [];
}
}
}

View File

@@ -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}`);
}

View File

@@ -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,14 @@ 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,
ERC20BridgeSource.LiquidityProvider,
]),
},
@@ -129,6 +140,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 +160,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 +169,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 +184,14 @@ 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,
ERC20BridgeSource.LiquidityProvider,
]),
},
new SourceFilters([]),
@@ -285,6 +305,7 @@ export const MAINNET_TOKENS = {
STABLEx: '0xcd91538b91b4ba7797d39a2f66e63810b50a33d0',
alUSD: '0xbc6da0fe9ad5f3b0d58160288917aa56653660e9',
FRAX: '0x853d955acef822db058eb8505911ed77f175b99e',
LUSD: '0x5f98805a4e8be255a32880fdec7f6728c6568ba0',
};
export const BSC_TOKENS = {
@@ -321,11 +342,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 +355,8 @@ export const CURVE_POOLS = {
STABLEx: '0x3252efd4ea2d6c78091a1f43982ee2c3659cc3d1',
alUSD: '0x43b4fdfd4ff969587185cdb6f0bd875c5fc83f8c',
FRAX: '0xd632f22692fac7611d2aa1c0d552930d43caed3b',
LUSD: '0xed279fdd11ca84beef15af5d39bb4d4bee23f0ca',
BUSD: '0x4807862aa8b2bf68830e4c8dc86d0e9a998e085a',
};
export const SWERVE_POOLS = {
@@ -343,7 +366,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 +395,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 +455,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 +513,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 +689,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 +697,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 +729,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 +750,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 +780,7 @@ export const SMOOTHY_MAINNET_INFOS: { [name: string]: CurveInfo } = {
MAINNET_TOKENS.GUSD,
],
metaToken: undefined,
gasSchedule: 200e3,
gasSchedule: 190e3,
},
};
@@ -721,7 +792,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 +804,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 +815,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 +1050,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 +1086,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 +1100,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 +1159,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 +1198,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 +1254,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 +1272,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 +1281,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 +1339,6 @@ export const DEFAULT_GET_MARKET_ORDERS_OPTS: GetMarketOrdersOpts = {
exchangeProxyOverhead: () => ZERO_AMOUNT,
allowFallback: true,
shouldGenerateQuoteReport: true,
shouldIncludePriceComparisonsReport: false,
tokenAdjacencyGraph: { default: [] },
};

View File

@@ -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 [];
}
}
}

View File

@@ -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);
}),
);
}
}

View File

@@ -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] {

View File

@@ -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;
}

View File

@@ -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 [];
}
}
}

View File

@@ -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 [];
}
}
}

View File

@@ -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 [];
}
}
}

View File

@@ -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';

View File

@@ -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